DM 原始碼閱讀系列文章(七)定製化資料同步功能的實現
作者:王相
本文為 DM 原始碼閱讀系列文章的第七篇,在 上篇文章 中我們介紹了 relay log 的實現,主要包括 relay log 目錄結構定義、relay log 資料的處理流程、主從切換支援、relay log 的讀取等邏輯。本篇文章我們將會對 DM 的定製化資料同步功能進行詳細的講解。
在一般的資料同步中,上下游的資料是一一對應的,即上下游的庫名、表名、列名以及每一列的值都是相同的,但是很多使用者因為業務的原因希望 DM 在同步資料到 TiDB 時進行一些定製化的轉化。下面我們將主要介紹資料同步定製化中的庫表路由(Table routing)、黑白名單(Black & white table lists)、列值轉化(Column mapping)、binlog 過濾(Binlog event filter)四個主要功能的實現。值得注意的是,由於其他一些工具(例如 TiDB Lightning 和 TiDB Binlog)也需要類似的功能,所以這四個功能都以 package 的形式維護在
庫表路由(Table routing)
庫表路由顧名思義就是對庫名和表名根據一定的路由規則進行轉換。比如使用者在上游多個 MySQL 例項或者 schema 有多個邏輯上相同的表,需要把這些表的資料同步到 TiDB 叢集的同一個表中,這個時候就可以使用 table-router 功能,如下圖所示:
該功能實現在 pkg/table-router
中,庫表路由的規則定義在結構 TableRule
中,其中的屬性 SchemaPattern
和 TablePattern
用於配置原庫名和表名的模式,TargetSchema
和 TargetTable
使用結構 Table 對路由規則進行維護,Table 提供瞭如下方法:
方法 | 說明 |
---|---|
AddRule | 增加規則 |
UpdateRule | 修改規則 |
RemoveRule | 刪除規則 |
Route | 獲取路由後的結果 |
Table 結構中組合了 Selector
,Selector
用於管理指定模式的庫、表的規則,提供如下方法:
方法 | 說明 |
---|---|
Insert | 增加規則 |
Match | 查詢指定的庫、表匹配到的規則 |
Remove | 刪除規則 |
AllRules | 返回所有的規則 |
Selector 的底層實現是 trieSelector
黑白名單(black & white table lists)
黑白名單功能用來選擇同步哪些庫和表,以及不同步哪些庫和表,這部分程式碼維護在 pkg/filter
中。
黑白名單規則配置在 Rules
結構中,該結構包括 DoTables
、DoDBs
、IgnoreTables
和 IgnoreDBs
四個屬性,下面以判斷表 test.t
是否應該被過濾的例子說明配置的作用:
-
首先 schema 過濾判斷。
- 如果
do-dbs
不為空,則判斷do-dbs
中是否存在一個匹配的 schema。- 如果存在,則進入 table 過濾判斷。
- 如果不存在,則過濾
test.t
。
- 如果
do-dbs
為空並且ignore-dbs
不為空,則判斷ignore-dbs
中是否存在一個匹配的 schema。- 如果存在,則過濾
test.t
。 - 如果不存在,則進入 table 過濾判斷。
- 如果存在,則過濾
- 如果
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 中哪些表可以同步。
列值轉化(Column mapping)
列值轉化功能用於對指定列的值做一些轉化,主要用於分庫分表的同步場景。比較典型的場景是:在上游分表中使用自增列作為主鍵,這樣資料在同步到 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 event filter)
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/
相關推薦
DM 原始碼閱讀系列文章(七)定製化資料同步功能的實現
作者:王相 本文為 DM 原始碼閱讀系列文章的第七篇,在 上篇文章 中我們介紹了 relay log 的實現,主要包括 relay
DM 原始碼閱讀系列文章(八)Online Schema Change 同步支援
作者:lan 本文為 DM 原始碼閱讀系列文章的第八篇,上篇文章 對 DM 中的定製化資料同步功能進行詳細的講解,包括庫表路由(T
DM 原始碼閱讀系列文章(九)shard DDL 與 checkpoint 機制的實現
作者:張學程 本文為 DM 原始碼閱讀系列文章的第九篇,在 上篇文章 中我們詳細介紹了 DM 對 online schema ch
DM 原始碼閱讀系列文章(十)測試框架的實現
作者:楊非 本文為 DM 原始碼閱讀系列文章的第十篇,之前的文章已經詳細介紹過 DM 資料同步各元件的實現原理和程式碼解析,相信大
TiDB 原始碼閱讀系列文章(二)初識 TiDB 原始碼
本文為 TiDB 原始碼閱讀系列文章的第二篇,第一篇文章介紹了 TiDB 整體的架構,知道 TiDB 有哪些模組,分別是做什麼的,從哪裡入手比較好,哪些可以忽略,哪些需要仔細閱讀。 這篇文章是一篇入門文件,難度係數比較低,其中部分內容可能大家在其他渠道已經看過
TiKV 原始碼解析系列文章(七)gRPC Server 的初始化和啟動流程
作者:屈鵬 本篇 TiKV 原始碼解析將為大家介紹 TiKV 的另一週邊元件—— grpc-rs。grpc-rs 是 PingCA
TiDB Binlog 原始碼閱讀系列文章(四)Pump server 介紹
作者: satoru 在 上篇文章 中,我們介紹了 TiDB 如何通過 Pump client 將 binlog 發往 Pump,
TiDB 原始碼閱讀系列文章(二十)Table Partition
作者:肖亮亮 Table Partition 什麼是 Table Partition Table Partition 是指根據一定規則,將資料庫中的一張表分解成多個更小的容易管理的部分。從邏輯上看只有一張表,但是底層卻是由多個物理分割槽組成。相信對有關係型資料庫使用背景的使用者來
TiDB 原始碼閱讀系列文章(十九)tikv-client(下)
上篇文章 中,我們介紹了資料讀寫過程中 tikv-client 需要解決的幾個具體問題,本文將繼續介紹 tikv-client 裡的兩個主要的模組——負責處理分散式計算的 copIterator 和執行二階段提交的 twoPhaseCommitter。 copIterator cop
TiDB 原始碼閱讀系列文章(二十一)基於規則的優化 II
在 TiDB 原始碼閱讀系列文章(七)基於規則的優化 一文中,我們介紹了幾種 TiDB 中的邏輯優化規則,包括列剪裁,最大最小消除,投影消除,謂詞下推和構建節點屬性,本篇將繼續介紹更多的優化規則:聚合消除、外連線消除和子查詢優化。 聚合消除 聚合消除會檢查 SQL 查詢中 Group By 語句所使用的列是否
TiKV 原始碼解析系列文章(三)Prometheus(上)
開發十年,就只剩下這套架構體系了! >>>
讀logback原始碼系列文章(四)——記錄日誌
今天晚上本來想來寫一下Logger怎麼記錄日誌,以及Appender元件。不過9點才從丈母孃家回來,又被幾個兄弟喊去喝酒,結果回來晚了,所以時間就只夠寫一篇Logger類的原始碼分析了。Appender找時間再寫 上篇部落格介紹了LoggerContext怎麼生成Logger
讀logback原始碼系列文章(八)——記錄日誌的實際工作類Encoder
本系列的部落格從logback怎麼對接slf4j開始,逐步介紹了LoggerContext、Logger、ContextInitializer、Appender、Action等核心元件。跟讀logback的原始碼到這個程度,雖然不能說精通,不過至少日常的配置,和簡單的自定義擴
TiKV 原始碼解析系列文章(十一)Storage
作者:張金鵬 背景知識 TiKV 是一個強一致的支援事務的分散式 KV 儲存。TiKV 通過 raft 來保證多副本之間的強一致,
Java系列文章(全)
java 學習JVMJVM系列:類裝載器的體系結構 JVM系列:Class文件檢驗器JVM系列:安全管理器JVM系列:策略文件Java垃圾回收機制深入剖析Classloader(一)--類的主動使用與被動使用深入剖析Classloader(二)-根類加載器,擴展類加載器與系統類加載器深入理解JVM—JVM內存
openstack系列文章(四)
cnblogs 調度器 5.5 min 代碼位置 虛機 inux latest 階段 學習 openstack 的系列文章 - Nova Nova 基本概念 Nova 架構 openstack Log Nova 組件介紹 Nova 操作介紹 1. Nova 基本概念
SVM支援向量機系列理論(七) 線性支援向量機與L2正則化 Platt模型
7.1 軟間隔SVM等價於最小化L2正則的合頁損失 上一篇 說到, ξi ξ i \xi_i 表示偏離邊界的度量,若樣本點
Spring Boot乾貨系列:(七)預設日誌logback配置解析
前言 今天來介紹下Spring Boot如何配置日誌logback,我剛學習的時候,是帶著下面幾個問題來查資料的 如何引入日誌? 日誌輸出格式以及輸出方式如何配置? 程式碼中如何使用? 正文 Spring Boot在所有
Git 系列文章(一)——GitHub 介紹
正文之前 相信大部分都人都知道 GitHub,對,就是被微軟收購的全球最大交友網站。目前博主還處於學生階段,所以一直處於這樣的迴圈中: git add git commit git pull git push 但是本著要深入學習的心態,以及目前參加掘金翻譯
Git 系列文章(二)—— Git 基本用法
正文之前 上一篇文章簡單介紹了 Git 和 GitHub,這一篇文章用一個倉庫來作為例子介紹 Git 的基本用法,而不是單純地列出每一條 Git 命令 這篇文章來自我的部落格 正文 1. 倉庫的初始操作 初始化 首先我先在本地存放 GitHub 倉庫的資料夾