騰訊遊戲DBA利刃 - SQL稽核工具介紹
作者介紹
韓全安(willhan) 華中科技大學,碩士,現代資料庫方向。2013年畢業,就職於騰訊到今,工作專案:TMySQL、SQL稽核、InnoDB列壓縮、TSpider、GCS
- 團隊部落格: tencentdba.com
- 團隊Github: https://github.com/TencentDBA/TMySQL
主題簡介
本文將主要從以下幾個部分同大家探討:
- 誕生背景
- 實現原理
- 使用介紹
- 應用示例
1. 誕生背景
騰訊遊戲業務的DB變更流程是由職能化或運維同學在騰訊遊戲GCS平臺(Game Cloud Storage)中提SQLScript的變更單,DBA對SQL逐句進行稽核,通過後再由提單者在GCS平臺執行現網變更。
騰訊遊戲GCS平臺:是騰訊互動娛樂事業群DBA(簡稱:騰訊遊戲DBA)傾力打造,提供多樣化的底層儲存架構(TProxyTMySQLTSpiderTRedis),以及貼合遊戲運營生命週期實現資料層的管理排程體系。
由於變更單據的多樣性與複雜性,變更單的稽核工作不止消耗DBA大量的時間精力,也無法保證變更單的正確性。可能會執行非法SQL導致變更時間延長,影響遊戲正常開服造成損失。
下表為騰訊遊戲 GCS 平臺(Game Cloud Storage)統計2012.7.1~2013.7.1 一年SQL變更單據語法錯誤的結果。
表1 2012.7.1~2013.7.1的單據語法錯誤統計
從上表可以看出,變更因語法錯誤導致的失敗率為3.3%,平均每2天有一個變更失敗是因為語法錯誤。於是誕生了SQL稽核工具(TMySQLParse)。
SQL稽核工具(TMySQLParse)用於對 MySQL的SQL 語句進行語法解析,判定語法正確性,並根據自定義的高危特性檢測SQL是否存在高危情況。
通過將 TMySQLParse 整合到 GCS 平臺中,可以降低人工審單的難度及減少其工作量,從而實現審單的自動化。
在 TMySQLParse 整合 GCS 平臺後,運維的提單就可由SQL稽核工具自動進行語法解析及高危SQL告警,保證提交語法正確的變更單據到現網伺服器中。
SQL稽核工具 TMySQLParse 的git地址(包含有32位與64位可執行檔案): https://github.com/GCSAdmin/tmysqlparse
2. 實現原理
SQL稽核工具應該完全相容 MySQL 的輸入,及解析 MySQL 的語法。
我們改造 MySQL 原始碼的 Client 模組來實現SQL稽核工具的輸入,利用 MySQL 原始碼的語法分析模組來對 SQL 語法進行解析。
下圖1為 SQL 稽核工具與 MySQL 原始碼模組對應示例。
圖1 SQL 稽核工具與 MySQL 原始碼模組對應
SQL稽核工具實現中最重要的兩個模組:輸入模組及語法分析模組,下面分別進行說明。
2.1 輸入模組
SQL稽核工具的輸入模組是對 MySQL Client 原始碼進行了改造。 MySQL Client 部分的邏輯如下:
- MY_INIT(),初始化一些系統函式、資源及變數,比如執行緒、臨界區及tcp/ip等。
- Isatty(),判定輸入輸出是檔案還是 console 。
- load_defaults(),從配置檔案讀取配置引數。
- get_options(),讀取mysql 選項引數。
- batch_readline_init(),初始化 console 大小。
- mysql_server_init(),與伺服器相關資訊的初始化。
- init_alloc_root(),分配 root 記憶體。
- sql_connect(),與Server連線。
- read_and_execute(),處理SQL語句並與Server互動。
- mysql_end(),資源釋放。
其中最主要的函式就是 read_and_execute()
,在這個函式中有對SQL語句的完整處理。
read_and_execute()
函式的主體是一個 for(;;) 迴圈。
在這個迴圈裡,處理每一條讀取或者輸入的字串,分別通過函式 batch_readline()
從檔案讀或函式 my_cgets()
從終端讀,利用哪種方式讀取取決於前面的 isatty()
函式值。
SQL解析工具需要完全相容 MySQL Client 的輸入模式,比如檔案/終端輸入,支援 delimiter 分割斷句,支援各種註釋等,卻不需要連線到MySQL Server,並與MySQL Server進行互動。
因此,SQL稽核工具在MySQL Client的基礎上,不需要做load_defaults
、server_init
、sql_connect
,並且將 read_and_execute()
改造為 read_and_sqlparse
,即提取SQL並進行語法解析。
圖2 MySQL Client與TMySQLParse輸入模組的對比
2.2 語法解析模組
MySQL 語法處理是由 yacc 實現的, yacc(Yet Another Compiler Compiler) ,是一個經典的生成語法分析器的工具。
MySQL 通過 yacc定義語法規則,並且將 SQL 語句解析出來的內容放在LEX結構體裡。
如下圖3所示為 Update 語句的 yacc 規則,
Update:為一個非終結符,後面為一系列的終結符號與非終結符號組合。
如果SQL語句能夠匹配到其中的終結符號,則執行大括弧 {} 中的動作,否則則進一步解析解析成終結符號。
從圖3也可以看出,語法解析的內容存放在LEX結構體中。在 MySQL 原始碼中,函式 parse_sql() 封裝了MySQL中通過 yacc 解析語法的邏輯。傳入一條 SQL 給 parse_sql(), parse_sql()即可將SQL語句生成語法樹,儲存到LEX結構體中。
SQL 稽核工具的語法解析模組就是依賴於MySQL的語法模組實現。 這樣的好處:
- 完全相容 MySQL 的語法
- 不需要構造複雜LEX結構體,這樣除了滿足語法檢查的要求,也可以通過 LEX 獲取語法特徵資訊
為此我們只需要剝離出函式 parse_sql 即可。
圖3 Update語句的yacc規則
3. 使用介紹
上面介紹了 SQL 稽核工具的背景及實現,現在講下SQL稽核工具應如何使用。
先總結下 SQL 稽核工具: 一個基於 MySQL 5.5.24 實現的元件 TMySQLParse,能夠檢查 SQL 語法正確性,並提取需要的語法特徵。
具體一點就是:
- TMySQLParse 是一個獨立元件,能夠相容 MySQL 的輸入(終端/檔案,delimiter 斷句)。
- 完全的支援MySQL語法(MySQL 5.5.24, TMySQL 1.4),併兼容多個 MySQL 版本的保留字 。
- 能夠提取語句型別,包括自定義型別(CREATE_TABLE_WITHOUT_INDEX),能夠提取庫、表、索引等資訊 。
3.1 SQL 稽核工具引數
SQL 解析元件有如下引數,比如指定字符集,字元 MYSQL 版本號,指定輸入的檔案路徑,指定獲取表的個數,獲取 table,database 資訊等。具體詳見圖4:
圖4 TMySQLParse工具選項示例
其中-v引數用來指定MySQL的版本號。 TMySQLParse是基於MySQL 5.5.24的原始碼實現,所以主要支援MySQL 5.5.24版本的語法。此處指定MySQL版本號的意義在於相容MySQL各個版本間的保留字。由於各業務使用習慣不同,開發商可能在MySQL 5.1版本中使用了MySQL 5.5版本的保留字,會被TMySQLParse判定為語法錯誤。
為此我們相容了 MySQL 各個版本間的保留字。即 MySQL 5.5.24 前的版本,使用後面版本新增加的保留字作為表中欄位也可以通過語法檢查。
3.2 SQL 稽核工具的輸入/輸出
SQL 稽核工具 TMySQLParse 提供兩種輸入方式:
- 從終端輸入
- 文字輸入
文字輸入可以通過./tmysqlparse < xxx.sql
。
xxx.sql 即為輸入的檔案。
TMySQLParse 部分引數使用示例,詳見如下:
指定輸出結果到 xxx.xml 中
./tmysqlparse -f xxx.xml
version 是 MySQL 版本號,如 ”5.0”
./tmysqlparse -v version
輸出 TMySQLParse 的版本資訊
./tmysqlparse -V/--version
提供幫助資訊
./tmysqlparse –help
指定資料庫名為test
./tmysqlparse test
示例命令:
./tmysqlparse –f xxx.xml test –v “5.1” < xxx.sql
tmysqlparse以xml的形式輸出SQL檢查的結果。
通過如下定義:
<result></result>
中包含TMySQLParse分析後的所有結果。
<syntax_failed></syntax_failed>
包含所有語法出錯的資訊。
<failed_info></failed_info>
包含一條出錯語句,裡面再分 <sql>、<error_code>、<error_msg>
和 <line>
四部分來輸出出錯SQL語句的資訊。
<risk_warnings></risk_warnings>
包含所有的高危告警資訊,產生告警的前提是語法正確,與 <syntax_failed></syntax_failed>
互相獨立,不存在交集。
<warning_info></warning_info>
包含一條產生高危告警的SQL語句資訊。
<type>、<name>、<text>
和 <line>
四部分給出告警SQL語句資訊。
<info></info>
則儲存額外的資訊
<type>
中包含是產生告警的型別,比如:
STMT_DROP_DB 刪除資料庫操作
STMT _DROP_TABLE 刪除表操作
STMT _DROP_VIEW 刪除檢視操作
STMT _TRUNCATE 清空表操作
STMT _DELETE 刪除操作不帶where條件
STMT _UPDATE 更新操作不帶where條件
STMT _CREATE_TABLE 建立表時blob/text欄位數大於10
STMT _ALTER_TABLE 更改表增加的blob/text欄位數大於10
下圖5為輸出結果的截圖,以 xml 格式輸出有助於對結果進行解析。
3.3 SQL 稽核工具的使用
在下面的 TMySQLParse 的 console 中,輸入瞭如下幾條 SQL 語句,一個建表,一個是 delete * from t1
,一個 alter table
操作。
Tmysqlparse 會稽核這每條 SQL 語句,我們會發現其中2個語法錯誤:
- delete 這條SQL多一個*
- alter table 加欄位多了一個add
另外,也會發現告警,我們的建的表是沒有索引的。 SQL 稽核工具使用示例詳見下圖5:
圖5 TMySQLParse 工具使用示例
更多SQL稽核工具的用法詳見: http://tencentdba.com/blog/tmysqlparse-instructions/
4. 應用示例
騰訊遊戲 GCS 平臺當前已集成了 TMySQLParse 工具,下圖為應用 TMySQLParse 工具後,GCS 平臺的單據檢測效果:
圖6 GCS 平臺中應用TMySQLParse檢測出語法錯誤
點開語法錯別的連結,可得如下詳細語法錯誤資訊,同 MySQL 的表現完全一致。
圖7 點選語法錯誤資訊後所示
SQL 稽核工具除了能夠檢測語法錯誤,還是提示高危的 SQL 語句給 DBA,減少 DBA 審單的壓力,下圖為高危告警的示例圖:
圖8 GCS平臺高危告警示例圖