做者:王相git
本文爲 DM 源碼閱讀系列文章的第七篇,在 上篇文章 中咱們介紹了 relay log 的實現,主要包括 relay log 目錄結構定義、relay log 數據的處理流程、主從切換支持、relay log 的讀取等邏輯。本篇文章咱們將會對 DM 的定製化數據同步功能進行詳細的講解。github
在通常的數據同步中,上下游的數據是一一對應的,即上下游的庫名、表名、列名以及每一列的值都是相同的,可是不少用戶由於業務的緣由但願 DM 在同步數據到 TiDB 時進行一些定製化的轉化。下面咱們將主要介紹數據同步定製化中的庫表路由(Table routing)、黑白名單(Black & white table lists)、列值轉化(Column mapping)、binlog 過濾(Binlog event filter)四個主要功能的實現。值得注意的是,因爲其餘一些工具(例如 TiDB Lightning 和 TiDB Binlog)也須要相似的功能,因此這四個功能都以 package 的形式維護在 tidb-tools 項目下,這樣方便使用和維護。正則表達式
庫表路由顧名思義就是對庫名和表名根據必定的路由規則進行轉換。好比用戶在上游多個 MySQL 實例或者 schema 有多個邏輯上相同的表,須要把這些表的數據同步到 TiDB 集羣的同一個表中,這個時候就可使用 table-router 功能,以下圖所示:sql
該功能實如今 pkg/table-router
中,庫表路由的規則定義在結構 TableRule
中,其中的屬性 SchemaPattern
和 TablePattern
用於配置原庫名和表名的模式,TargetSchema
和 TargetTable
用於配置目標庫和表名,即符合指定 pattern 的庫和表名都將轉化成目標庫名和表名。數據庫
使用結構 Table 對路由規則進行維護,Table 提供了以下方法:緩存
方法 | 說明 |
---|---|
AddRule |
增長規則 |
UpdateRule |
修改規則 |
RemoveRule |
刪除規則 |
Route |
獲取路由後的結果 |
Table 結構中組合了 Selector
,Selector
用於管理指定模式的庫、表的規則,提供以下方法:app
方法 | 說明 |
---|---|
Insert |
增長規則 |
Match |
查找指定的庫、表匹配到的規則 |
Remove |
刪除規則 |
AllRules |
返回全部的規則 |
Selector 的底層實現是 trieSelector
,使用了單詞查找樹的結構來維護庫、表與規則的對應關係,感興趣的同窗能夠閱讀代碼深刻了解一下。 trieSelector 中使用 cache 緩存了庫、表到規則的映射關係,這樣能夠減小相同庫、表匹配規則的資源消耗。除了 table routing,如下的列值轉化和 binlog 過濾功能也都使用了 Selector,在下面的介紹中就再也不贅述。工具
黑白名單功能用來選擇同步哪些庫和表,以及不一樣步哪些庫和表,這部分代碼維護在 pkg/filter
中。優化
黑白名單規則配置在 Rules
結構中,該結構包括 DoTables
、DoDBs
、IgnoreTables
和 IgnoreDBs
四個屬性,下面以判斷表 test.t
是否應該被過濾的例子說明配置的做用:code
首先 schema 過濾判斷。
do-dbs
不爲空,則判斷 do-dbs
中是否存在一個匹配的 schema。
test.t
。do-dbs
爲空而且 ignore-dbs
不爲空,則判斷 ignore-dbs
中是否存在一個匹配的 schema。
test.t
。do-dbs
和 ignore-dbs
都爲空,則進入 table 過濾判斷。進行 table 過濾判斷。
do-tables
不爲空,則判斷 do-tables
中是否存在一個匹配的 table。
test.t
。test.t
。ignore-tables
不爲空,則判斷 ignore-tables
中是否存在一個匹配的 table。
test.t
。test.t
。do-tables
和 ignore-tables
都爲空,則同步 test.t
。使用 Filter 對黑白名單進行管理,Filter 提供了 ApplyOn
方法來判斷一組 table 中哪些表能夠同步。
列值轉化功能用於對指定列的值作一些轉化,主要用於分庫分表的同步場景。比較典型的場景是:在上游分表中使用自增列做爲主鍵,這樣數據在同步到 TiDB 的一個表時會出現主鍵衝突,所以咱們須要根據必定規則對主鍵作轉化,保證每一個主鍵在全局仍然是惟一的。
該功能實如今 pkg/column-mapping
中的 PartitionID
:修改列的值的最高几位爲 PartitionID
的值(只能做用於 Int64 類型的列)。
代碼中使用 Rule 來設置 column mapping 的規則,Rule 的屬性及說明以下表所示:
屬性 | 說明 | 值 |
---|---|---|
PatternSchema |
匹配規則的庫的模式 | 能夠設置爲指定的庫名,也可使用通配符 「*」 和 「?」 |
PatternTable |
匹配規則的表的模式 | 能夠設置爲指定的表名,也可使用通配符 「*」 和 「?」 |
SourceColumn |
須要轉化的列 | 列名 |
TargetColumn |
轉化後的值保存到哪一個列 | 列名 |
Expression |
轉化表達式 | 目前只支持 PartitionID |
Arguments |
轉化所須要的參數 | Expression 爲 PartitionID ,參數爲 InstanceID 、schema 名稱前綴、table 名稱前綴以及前綴與 ID 的分割符號 |
Expression 爲 PartitionID
的配置和轉化的計算方式都較爲複雜,下面舉個例子說明。
例如 Arguments 爲 [1, 「test」, 「t」, 「_」]
,1
表示數據庫實例的 InstanceID
,「test」
爲庫名稱的前綴,「t」
爲表名稱的前綴,「_」
爲前綴與 ID 的分隔符,則表 test_1.t_2
的 SchemaID
爲 1
,TableID
爲 2
。轉化列值時須要對 InstanceID
、SchemaID
、TableID
進行必定的位移計算,而後與原始的值進行或運算得出一個新的值。對於具體的計算方式,能夠查看代碼 partitionID
和 computePartitionID
。下面是一個 PartitionID
邏輯簡化後的示意圖:
使用 Mapping 結構對 column mapping 的規則進行管理,Mapping 提供列以下方法:
方法 | 說明 |
---|---|
AddRole |
增長規則 |
UpdateRule |
修改規則 |
RemoveRule |
刪除規則 |
HandleRowValue |
獲取轉化結果 |
binlog 過濾功能支持過濾指定類型的 binlog,或者指定模式的 query,該功能維護在 pkg/binlog-filter 中。某些用戶不但願同步一些指定類型的 binlog,例如 drop table 和 truncate table,這樣就能夠在下游仍然保存這些表的數據做爲備份,或者某些 SQL 語句在 TiDB 中不兼容,但願能夠在同步中過濾掉,均可以經過配置 binlog event filter 功能來實現。
首先須要對 binlog 進行分類,能夠查看代碼 Event Type List
。而後再定義過濾規則 BinlogEventRule
,包括如下屬性:
屬性 | 說明 | 值 |
---|---|---|
SchemaPattern |
匹配規則的庫的模式 | 能夠設置爲指定的庫名,也可使用通配符 「*」 和 「?」 |
TablePattern |
匹配規則的表的模式 | 能夠設置爲指定的表名,也可使用通配符 「*」 和 「?」 |
Events |
規則適用於哪些類型的 binlog | binlog event 的類型 |
SQLPattern |
匹配的 SQL 的模式 | SQL 語句的模式,支持適用正則表達式 |
Action |
是否對符合上面要求的 binlog 進行過濾 | Ignore 或者 Do |
例如,TiDB 對 ADD PARTITION
和 DROP PARTITION
語句不兼容,在同步時須要過濾掉相關的 SQL 語句,就能夠在 DM 中使用以下配置:
filter-partition-rule: schema-pattern: "*" sql-pattern: ["ALTER\\s+TABLE[\\s\\S]*ADD\\s+PARTITION", "ALTER\\s+TABLE[\\s\\S]*DROP\\s+PARTITION"] action: Ignore
若是須要過濾掉全部的 DROP DATABASE
語句,則能夠在 DM 中使用以下配置:
filter-schema-rule: schema-pattern: "*" events: ["drop database"] action: Ignore
代碼中經過 BinlogEvent
結構對 binlog event 過濾規則作統一的管理,BinlogEvent
提供了以下的方法:
方法 | 說明 |
---|---|
AddRule |
增長規則 |
UpdateRule |
修改規則 |
RemoveRule |
刪除規則 |
Filter |
判斷指定的 binlog 是否應該過濾 |
以上就是定製化數據同步功能中庫表路由(Table routing)、黑白名單(Black & white table lists)、列值轉化(Column mapping)、binlog 過濾(Binlog event filter)的實現介紹。歡迎你們閱讀相關代碼深刻了解,也歡迎給咱們提 pr 優化代碼。下一篇咱們將介紹 DM 是如何支持上游 online DDL 工具(pt-osc,gh-ost)的 DDL 同步場景的。
原文閱讀:https://www.pingcap.com/blog-cn/dm-source-code-reading-7/