DM 分庫分表 DDL “悲觀協調” 模式介紹丨TiDB 工具分享

PingCAP發表於2021-12-24

背景

TiDB 作為分庫分表方案的一個 “終結者”,獲得了許多使用者的青睞。在切換到 TiDB 之後,使用者告別了分庫分表查詢和運維帶來的複雜度。但是在從分庫分表方案切換到 TiDB 的過程中,這個複雜度轉移到了資料遷移流程裡。TiDB DM 工具為使用者提供了分庫分表合併遷移功能,在資料遷移的過程中,支援將分表 DML 事件合併遷移,並一定程度支援上游分表進行 DDL 變更。

本文以及後續文章主要介紹分庫分表合併遷移時,各分表 DDL 變更的協調。DM 的分庫分表 DDL 協調可配置為 “悲觀協調” 和 “樂觀協調”,本文主要介紹 TiDB DM 分庫分表 DDL 協調的 “悲觀協調” 模式。後續文章會介紹 “樂觀協調” 模式。

分庫分表 DDL 的問題(簡略版)

本節首先以一個例子粗略介紹分庫分表 DDL 對資料遷移的影響,然後就這個問題給出更加正式的定義。

假設在兩個上游有兩個分表 t1、t2,下游表為 t

t1 接下來的同步事件是 INSERT (3,3),t2 接下來的同步事件是 DROP COLUMN c2。如果 DROP COLUMN c2 先被同步到下游,在同步到 INSERT (3,3) 時就會因為缺少 c2 列而報錯。因此我們要對 DDL 同步事件進行特殊處理。

分庫分表合併遷移的定義

接下來我們嘗試使用更正式一點的語言來描述這個問題,從而引出如何正確解決這個問題。

從使用者的角度來講,資料庫的用途主要的是查詢,在分庫分表合併前後,查詢的結果應該是相同的(不考慮 LIMIT 等運算元以及不確定性查詢)。也就是說,各分表查詢結果的並集應當等於遷移後的查詢結果。容易得到一個滿足此要求的充分條件:各分表資料的並集應當等於遷移後的表資料。考慮到同步延遲的影響,也就是當前時刻下游表的資料等於各分表在過去某時刻資料的並集。

對於這個定義而言,資料遷移就是讓各分表的同步時刻不斷向前推進。如果在同步某事件前,下游表與各分表滿足定義,那麼我們將一個分表的同步事件以相同影響的方式應用到下游,就將該分表的同步時刻正確地推進了。

分庫分表 DDL 的問題(正式版)

從上面的定義來看,DDL 會造成兩個方面的問題。

首先是 DDL 可能會變更表結構。參照之前的例子,如果 t1、t2 都有 DROP COLUMN c2 事件,DM 先同步到了 t2 的該事件,而同步事件需要以相同影響的方式應用到下游,我們應該只將下游 t2 對應的資料 DROP COLUMN。顯然下游 t1、t2 的資料共享一個表結構,無法完成這個操作。因此 t2 的該事件暫時不能被同步。

另一個問題是,部分 DDL 即使不影響表結構,也會產生對資料產生影響。例如 ALTER TABLE DROP COLUMN c, ADD COLUMN c DEFAULT xx,會將一個分表的 c 列全部修改為 xx。目前 DM 的實現同樣無法將這個事件以相同影響的方式應用到下游。

解決方法

對於上述 DDL 引入的問題並基於前文對於同步正確性的定義,我們可以得到一個滿足要求的充分條件:當某分表出現 DDL 同步事件時,我們將其同步暫停;直到所有分表都出現該 DDL 同步事件時,我們將 DDL 應用到下游並恢復所有分表的同步。此時我們可以保證下游表的 DDL 產生的影響等於所有分表都進行了 DDL(不考慮非確定性 DDL,例如 DDL 新增列預設值為 current_timestamp)。

悲觀協調例子

我們仍然以兩張表 t1、t2 的合併遷移為例,觀察 binlog 同步進度

左圖中,當分表 t1 遇到 DDL 時,t2 同步事件還沒有到這條 DDL,因此 t1 同步應當被暫停。當進展到右圖時,t1、t2 分表都出現了相同的 DDL,因此此時可以將這條 DDL 應用到下游並恢復 t1、t2 的同步。

在某些情況下,t1、t2 可能位於一個 binlog 流之中,因此上圖中看似獨立的流的暫停與恢復,實際實現為在同一個 binlog 流中跳過事件及回滾同步位置。

如上圖,我們需要在事件 1、2、4、5、6 之後同步事件 3,因此在 binlog 流中首次遇到事件 3 時跳過,並在事件 6 完成之後重新從事件 3 開始同步,並跳過已經同步的 4、5、6 事件。

悲觀協調模式限制

可以看到這種協調模式解決方法有如下的限制:

  • 出現 DDL 同步事件時分表會暫停,會導致同步延遲增加。這可能會導致恢復同步時,上游 binlog 已經被清理
  • 不支援只變更部分分表以進行灰度測試時的場景。灰度期間其餘分表的同步會暫停。此外如果灰度測試結果是回滾時,無法恢復同步
  • 要求所有分表以相同的順序出現 DDL 同步事件

    • 如果分表由於誤操作而進入 DDL 不一致的狀態,修復操作較為複雜
    • 對於 DM 的使用者而言,可能無法控制上游 DDL 的發起從而無法滿足條件

相關文章