MySQL SQL審核利器-Inception

引子

最近打算做一個(gè) MySQL 的數(shù)據(jù)庫運(yùn)維平臺(tái)秀仲。這里面有一個(gè)非常重要的功能就是 SQL 的審核,如果完全靠人工去實(shí)現(xiàn)就沒必要做成一個(gè)平臺(tái)了。正沒頭緒如何去實(shí)現(xiàn)的時(shí)候菇曲,google 了一下,看下有沒有現(xiàn)成的開源方案抚吠。果不其然常潮,github 上發(fā)現(xiàn)一個(gè) 【去哪兒網(wǎng)】開源的一個(gè)數(shù)據(jù)庫運(yùn)維工具 Inception, 它是一個(gè)集審核、執(zhí)行楷力、備份及生成回滾語句于一身的MySQL自動(dòng)化運(yùn)維工具喊式。

Inception 介紹

Inception 的架構(gòu)圖如下圖所示孵户,簡單來說,Inception 就是一個(gè) MySQL 的代理岔留,能夠幫助你審核 SQL夏哭,執(zhí)行 SQL,備份 SQL 影響的記錄献联。Inception 是一個(gè) C/S 的軟件架構(gòu)竖配。我們可以通過原生的 MySQL 客戶端 去連接,也可以通過遠(yuǎn)程的接口去連接酱固,目前執(zhí)行只支持通過C/C++接口械念、Python接口來對(duì)Inception訪問

inception-architecture.png

執(zhí)行流程圖如下:

inception執(zhí)行流程圖.png

安裝 Inception

我安裝的環(huán)境
OS: Ubuntu 16.04.2 LTS

安裝依賴

  • 下載bison: 版本最好是2.6之前的(Ubuntu 16.04.2 LTS 版本下安裝的是 bison-2.5.1)运悲,最新的可能會(huì)有問題龄减,下載之后,需要自己編譯源碼來安裝班眯,具體安裝方法希停,可以參數(shù)網(wǎng)上的一些說明。
  • cmake安裝:apt-get install cmake
  • ncurses安裝:apt-get install libncurses5-dev
  • 安裝openssl:apt-get install libssl-dev
  • 安裝g++:sudo apt-get install g++
  • 安裝m4: apt-get install m4

編譯安裝 Inception

git clone https://github.com/mysql-inception/inception.git
sh inception_build.sh debug [linux]  (如果不指定就是linux平臺(tái)署隘,而如果要指定是Xcode宠能,就后面指定Xcode)

可執(zhí)行文件在 debug/sql/Debug/ 目錄下面(不同平臺(tái)有可能不相同)。

啟動(dòng) Inception

創(chuàng)建一個(gè)配置文件 inc.cnf, 里面主要是配置 Inception 啟動(dòng)的端口磁餐,SQL 審核的策略违崇,備份數(shù)據(jù)庫的配置等等,更多可參考官方文檔诊霹。

[inception]
general_log=1
general_log_file=inception.log
port=6669   # Inception 的監(jiān)聽的端口
socket=/tmp/inc.socket
character-set-client-handshake=0
character-set-server=utf8
inception_remote_system_password=root  # 備份數(shù)據(jù)庫密碼
inception_remote_system_user=wzf1      # 備份數(shù)據(jù)庫用戶名
inception_remote_backup_port=3306      # 備份數(shù)據(jù)庫端口
inception_remote_backup_host=127.0.0.1 # 備份數(shù)據(jù)庫地址
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_enable_blob_type=1
inception_check_column_default_value=1

啟動(dòng)

./Inception --defaults-file=inc.cnf

訪問

  1. 通過原生的 MySQL 客戶端的方式羞延。主要注意的是,請(qǐng)不要將的 SQL 語句塊脾还,放到 MySQL 客戶端中執(zhí)行伴箩,因?yàn)檫@是一個(gè)自動(dòng)化運(yùn)維工具,如果使用交互式的命令行來使用的話沒有意義鄙漏,所有的 SQL 執(zhí)行應(yīng)該都通過接口的方式嗤谚,這個(gè)方式僅僅可用來查看和設(shè)置上訴配置文件里的配置,如 inception get variables; 可查看所有的變量怔蚌,更多請(qǐng)參考官方文檔巩步。
mysql -uroot -h127.0.0.1 -P6669
  1. 通過接口的方式。下面是官方示例中的 Python 代碼媚创,需要注意的是如果使用 Python3 的 pymsql 去連接會(huì)有異常渗钉,目前的解決方案是需要修改 pymysql 的源碼,具體 issue
#!/usr/bin/python
#-\*-coding: utf-8-\*-
import MySQLdb
sql='/*--user=username;--password=password;--host=127.0.0.1;--execute=1;--port=3306;*/\
inception_magic_start;\
use mysql;\
CREATE TABLE adaptive_office(id int);\
inception_magic_commit;'
try:
    conn=MySQLdb.connect(host='127.0.0.1',user='',passwd='',db='',port=9998)
    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])

SQL 審核 & 執(zhí)行

通過 Inception 對(duì)語句進(jìn)行審核時(shí),必須要告訴 Inception 這些語句對(duì)應(yīng)的數(shù)據(jù)庫地址鳄橘、數(shù)據(jù)庫端口以及Inception連接數(shù)據(jù)庫時(shí)使用的用戶名声离、密碼等信息,而不能簡單的只是執(zhí)行一條sql語句瘫怜,所以必須要通過某種方式將這些信息傳達(dá)給 Inception术徊。

連接信息放在 /* ... */ 的注釋中,真正的 SQL 語句則包括在 inception_magic_startinception_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;

連接的信息里可以配置更多的信息鲸湃,比如關(guān)閉備份等等赠涮,具體請(qǐng)參考官方文檔

審核

審核的規(guī)范見官方文檔暗挑,有些規(guī)范是可配置的笋除,可根據(jù)自己公司的規(guī)范在 Inception 的配置文件中配置。

執(zhí)行

注意下炸裆,官方說是支持 DDL垃它,DML 語句的,但是并不支持 SELECT 查詢烹看。

inception_accept.png

比如通過 Inception 執(zhí)行一個(gè)建表語句:

...
inception_magic_start;  
use mysql;  
CREATE TABLE adaptive_office(id int);  
inception_magic_commit;
...

返回結(jié)果, 可見是每一條 SQL 就會(huì)返回一個(gè)可執(zhí)行的結(jié)果国拇,errlevel 非 0 時(shí)表示執(zhí)行失敗,下面所示中的第二條 SQL 語句 Audit completed(審核完成) 但是不符合建表的規(guī)范惯殊,更多關(guān)于返回結(jié)果的說明可見官方文檔

'ID', 'stage', 'errlevel', 'stagestatus', 'errormessage', 'SQL', 'Affected_rows', 'sequence', 'backup_dbname', 'execute_time', 'sqlsha1'
1 | CHECKED | 0 | Audit completed | None | use inception_test | 0 | '0_0_0' | None | 0 | 
2 | CHECKED | 1 | Audit completed | Set engine to innodb for table 'adaptive_office'.
Set charset to one of 'utf8mb4' for table 'adaptive_office'.
Set comments for table 'adaptive_office'.
Column 'id' in table 'adaptive_office' have no comments.
Column 'id' in table 'adaptive_office' is not allowed to been nullable.
Set Default value for column 'id' in table 'adaptive_office'
Set a primary key for table 'adaptive_office'. | CREATE TABLE adaptive_office(id int) | 0 | '0_0_1' | 10_10_1_67_1028_inception_test | 0 | 

備份功能

前提條件

  • 線上服務(wù)器必須要打開 binlog酱吝,不然不會(huì)備份及生成回滾語句。
  • 參數(shù) binlog_format 必須要設(shè)置為 mixed 或者 row 模式土思,通過語句:set global binlog_format=mixed/row 來設(shè)置务热,如果是 statement 模式,則不做備份及回滾語句的生成己儒。

注意點(diǎn)

  • 在備份是陕习,執(zhí)行時(shí)被影響的表如果沒有主鍵的話,就不會(huì)做備份了址愿,這樣更簡單并且備份時(shí)間及數(shù)據(jù)都會(huì)少一點(diǎn),不然再生成的回滾語句的 WHERE 條件就會(huì)將所有列寫進(jìn)去冻璃,這樣會(huì)影響性能且沒有太大意義响谓,所以在 WHERE 條件中,只需要主鍵即可省艳。

Inception 在做 DML 操作時(shí)具有備份功能(默認(rèn)開啟娘纷,可通過在執(zhí)行 SQL 中注釋文件中指定 --disable-remote-backup),它會(huì)將所有當(dāng)前語句修改的行備份下來跋炕,存儲(chǔ)到一個(gè)指定的備份庫中赖晶, 備份庫通過配置 Inception 參數(shù)來指定。

關(guān)于備份數(shù)據(jù)庫的命名方式,備份機(jī)器的庫名組成是由線上機(jī)器的 IP 地址的點(diǎn)換成下劃線遏插,再加上端口號(hào)捂贿,再加上庫名三部分,這三部分也是通過下劃線連接起來的胳嘲。例如:我執(zhí)行 DML 操作的數(shù)據(jù)庫地址是 192.168.1.1, 端口是 3306, 庫名是 inceptiondb, 則在備份數(shù)據(jù)庫中表名為:192_168_1_1_3306_inceptiondb厂僧。

比如,我有一個(gè) inception_test 庫了牛,其中有一張 userinfo 表颜屠,就兩個(gè)字段:

userinfo.png

我通過 Inception 去執(zhí)行一個(gè) innert 操作:

/*--user=root;--password=xxx;--host=1.1.1.1;--execute=1;--port=3306;--sleep=0;--enable-remote-backup;*/\
inception_magic_start;\
use inception_test; \
insert into userinfo(`username`) values("test");\
inception_magic_commit;

返回的結(jié)果如下, 可以看到 Execute Successfully Backup successfully:

2 | EXECUTED | 0 | Execute Successfully
Backup successfully | None | insert into userinfo(`username`) values("test") | 1 | '1533716166_25519001_1' | 1_1_1_1_3306_inception_test | 0.060 | 

查看下備份數(shù)據(jù)庫中的 1_1_1_1_3306_inception_testuserinfo 表的結(jié)果, 根據(jù) innert 的語句生成了一條 delete 回滾語句:

3   DELETE FROM `inception_test`.`userinfo` WHERE id=4; 1533716166_25519001_1

那么,我需要如果正確地找到回滾的語句呢鹰祸?

可以查看下備份庫 1_1_1_1_3306_inception_testuserinfo 的表結(jié)構(gòu):

backup_userinfo.png

主要有兩個(gè)字段:

  • rollback_statement text: 生成修改的回滾語句甫窟。
  • opid_time varchar(50): 這個(gè)列存儲(chǔ)的是的被執(zhí)行的 SQL 語句在執(zhí)行時(shí)的一個(gè)序列號(hào),這個(gè)序列號(hào)由三部分組成:timestamp(int 值蛙婴,是語句被執(zhí)行的時(shí)間點(diǎn)) + 線上服務(wù)器執(zhí)行時(shí)所產(chǎn)生的 thread_id + 當(dāng)前這條語句在所有被執(zhí)行的語句塊中的一個(gè)序號(hào)組成粗井。可見上面的結(jié)果:1533716166_25519001_1, 這個(gè)序列號(hào)會(huì)出現(xiàn)在執(zhí)行返回的結(jié)果中敬锐,所有需要回滾就是根據(jù)這個(gè)序列號(hào)去備份表中查詢回滾的 SQL 語句背传。

更多說明,請(qǐng)參考官方文檔中的備份功能說明台夺。

最后

有了這么好用的工具径玖,基于這個(gè)為基礎(chǔ),我們?cè)趯懸粋€(gè) WEB 頁面做一個(gè)權(quán)限審批管理等功能颤介,一個(gè)數(shù)據(jù)庫運(yùn)維平臺(tái)就可以實(shí)現(xiàn)了梳星,真的需要自己去寫嗎?我有發(fā)現(xiàn)了一個(gè)基于 Inception 實(shí)現(xiàn)的一個(gè)數(shù)據(jù)庫運(yùn)維平臺(tái) Yearning滚朵。

感謝開源冤灾!

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市辕近,隨后出現(xiàn)的幾起案子韵吨,更是在濱河造成了極大的恐慌,老刑警劉巖移宅,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件归粉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡漏峰,警方通過查閱死者的電腦和手機(jī)糠悼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浅乔,“玉大人倔喂,你說我怎么就攤上這事。” “怎么了席噩?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵班缰,是天一觀的道長。 經(jīng)常有香客問我班挖,道長鲁捏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任萧芙,我火速辦了婚禮给梅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘双揪。我一直安慰自己动羽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布渔期。 她就那樣靜靜地躺著运吓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疯趟。 梳的紋絲不亂的頭發(fā)上拘哨,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音信峻,去河邊找鬼倦青。 笑死,一個(gè)胖子當(dāng)著我的面吹牛盹舞,可吹牛的內(nèi)容都是我干的产镐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼踢步,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼癣亚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起获印,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤述雾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后兼丰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绰咽,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年地粪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琐谤。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蟆技,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情质礼,我是刑警寧澤旺聚,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站眶蕉,受9級(jí)特大地震影響砰粹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜造挽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一碱璃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饭入,春花似錦嵌器、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乾忱,卻和暖如春讥珍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背窄瘟。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工衷佃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寞肖。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓纲酗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親新蟆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子觅赊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容