介紹 從系統管理員或 DBA 的角度來講, 總期望將線上的各種變更限制在一個可控的範圍內, 減少一些不確定的因素. 這樣做有幾點好處: 從這三點來看, 有很多種方式可以實現, 比如通過 migrate 等工具強制所有的操作都以統一的方式執行, 這需要開發人員做更多的配合, 所以這類工具在非規模話的業 ...
介紹
從系統管理員或 DBA 的角度來講, 總期望將線上的各種變更限制在一個可控的範圍內, 減少一些不確定的因素. 這樣做有幾點好處:
1. 記錄線上的庫表變更; 2. 對線上的庫表變更有全局的瞭解; 3. 如果有問題, 方便回滾操作;
從這三點來看, 有很多種方式可以實現, 比如通過 migrate 等工具強制所有的操作都以統一的方式執行, 這需要開發人員做更多的配合, 所以這類工具在非規模話的業務場景中較難實現; 另外管理員或 DBA 也可以通過知識庫比如 redmine 等類似的方式記錄變更, 不過不可控因素很多, 特別依賴上線的流程, 也容易出現紕漏. 這就引申出本文要介紹的如何跟蹤線上庫表的變更, 下文以 MySQL 資料庫介紹說明.
跟蹤的方式
在 Postgresql 中, 由於觸發器對各種操作都有很好的支持, 我們完全可以通過觸發器的形式來記錄所有 DDL 語句的變更. 與此相比, MySQL 則顯得較為弱小, 我們只能以其它方式實現類似的目標. 下麵以中間件, log, binlog, 註冊 slave, mysqldiff 五種方式進行介紹.
1. 中間件
現有的中間件 atlas, kingshard, mycat 等, 都以 proxy 的角色部署於程式和 MySQL 之間, 所有發往 MySQL 的 sql 都通過 proxy 進行轉發. 如下圖所示, 我們可以在 proxy 層面增加一些 DDL, DML 相關語句的記錄, 達到跟蹤變更的目的.
+------+ +-------+ +-------+ | app | ---> | proxy | ---> | MySQL | +------+ +-------+ +-------+
這種方式自由度較高, 大家都可以隨意定製. 不過需要一些開發能力, 另外 sql 的過濾也會影響到查詢的性能, 通過中間件來直接修改表結構等操作也是有風險較大的方式.
2. log
這種方式很簡單, 打開 MySQL 的 general log 或 audit log 即可記錄所有的 sql 語句. 這種方式比較適合開發環境, 線上環境如果開啟會產生很多日誌, 弊遠遠大於利, 也不利於維護;
3. binlog
管理員或 DBA 同樣可以解析 MySQL 的 binlog 來過濾表或許可權的變更. 這種方式本質上等同第二種方式, 線上資料庫需要開啟 binlog 選項, 解析 binlog 也是很耗資源的操作. 線上如果實例較多, 這種方式特別不可取.
4. 註冊 slave
註冊 slave 的意思即通過 MySQL 的主從協議偽造一個假的 slave, 這樣 master 會把所有的更新都發送過來, 再進行一些過濾的操作. 這種方式在同步數據或增量消費的場景特別適合, 這裡只用於記錄表或許可權的變更確實是大材小用, 線上實例較多的話也不可取. 典型的工具有 myreplication, tungsten-replicator 以及阿裡的 canal 等.
5. mysqldiff
實際上許可權和表變更本身是低頻率的操作事件, 上述的四種方式雖然都可以達到目標, 但本質上都是很耗費資源的操作. 考慮到這點, 我們可以通過對比的方式來實現許可權及表結構變更的跟蹤, 詳見 sys-mysql-diff 工具. 考慮到通用性, sys-mysql-diff 工具每次都需要獲取指定庫的所有表的定義語句, 通過對比來生成對應的 DDL 語句. mysqldiff 則是對 sys-mysql-diff 工具的封裝, 可以批量跟蹤多個實例.
如何使用 mysqldiff
mysqldiff 工具是在 sys-mysql-diff 工具的基礎上進行了一層封裝, 所以本質上是通過 sys-mysql-diff 工具跟蹤線上庫的變化. 在實際的運用中, 需要註意以下幾點:
1. 配置文件
mysqldiff 所需要的配置參考以下:
[backend] dsn = user_mysqlmon:xxxxxxxx@tcp(10.0.21.17:3306)/mysqldiff?charset=utf8 [test3301] host = 10.0.21.5 port = 3301 db = test user = user_mysqldiff pass = xxxxxxxx tag = host_location [test3306] host = 10.0.21.7 port = 3306 db = percona user = user_mysqldiff pass = xxxxxxxx tag = host_location
2. 許可權
所有的變更結果都會保存到指定的 MySQL 庫中的 mysql_diff 表, 即上述的 [backend]
部分, 對於該表需要 select, insert, update
相關的許可權. 被跟蹤的實例則是 [testXXXX]
部分, 由於需要查看表結構和用戶許可權所以需要 select 和 grant option 許可權. 我們以 user_mysqlmon 用戶為 [backend]
的用戶, 以 user_mysqldiff 為 [testXXXX]
部分的用戶為例, 需要賦予他們以下許可權:
grant select,insert,update on mysqldiff.* to user_mysqlmon@`10.0.21.%`; grant select on *.* to user_mysqldiff@`10.0.21.%` with grant option;
配置中的 db = information_schema 則表示跟蹤所有的資料庫;
3. 運行
運行 mysqldiff 命令進行跟蹤:
# ./mysqldiff -conf conf.cnf -verbose 2017/03/20 16:31:27 --------------------------- changes from 10.0.21.5:3301 changes from 10.0.21.7:3306 DROP TABLE `emp`; SET GLOBAL wait_timeout = 1000; 2017/03/20 16:31:27 insert 10.0.21.17:3306/percona ok 2017/03/20 16:31:27 ---------------------------
insert ... ok
一行表示將結果插入到了 [backend]
中.
總結
以 mysqldiff 方式跟蹤庫表及許可權的變化相對簡單方便, 比起其它方式算得上輕便. 另外也不受業務場景和管理員習慣的制約, 相對很通用. 不過其也有自身的缺陷, 在短時間內經常變更的表則很難跟蹤, mysqldiff 僅能記錄最後一次的變更. 另外管理員需要嚴格限制配置文件的許可權, 最好給予 0600 的許可權僅限當前用戶查看. 不過整體而言, 要跟蹤線上庫表許可權的變更, mysqldiff 是一個較為合適且通用的工具.