Inception  是去哪儿网发布的MySQL自动化运维及语句审核工具 . 项目地址 https://github.com/mysql-inception/inception. 文档说明:

http://mysql-inception.github.io/inception-document/.

一:安装说明:

1首选要确保线上已安装好mysql数据库.

2线上服务器必须要打开 binlog ,参数binlog_format必须要设置为 mixed 或者 row 模式. 不然不会备份及生成回滚语句.

参数 server_id 必须要设置为非0及非1,不然在备份时会报错。

以mysql5.5为例:修改/etc/mysql/my.cnf

确保有以下内容:

server-id = 2
binlog_format = MIXED
log_bin = /var/log/mysql/mysql-bin.log

3.线上服务器一定要有指定用户名的权限,这个是在语句前面的注释中指定的,做什么操作就要有什么权限,否则还是会报错,如果需要执行的功能,则要有线上执行语句的权限,比如DDL及DML,同时如果要执行inception show 等远程命令的话,有些语句是需要特殊权限的,这些权限也是需要授予的.

需要注意的:
在执行时,不能将 DML 语句及 DDL 语句放在一起执行,否则会因为备份解析binlog时由于表结构的变化出现不可预知的错误,如果要有同时执行 DML 及 DDL,则请分开多个语句块儿来执行,如果真的这样做了,Inception 会报错,不会去执行。

4 .首先就是编译,在源码根目录下面有一个文件inception_build.sh,执行命令sh inception_build.sh,会输出使用方法。 实际上只需要执行inception_build.sh debug [Xcode]即可,后面的平台是可选的,如果不指定就是linux平台,而如果要指定是Xcode,就后面指定Xcode,而debug是编译的目录,编译之后,所有的生成文件都在这个目录下面,包括可执行文件Inception。可执行文件在debug/sql/Debug/目录下面(不同平台有可能不相同)。

注意: centos下 运行inception_build.sh不成功,

所以要用以下命令去安装

cmake -DWITH_DEBUG=OFF -DCMAKE_INSTALL_PREFIX=./mysql -DMYSQL_DATADIR=./mysql/data \
-DWITH_SSL=yes -DCMAKE_BUILD_TYPE=RELEASE\
-DWITH_ZLIB=bundled\
-DMY_MAINTAINER_CXX_WARNINGS="-Wall -Wextra -Wunused -Wwrite-strings -Wno-strict-aliasing -Wno-unused-parameter -Woverloaded-virtual" \
-DMY_MAINTAINER_C_WARNINGS="-Wall -Wextra -Wunused -Wwrite-strings -Wno-strict-aliasing -Wdeclaration-after-statement" \

make install

如果编译出错,请先安装信依赖包,以ubuntu为例 :

  1. 下载bison:http://ftp.gnu.org/gnu/bison/,版本最好是2.6之前的,最新的可能会有问题
  2. cmake安装:apt-get install cmake
  3. ncurses安装:apt-get install libncurses5-dev
  4. 安装openssl:apt-get install libssl-dev
  5. 安装g++:sudo apt-get install g++

安装完成这些,再编译应该是没什么问题了,那么需要注意的是,每次如果出错之后,需要把编译目录删除掉,重新执行,不然会执行出错。

5.添加配置文件: 编译完成之后,就是使用了,那么需要一个配置文件(inc.cnf)

[inception]
general_log=1
general_log_file=inception.log
port=6669  #说明:inception的端口
socket=/data/workspace/inception_data/inc.socket
character-set-client-handshake=0
character-set-server=utf8
inception_remote_system_password=root
inception_remote_system_user=root
inception_remote_backup_port=3306 #说明:远程备份服务器的端口
inception_remote_backup_host=127.0.0.1 #说明:远程备份服务器的地址
inception_support_charset=utf8mb4
inception_enable_nullable=0
inception_check_primary_key=1
inception_check_column_comment=1
inception_check_table_comment=1
inception_osc_min_table_size=1
inception_osc_bin_dir=/data/temp
inception_osc_chunk_time=0.1
inception_ddl_support=1
inception_enable_blob_type=1
inception_check_column_default_value=1

上面这些参数的配置都是本人随便举例而已。

所有的参数请参考 http://mysql-inception.github.io/inception-document/variables/

把inc.cnf放到主目录(~)下:

6.启动Inception. 现在就到启动时间了,那么启动有两种方式,和MySQL是一样的
1. Inception --defaults-file=inc.cnf
2. Inception --port=6669

第二种方法就是只指定一个端口,其它参数都是默认值,而第一种方法就是在配置文件中可以指定很多参数,按照自己喜欢的规则来配置。

注意: 因为Inception支持OSC执行的功能,是通过调用pt-online-schema-change工具来做的,但如果Inception后台启动(&)的话,可能会导致pt-online-schema-change在执行完成之后,长时间不返回,进而导致Inception卡死的问题,这个问题后面会解决,但现阶段请尽量不要使用后台启动的方式,或者可以使用nohup Inception启动命令 &的方式来启动。

启动如果不报错的话,说明已经启动成功了,实际上很难让它报错,因为非常轻量级.

注意:如果启动时报以下错误:

显示如下
Warning: World-writable config file '/home/xxxxxxxx/inc.cnf' is ignored
2015-09-08 15:44:08 0 [Note] Welcome to use Inception2.0.18-beta
2015-09-08 15:44:08 11147 [Note] Server hostname (bind-address): '*'; port: 3306
2015-09-08 15:44:08 11147 [Note] IPv6 is available.
2015-09-08 15:44:08 11147 [Note] - '::' resolves to '::';
2015-09-08 15:44:08 11147 [Note] Server socket created on IP: '::'.
2015-09-08 15:44:08 11147 [ERROR] Can't start server: Bind on TCP/IP port: Address already in use
2015-09-08 15:44:08 11147 [ERROR] Do you already have another mysqld server running on port: 3306 ?
2015-09-08 15:44:08 11147 [ERROR] Aborting

需要修改一下inc.cnf的权限小一点,自己能读写,其它只读即可.

启动成功之后,可以简单试一下看,通过MySQL客户端
mysql -uroot -h127.0.0.1 -P6669
登录上去之后,再执行一个命令:
inception get variables;
输出了所有的变量,恭喜你,已经启动成功了,都说了非常简单。

二.Inception 使用方法.

通过Inception对语句进行审核时,必须要告诉Inception这些语句对应的数据库地址、数据库端口以及Inception连接数据库时使用的用户名、密码等信息,而不能简单的只是执行一条sql语句,所以必须要通过某种方式将这些信息传达给Inception。而我们选择的方式是,为了不影响语句的意义,将这些必要信息都以注释的方式放在语句最前面,也就是说所有这些信息都是被 /**/括起来的,每一个参数都是通过分号来分隔,类似的方式为:
/*--user=username;--password=xxxx;--host=127.0.0.1;--port=3306;*/
当然支持的参数不止是这几个,后面还会介绍一些其它的参数。Inception要做的是一个语句块的审核,需要引入一个规则,将要执行的语句包围起来,Inception规定,在语句的最开始位置,要加上inception_magic_start;语句,在执行语句块的最后加上inception_magic_commit;语句,这2个语句在 Inception 中都是合法的、具有标记性质的可被正确解析的 SQL 语句。被包围起来的所有需要审核或者执行的语句都必须要在每条之后加上分号,其实就是批量执行SQL语句。(包括use database语句之后也要加分号,这点与 MySQL 客户端不同),不然存在语法错误。

在具体执行时,在没有解析到inception_magic_start之前如果发现要执行其它的语句,则直接报错,因为规则中inception_magic_start是强制的。而如果在执行的语句块最后没有出现inception_magic_commit,则直接报错,不会做任何操作。 在前面注释部分,需要指定一些操作的选项,包括线上用户名、密码、数据库地址、检查/执行等,下面是一个简单的例子:

/*--user=zhufeng;--password=xxxxxxxxxxx;--host=xxxxxxxxxx; --enable-check;--port=3456;*/

inception_magic_start;

use mysql;

CREATE TABLE adaptive_office(id int);

inception_magic_commit;

那么上面这一段就是一批正常可以执行的SQL语句,目前执行只执行通过C/C++接口、Python接口来对Inception访问,这一段必须是一次性的通过执行接口提交给Inception,那么在处理完成之后,Inception会返回一个结果集,来告诉我们这些语句中存在什么错误,或者是完全正常等等。

下面是一段执行上面语句的Python程序的例子:

创建一个表:

#!/usr/bin/python
#-\*-coding: utf-8-\*-
import MySQLdb
sql='/*--user=root;--password=root;--host=127.0.0.1;--execute=1;--port=3306;*/\
inception_magic_start;\
use test;\
CREATE TABLE `alifeba_user` (\
`ID` int(11) unsigned NOT NULL auto_increment comment"aaa",\
`username` varchar(50) NOT NULL Default "" comment"aaa",\
`realName` varchar(50) NOT NULL Default "" comment"aaa",\
`age` int(11) NOT NULL Default 0 comment"aaa",\
PRIMARY KEY (`ID`)\
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT="AAAA";\
inception_magic_commit;'
try:
conn=MySQLdb.connect(host='127.0.0.1',user='',passwd='',db='',port=6669)

cur=conn.cursor()
ret=cur.execute(sql)
result=cur.fetchall()
num_fields = len(cur.description)
field_names = [i[0] for i in cur.description]
print field_names
for row in result:
print row[0], "¦",row[1],"¦",row[2],"¦",row[3],"¦",row[4],"¦",
row[5],"¦",row[6],"¦",row[7],"¦",row[8],"¦",row[9],"¦",row[10]
cur.close()
conn.close()
except MySQLdb.Error,e:
print "Mysql Error %d: %s" % (e.args[0], e.args[1])

执行这段程序之后,返回的结果如下表示执行成功:

['ID', 'stage', 'errlevel', 'stagestatus', 'errormessage', 'SQL', 'Affected_rows', 'sequence', 'backup_dbname', 'execute_time', 'sqlsha1']
1 | RERUN | 0 | Execute Successfully | None | 2 | EXECUTED | 0 | Execute Successfully
Backup successfully | None |

如果返回以下结果,表示没有执行成功:

['ID', 'stage', 'errlevel', 'stagestatus', 'errormessage', 'SQL', 'Affected_rows', 'sequence', 'backup_dbname', 'execute_time', 'sqlsha1']
1 | CHECKED | 0 | Audit completed | None | 2 | CHECKED | 1 | Audit completed | Set comments for table 'alifeba_user2'.
Column 'ID' in table 'alifeba_user2' have no comments.
Set unsigned attribute on auto increment column in table 'alifeba_user2'.
Column 'username' in table 'alifeba_user2' is not allowed to been nullable.
Set Default value for column 'realName' in table 'alifeba_user2' |

其中绿色字体都是提示你需要如何再修改的,按提示修改后,如果再没有 这些提示,应该就可以执行成功了.

从返回结果可以看到,每一行语句的审核及执行信息,最前面打印的是field_names,表示Inception的返回结果集的列名信息,总共包括十个列,下面是每个列对应的结果.

注意:最后一个“|”后面其实是存储列sqlsha1的,但这里没有改表语句,所以都是空.

下面是一些其它操作例子:

#!/usr/bin/python
#-\*-coding: utf-8-\*-
import MySQLdb
sql='/*--user=root;--password=root;--host=localhost;--execute=1;--enable-remote-backup;--port=3306;*/\
inception_magic_start;\
use test;\
INSERT INTO v9_wap(siteid,sitename,logo,domain,setting) VALUES ("12","aa","bb","cc","dd");\ #插入一条数据
delete from   v9_wap where siteid=11;\ #删除一条数据
update  v9_wap set sitename="haha" where siteid=10;\  #更新一条数据
inception_magic_commit;'

try:
conn=MySQLdb.connect(host='127.0.0.1',user='',passwd='',db='',port=6669)
cur=conn.cursor()
ret=cur.execute(sql)
result=cur.fetchall()
num_fields = len(cur.description)
field_names = [i[0] for i in cur.description]
print field_names
for row in result:
print row[0], "¦",row[1],"¦",row[2],"¦",row[3],"¦",row[4],"¦",
row[5],"¦",row[6],"¦",row[7],"¦",row[8],"¦",row[9],"¦",row[10]
cur.close()
conn.close()
except MySQLdb.Error,e:
print "Mysql Error %d: %s" % (e.args[0], e.args[1])

上面几个插入,删除,更新操作后,会在备份数据库另外创建2个数据库用于备份,一个库是inception,并生成表statistic.

另一个数据库是主机_端口_库名 如localhost_3306_test,具体备份操作后面讲.

三.Inception支持选项及意义

参见 http://mysql-inception.github.io/inception-document/option/

四.Inception 备份功能说明

上面已经提到,Inception在做DML操作时,具有备份功能,它会将所有当前语句修改的行备份下来,存储到一个指定的库中,这些库的指定需要通过几个参数,它们分别是:

  • inception_remote_backup_host //远程备份库的host
  • inception_remote_backup_port //远程备份库的port
  • inception_remote_system_user //远程备份库的一个用户
  • inception_remote_system_password //上面用户的密码

这些参数可以直接在命令行中指定,也可以用--defaults-file指定一个my.cnf文件,一经指定,再不能更改,除非将服务器关闭,修改之后再次启动。文件中指定这几个参数的值,用法与mysql是相同的。 另外:为了使备份成为一个可选功能,增加一个是不是备份的参数--enable-remote--backup(在前面<<Inception支持选项及意义>>一章中已经介绍过),如果开启则不做备份操作,都是直接执行,另外还有一点,执行时被影响的表如果没有主键的话,就不会做备份了,这样更简单并且备份时间及数据都会少一点,不然回滚语句的WHERE条件就会将所有列写进去,这样会影响性能且没有太大意义,所以在WHERE条件中,只需要主键即可。

备份数据在备份机器的存储,是与线上被修改库一对一的。但因为机器的多(线上机器有很多)对一(备份机器只有一台),所以为了防止库名的冲突,备份机器的库名组成是由线上机器的 IP 地址的点换成下划线,再加上端口号,再加上库名三部分,这三部分也是通过下划线连接起来的。例如:192_168_1_1_3310_inceptiondb.下面用 inceptiondb 举例为线上库名。

针对一个备份库,里面的表与对应线上表都是一一对应的,也就是说线上库inceptiondb中有什么表,在备份库192_168_1_1_3310_inceptiondb中就有什么表,表名也完全相同,不同的只是表中的列不同而已,它是用来存储所有对这个表修改的回滚语句的, 对应的表包括的列主要有下面两个:
rollback_statement text:这个列存储的是针对当前这个表的某一行被修改后,生成的这行修改的回滚语句(目前,ubuntu 14.04环境被修改后,除ddl语句外生成不了回滚语句,原因待研究,centos 没有 问题 )。因为 binlog 是 ROW 模式的,所以不管是什么语句,产生的回滚语句都是针对一行的,同时有可能一条语句的修改影响了多行,那么这里就会有多个回滚语句,但对应的是同一个 SQL 语句。对应关于通过下面的列来关联起来。
opid_time varchar(50):这个列存储的是的被执行的 SQL 语句在执行时的一个序列号,这个序列号由三部分组成:timestamp(int 值,是语句被执行的时间点),线上服务器执行时所产生的 thread_id,当前这条语句在所有被执行的语句块中的一个序号。产生结果类似下面的样子:1413347135_136_3,针对同一个语句影响多行的情况,那么所产生的多行数据中,这个列的值都是相同的,这样就可以找到一条语句对应的所有被影响数据的回滚语句。

除了与原库中的表一一对应之外,每个备份库中还有另外一个表:$_$Inception_backup_information$_$,这就是表名,非常难看,主要是为了防止与原线上库中的表名发生冲突。这个表是用来存储所有对当前库操作的操作记录的,它是公用的,对线上这个库的所有表操作记录都存储在这里面.这个表的字段如下:

opid_time:这个列其实与上面备份表中的列 opid_time 是对应的,这里面存储的每一条记录对应语句块中被执行的一条 SQL 语句,opid_time 就是根据这条语句所生成的,那么一条语句有可能产生多行的影响,那么上面回滚语句表中的多行或者一行对应这个公共表的一行,这样就对上了。
start_binlog_file:这个列从名字就可以看出,表示的是执行这条语句前 binlog 所在位置的文件名,当然这个值不一定准确,因为这是在执行语句前通过show master status;语句来获取的,那么在数据库并发比较高的话,这个值一般都不是准确的当前语句的Binlog开始位置,这个位置只能是这个语句产生的Binlog前面某个位置,同理下面三个位置信息也是一样。 

start_binlog_pos:这个列与上面的列对应,表示的是上面指定文件的位置信息。 
end_binlog_file:这个列表示的是执行当前语句之后,binlog 所在的文件名。 
end_binlog_pos:这个列与上面的列对应,它表示执行完成之后,binlog 在文件end_binlog_file中的偏移位置。 
sql_statement:这个列存储的是当前这个被执行的SQL 语句。
host:表示在什么地址执行了这条语句。
dbname:在哪个库中执行了这个语句。
tablename:表示当前语句影响的表的表名。可以通过这个名字来对应到备份表名。
port:与 host 对应,表示执行时数据库的端口是什么。
time:表示当前语句的执行时间。
type:表示操作类型,现在只支持INSERT、UPDATE、DELETE、CREATEDB、CREATETABLE、ALTERTABLE、DROPTABLE等类型。

关于备份更多请参考 http://mysql-inception.github.io/inception-document/backup/.

五.审核规范与原则

参考 http://mysql-inception.github.io/inception-document/rules/

六.Inception执行返回结果集

见 http://mysql-inception.github.io/inception-document/results/ ,

目前存在的问题,删除一个不存在的数据后,也提示执行成功

['ID', 'stage', 'errlevel', 'stagestatus', 'errormessage', 'SQL', 'Affected_rows', 'sequence', 'backup_dbname', 'execute_time', 'sqlsha1']
1 | RERUN | 0 | Execute Successfully | None | 2 | EXECUTED | 0 | Execute Successfully
Backup successfully | None |

有的列无返回内容. 目前执行DML语句,终端无响应, 也不生成回滚语句.(存在于ubuntu 14.04)

 

转载请注明:来自Lenix的博客
本文地址: http://blog.p2hp.com/archives/2234

最后更新于 2015年9月21日

MySQL自动化运维及语句审核工具 Inception的安装与使用
标签: