1. 程式人生 > 其它 >騰訊遊戲DBA利刃 - SQL稽核工具介紹

騰訊遊戲DBA利刃 - SQL稽核工具介紹

作者介紹

韓全安(willhan) 華中科技大學,碩士,現代資料庫方向。2013年畢業,就職於騰訊到今,工作專案:TMySQL、SQL稽核、InnoDB列壓縮、TSpider、GCS

主題簡介

本文將主要從以下幾個部分同大家探討:

  1. 誕生背景
  2. 實現原理
  3. 使用介紹
  4. 應用示例

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 部分的邏輯如下:

  1. MY_INIT(),初始化一些系統函式、資源及變數,比如執行緒、臨界區及tcp/ip等。
  2. Isatty(),判定輸入輸出是檔案還是 console 。
  3. load_defaults(),從配置檔案讀取配置引數。
  4. get_options(),讀取mysql 選項引數。
  5. batch_readline_init(),初始化 console 大小。
  6. mysql_server_init(),與伺服器相關資訊的初始化。
  7. init_alloc_root(),分配 root 記憶體。
  8. sql_connect(),與Server連線。
  9. read_and_execute(),處理SQL語句並與Server互動。
  10. 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_defaultsserver_initsql_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的語法模組實現。 這樣的好處:

  1. 完全相容 MySQL 的語法
  2. 不需要構造複雜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平臺高危告警示例圖