使用过inception的人对sql审核这块获取都比较熟悉,作为DBA,审核SQL是日常工作中的很重要的一块内容,审核好SQL对于后期项目以及数据库维护上起着至关重要的作用。
而goInception是一个集审核、执行、备份及生成回滚语句于一身的MySQL运维工具, 通过对执行SQL的语法解析,返回基于自定义规则的审核结果,并提供执行和备份及生成回滚语句的功能
官网:https://github.com/hanchuanchuan/goInception
相关的详细文档:https://hanchuanchuan.github.io/goInception/
一、简介
goInception基于TiDB的语法解析器,和业内有名的inpcetion审核工具重构。
同时提供Archery 查询支持(MySQL/MsSQL/Redis/PostgreSQL)、MySQL优化(SQLAdvisor|SOAR|SQLTuning)、慢日志管理、表结构对比、会话管理、阿里云RDS管理等。
从架构上来说,goinception简直跟inception一模一样,SQL提交到goinception,goinception连接到线上MySQL进行审核。执行的时候也是连接到线上MySQL进行执行,goinception提供了备份、回滚的功能,意思就是能够监听执行期间的binlog,基于binlog生成反向的回滚SQL。
goInception延用inception的使用方式,在审核的sql开始前添加注释来指定远端服务器,并在sql的前后添加特殊标识以区分待审核语句,示例如下:
/*--user=root;--password=root;--host=127.0.0.1;--check=1;--port=3306;*/
inception_magic_start;
use test;
create table t1(id int primary key);
inception_magic_commit;
>>>对比原生inception的优势
1) 对开源工具gh-ost的支持,可以不再使用触发器
2) 支持DML和DDL混合提交
3) 批量备份速度远远超过原生inception
4) 因为是go程序,所以不依赖于环境,执行执行即可,原生inception有一些包的问题
5) 支持某些原生incetpion不支持的语法,比如insert select这种带select关键字
二、安装部署
1、下载安装
1.1、二进制安装
下载地址:https://github.com/hanchuanchuan/goInception/releases下载好对应版本的goinception,直接解压即可,解压完成以后在config/config.toml.default有一个默认的配置文件
mkdir -p /usr/local/goinception
wget https://github.com/hanchuanchuan/goInception/releases/download/v1.2.3/goInception-linux-amd64-v1.2.3.tar.gz
tar -xvf goInception-linux-amd64-v1.2.3.tar.gz -C /usr/local/goinception
chown -R root:root /usr/local/goinception && chmod -R 755 /usr/local/goinception
1.2、源码编译
git clone https://gitee.com/hanchuanchuan/goInception.git
cd goInception
make parser
go build -o goInception tidb-server/main.go
1.3、docker部署
docker pull hanchuanchuan/goinception
2、修改配置文件(config.toml)
#· cat /usr/local/goinception/config/config.toml
================================================================================
# IP地址
host = "0.0.0.0"
# 端口
port = 8888
# TiDB数据库目录
path = "/tmp/tidb"
# 忽略终端连接断开信号
ignore_sighup = true
[log]
# 日志级别: debug, info, warn, error, fatal.
level = "info"
# 日志格式, one of json, text, console.
format = "text"
# 禁用时间戳输出
disable-timestamp = false
# 日志文件
[log.file]
# 日志文件名
filename = "/usr/local/goinception/goinception.log"
# 日志文件的最大上限(MB)
max-size = 1000
# Max日志文件的保存天数,默认值 `0`,即不清理
max-days = 7
# 要保留的最大旧日志文件数,默认值 `0`,即不清理
max-backups = 3
# 日志轮询,默认值 `true`,即开启
log-rotate = true
[inc]
backup_host = "127.0.0.1"
backup_port = 3306
backup_user = "root"
backup_password = "password"
enable_nullable = true
enable_drop_table = false
enable_set_engine = true
enable_change_column = true
check_timestamp_count = true
check_table_comment = false
check_column_comment = false
# 审核列类型变更
check_column_type_change = true
# 表名/索引名前缀
index_prefix = "idx_"
uniq_index_prefix = "uniq_"
table_prefix = ""
# explain判断受影响行数时使用的规则, 默认值"first"
# 可选值: "first", "max"
# "first": 使用第一行的explain结果作为受影响行数
# "max": 使用explain结果中的最大值作为受影响行数
explain_rule = "first"
# 安全更新是否开启(mysql自身的功能).
# -1 表示不做操作,基于远端数据库 [默认值]
# 0 表示关闭安全更新
# 1 表示开启安全更新
sql_safe_updates = 1
support_charset = "utf8,utf8mb4"
support_engine = "innodb"
#lang = "en-US"
lang = "zh-CN"
# 全量日志
general_log = false
[osc]
# 用来设置在arkit返回结果集中,对于原来OSC在执行过程的标准输出信息是不是要打印到结果集对应的错误信息列中,
# 如果设置为1,就不打印,如果设置为0,就打印。而如果出现了错误,则都会打印。默认值:OFF
osc_print_none = false
# 对应参数pt-online-schema-change中的参数--print。默认值:OFF
osc_print_sql = false
# 全局的OSC开关,默认是打开的,如果想要关闭则设置为OFF,这样就会直接修改。默认值:OFF
osc_on = false
# 这个参数实际上是一个OSC开关,如果设置为0,则全部ALTER语句都使用OSC方式,
# 如果设置为非0,则当这个表占用空间大小大于这个值时才使用OSC方式。
# 单位为M,这个表大小的计算方式是通过语句
# select (DATA_LENGTH INDEX_LENGTH)/1024/1024 from information_schema.tables
# where table_schema = 'dbname' and table_name = 'tablename' 来实现的。默认值:16
# [0-1048576]
osc_min_table_size = 1024
# 对应参数pt-online-schema-change中的参数alter-foreign-keys-method,具体意义可以参考OSC官方手册。默认值:none
# [auto | none | rebuild_constraints | drop_swap]
osc_alter_foreign_keys_method = "none"
# 对应参数pt-online-schema-change中的参数recursion_method,具体意义可以参考OSC官方手册。默认值:processlist
# [processlist | hosts | none]
osc_recursion_method = "processlist"
# 对应参数pt-online-schema-change中的参数--max-lag。默认值:3
osc_max_lag = 3
# 类似--max-lag,检查集群暂停流量控制所花费的平均时间(仅适用于PXC 5.6及以上版本,会自动检测)
osc_max_flow_ctl = -1
# 对应参数pt-online-schema-change中的参数 --set-vars lock_wait_timeout=?
osc_lock_wait_timeout = 60
# 对应参数pt-online-schema-change中的参数--[no]check-alter。默认值:ON
osc_check_alter = true
# 对应参数pt-online-schema-change中的参数--[no]check-replication-filters。默认值:ON
osc_check_replication_filters = true
# 对应参数pt-online-schema-change中的参数--[no]drop-old-table。默认值:ON
osc_drop_old_table = true
# 对应参数pt-online-schema-change中的参数--[no]drop-new-table。默认值:ON
osc_drop_new_table = true
# 对应参数pt-online-schema-change中的参数--max-load中的thread_running部分。默认值:80
osc_max_thread_running = 80
# 对应参数pt-online-schema-change中的参数--max-load中的thread_connected部分。默认值:1000
osc_max_thread_connected = 1000
# 对应参数pt-online-schema-change中的参数--critical-load中的thread_running部分。默认值:80
osc_critical_thread_running = 80
# 对应参数pt-online-schema-change中的参数--critical-load中的thread_connected部分。默认值:1000
osc_critical_thread_connected = 1000
# 对应参数pt-online-schema-change中的参数--chunk-time。默认值:1
osc_chunk_time = 1.0
# 对应参数pt-online-schema-change中的参数--chunk-size-limit。默认值:4
osc_chunk_size_limit = 4
# 对应参数pt-online-schema-change中的参数--chunk-size。默认值:1000
osc_chunk_size = 1000
# 对应参数pt-online-schema-change中的参数--check-interval,意义是Sleep time between checks for --max-lag。默认值:5
osc_check_interval = 5
osc_bin_dir = "/usr/local/bin"
[ghost]
ghost_on = true
ghost_allow_on_master = true
ghost_assume_rbr = true
ghost_chunk_size = 10000
ghost_concurrent_rowcount = true
ghost_cut_over = "atomic"
ghost_cut_over_lock_timeout_seconds = 3
ghost_default_retries = 60
ghost_heartbeat_interval_millis = 500
ghost_max_lag_millis = 1500
ghost_approve_renamed_columns = true
ghost_exponential_backoff_max_interval = 64
ghost_dml_batch_size = 100
ghost_ok_to_drop_table = true
ghost_skip_foreign_key_checks = true
[inc_level]
er_alter_table_once = 1
er_auto_incr_id_warning = 1
er_autoinc_unsigned = 1
er_blob_cant_have_default = 1
er_cant_change_column = 1
er_cant_change_column_position = 1
er_cant_set_charset = 1
er_cant_set_collation = 1
er_cant_set_engine = 1
er_change_column_type = 1
er_change_too_much_rows = 1
er_char_to_varchar_len = 1
er_charset_on_column = 1
er_column_have_no_comment = 1
er_datetime_default = 1
er_foreign_key = 2
er_ident_use_keyword = 1
er_implicit_type_conversion = 1
er_inc_init_err = 1
er_index_name_idx_prefix = 1
er_index_name_uniq_prefix = 1
er_insert_too_much_rows = 1
er_invalid_data_type = 1
er_invalid_ident = 1
er_join_no_on_condition = 1
er_json_type_support = 2
er_must_have_columns = 1
er_columns_must_have_index = 1
er_columns_must_have_index_type_err = 1
er_no_where_condition = 1
er_not_allowed_nullable = 1
er_ordery_by_rand = 1
er_partition_not_allowed = 1
er_pk_cols_not_int = 1
er_pk_too_many_parts = 1
er_select_only_star = 1
er_set_data_type_int_bigint = 2
er_table_charset_must_null = 1
er_table_charset_must_utf8 = 1
er_table_must_have_comment = 1
er_table_must_have_pk = 1
er_table_prefix = 1
er_text_not_nullable_error = 1
er_timestamp_default = 1
er_too_many_key_parts = 1
er_too_many_keys = 1
er_too_much_auto_datetime_cols = 2
er_too_much_auto_timestamp_cols = 2
er_udpate_too_much_rows = 1
er_use_enum = 1
er_use_text_or_blob = 2
er_with_default_add_column = 1
er_with_insert_field = 1
er_with_limit_condition = 1
er_with_orderby_condition = 1
er_wrong_and_expr = 1
3、启动goinception
cd /usr/local/goinception
./goInception -config=config/config.toml &
三、goinception测试
1、安装依赖
pip install pymysql prettytable
2、测试脚本(t_goinception.py)
import pymysql
import prettytable as pt
tb = pt.PrettyTable()
sql = '''/*--user=root;--password=password;--host=127.0.0.1;--check=0;--port=3306;--execute=1;--backup=1;*/
inception_magic_start;
use go;
create table t1(id int primary key,c1 int,c2 int );
insert into t1(id,c1,c2) values(1,1,1);
inception_magic_commit;'''
conn = pymysql.connect(host='127.0.0.1', user='', passwd='',
db='', port=8888, charset="utf8mb4")
cur = conn.cursor()
ret = cur.execute(sql)
result = cur.fetchall()
cur.close()
conn.close()
tb.field_names = [i[0] for i in cur.description]
for row in result:
tb.add_row(row)
print(tb)
3、测试结果
五、goInception的三个阶段
goInception内部会进行三个阶段的操作,分别是审核阶段,执行阶段和备份阶段。
1、审核阶段
1)goInception在收到sql语句后,先会解析注释中的远程数据库配置,并建立连接
2)如果开启了备份功能,则会检查binlog日志是否开启(log_bin=ON)
3)判断语法开始位置,必须以 inception_magic_start 语法开始
4)开始逐行解析,并进行语法树解析,失败时返回
5)解析到use dbtest,会通过show databases判断数据库是否存在
6)解析到create table table1...,接下来进行建表的校验
- 判断库、表是否存在
- 表名、列名长度校验,关键字校验
- 存储引擎校验,表/列的字符集和注释校验
- 列名重复性校验
- 自增列个数校验,自增列列名校验,起始值校验,建议添加unsigned属性
- 外键校验,分区表校验
- 列类型校验,部分类型有设置开关,开启后才能使用,char也会建议改为varchar类型
- 默认值校验,日期格式校验
- not null约束校验
- 索引名校验,前缀校验,长度校验,表索引个数,索引列数,索引列重复性校验
7)解析到insert into table1 ...,接下来进行insert的校验
- 判断表、列是否存在
- 判断insert列数和值列表是否一致
- 检查不为null的列,是否指定了null
- 检查列是否重复指定
- 如果使用了insert select语法,会审核select语法是否有不存在的表或列
8)解析到inception_magic_commit,判断所有的审核是否成功,如果有错误时,直接返回,而有警告时会判断是否开启了忽略警告的参数,以判断是否进行下一步
2、执行阶段
- 只有在审核成功时(或有警告但启用了忽略),才会进入执行阶段
- 有些语法是不会执行的,其在审核阶段已经执行,比如desc table1;语法
接下来继续说明执行阶段:
1)在执行阶段,DDL语句和DML语句走不同的逻辑,其中DML通过binlog解析实现回滚,而DDL语句根据语法树规则直接生成逆向SQL即可
2)DML:在开始执行和执行完成时,记录binlog位置
3)DDL和DML:开始执行,并在执行失败时记录失败原因并结束执行操作,成功时记录受影响行数
4)执行中可能想要执行KILL以中止执行
3、备份阶段
1)到达备份阶段有两种情况,可能执行成功也可能部分成功了,此时会进行判断,只备份执行成功的语句
2)DDL的备份是保存自动生成的逆向SQL语句
3)DML的备份是根据执行前后记录的binlog位置和线程号,模拟从库的形式获取binlog信息,并做事件解析
4)解析binlog日志要求binlog格式必须为ROW模式,该模式也会有备份前检查和自动设置,因此可能需要SUPER权限
5)在解析过binlog后,会生成逆向的SQL语句,并异步批量写入备份库
6)在回滚语句写入完成后,所有操作执行完成,并返回结果给客户端。
后面会分享更多devops和DBA方面内容,感兴趣的朋友可以关注下!
,