TiDB Online DDL 在 TiCDC 中的應用丨TiDB 工具分享
引言
TiCDC 作為 TiDB 的資料同步元件,負責直接從 TiKV 感知資料變更同步到下游。其中比較核心的問題是資料解析正確性問題,具體而言就是如何使用正確的 schema 解析 TiKV 傳遞過來的 Key-Value 資料,從而還原成正確的 SQL 或者其他下游支援的形式。本文主要通過對 TiDB Online DDL 機制原理和實現的分析,引出對當前 TiCDC 資料解析實現的討論。
背景和問題
資料同步元件是資料庫生態中不可或缺的生態工具,比較知名的開源單機資料庫 MySQL 就將資料同步作為 Server 能力的一部分,並基於 MySQL binlog 實現非同步/半同步/同步的主從複製。由於 MySQL 悲觀事務模型和表後設資料鎖的存在,我們總是可以認為 MySQL binlog 中存在因果關係的 data 和 schema 符合時間先後順序的,即:
New data commitTs > New schema commitTs
但是對於 TiDB 這種儲存計算分離的架構而言,schema 的變更在儲存層持久化,服務層節點作為多快取節點,總是存在一個 schema 狀態不一致的時間段。為了保證資料一致性和實現線上 DDL 變更,現有的分散式資料庫大都採用或者借鑑了 Online, Asynchronous Schema Change in F1 機制。所以我們要回答的問題變成了,在 TiDB Online DDL 機制下,TiCDC 如何正確處理 data 和 schema 的對應關係,存在因果關係的 data 和 schema 是否仍然滿足:
New data commitTs > New schema commitTs
為了回答這個問題,我們首先需要先闡述原始的 F1 Online Schema Change 機制的核心原理,然後描述當前 TiDB Online DDL 實現,最後我們討論在當前 TiCDC 實現下,data 和 schema 的處理關係和可能出現的不同的異常場景。
F1 Online Schema Change 機制
F1 Online Schema Change 機制要解決的核心問題是,在單儲存多快取節點的架構下,如何實現滿足資料一致性的 Online Schema 變更,如圖 1 所示:
這裡我們定義資料不一致問題為資料多餘(orphan data anomaly)和資料缺失(integrity anomaly),Schema 變更結束後出現資料多餘和資料缺失我們就認為資料不一致了。這類系統的 schema 變更問題特點可以總結成以下 3 點:
-
一份 schema 儲存,多份 schema 快取
-
部分 new schema 和 old schema 無法共存
-
直接從 old schema 變更到 new schema 時,總是存在一個時間區間兩者同時存在
特點 1 和特點 3 是系統架構導致的,比較容易理解。特點 2 的一個典型例子是 add index,載入了 new schema 的服務層節點插入資料時會同時插入索引,而載入了 old schema 的服務層節點執行刪除操作只會刪除資料,導致出現了沒有指向的索引, 出現資料多餘。
Schema 變更問題的特點 2 和特點 3 看起來是互相矛盾的死結,new schema 和 old schema 無法共存,但又必然共存。而 F1 Online Schema 機制提供的解決方案也很巧妙,改變不了結果就改變條件。所以該論文的解決思路上主要有 2 點,如圖 2 所示:
1. 引入共存的中間 schema 狀態,比如 S1->S2’->S2, S1 和 S2’ 可以共存,S2’ 和 S2 可以共存;
2. 引入確定的隔離時間區間,保證無法共存的 schema 不會同時出現;
具體來講:
- 引入共存的中間 schema 狀態
因為直接從 schema S1 變更到 schema S2 會導致資料不一致的問題,所以引入了 delete-only 和 write-only 中間狀態,從 S1 -> S2 過程變成 S1 -> S2+delete-only -> S2+write-only -> S2 過程,同時使用 lease 機制保證同時最多有 2 個狀態共存。這時只需要證明 每相臨的兩個狀態都是可以共存的,保證資料一致性,就能推匯出 S1 到 S2 變更過程中資料是一致的。
- 引入確定的隔離時間區間
定義 schema lease,超過 lease 時長後節點需要重新載入 schema,載入時超過 lease 之後沒法獲取 new schema 的節點直接下線,不提供服務。所以可以明確定義 2 倍 lease 時間之後,所有節點都會更新到下一個的 schema。
引入共存的中間狀態
我們需要引入什麼樣的中間狀態呢?那要看我們需要解決什麼問題。這裡我們仍然使用 add index 這個 DDL 作為例子,其他 DDL 細節可以查閱 Online, Asynchronous Schema Change in F1 。
Delete-only 狀態
我們可以看到 old schema 是無法看到索引資訊的,所以會導致出現刪除資料,遺留沒有指向的索引這種資料多餘的異常場景,所以我們要引入的第一個中間狀態是 delete-only 狀態,賦予 schema 刪除索引的能力。在 delete-only 狀態下,schema 只能在 delete 操作的時候對索引進行刪除,在 insert/select 操作的時候無法操作索引,如圖 3 所示:
原始論文對於 delete-only 的定義如下:
假設我們已經引入了明確的隔離時間區間(下一個小節會細講),能保證同一時刻最多隻出現 2 個 schema 狀態。所以當我們引入 delete-only 狀態之後,需要考慮的場景就變成:
-
old schema + new schema(delete-only)
-
new schema(delete-only) + new schema
-
對於場景 1,所有的服務層節點要麼處於 old schema 狀態,要麼處於 new schema(delete-only) 狀態。由於 index 只能在 delete 的時候被操作,所以根本沒有 index 生成,就不會出現前面說的遺留沒有指向的索引問題,也不會有資料缺失問題,此時資料是一致的。我們可以說 old schema 和 new schema(delete-only) 是可以共存的。
-
對於場景 2,所有的服務層節點要麼處於 new schema(delete-only) 狀態,要麼處於 new schema 狀態。處於 new schema 狀態的節點可以正常插入刪除資料和索引,處於 new schema( delete-only) 狀態的節點只能插入資料,但是可以刪除資料和索引,此時存在部分資料缺少索引問題,資料是不一致的。
引入 delete-only 狀態之後,已經解決了之前提到的索引多餘的問題,但是可以發現,處於 new schema( delete-only) 狀態的節點只能插入資料,導致新插入的資料和存量歷史資料都缺少索引資訊,仍然存在資料缺失的資料不一致問題。
Write-only 狀態
在場景 2 中我們可以看到,對於 add index 這種場景,處於 new schema( delete-only) 狀態節點插入的資料和存量資料都存在索引缺失的問題。而存量資料本身數量是確定且有限的,總可以在有限的時間內根據資料生成索引,但是 new insert 的資料卻可能隨時間不斷增加。為了解決這個資料缺失的問題,我們還需要引入第二個中間狀態 write-only 狀態,賦予 schema insert/delete 索引的能力。處於 write-only 狀態的節點可以 insert/delete/update 索引,但是 select 無法看到索引,如圖 4 所示:
原始論文中對於 write-only 狀態的定義如下:
引入 write-only 狀態之後,上述的場景 2 被切分成了場景 2‘ 和場景 3:
2’: new schema(delete-only) + new schema(write-only)
3: new schema(write-only) + new schema
-
對於場景 2‘,所有的服務層節點要麼處於 new schema(delete-only) 狀態,要麼處於 new schema(write-only) 。處於 new schema(delete-only) 狀態的服務層節點只能插入資料,但是可以刪除資料和索引,處於 new schema(write-only) 可以正常插入和刪除資料和索引。此時仍然存在索引缺失的問題,但是由於 delete-only 和 write-only 狀態下,索引對於使用者都是不可見的,所以在使用者的視角上,只存在完整的資料,不存在任何索引,所以內部的索引缺失對使用者而言還是滿足資料一致性的。
-
對於場景 3,所有的服務層節點要麼處於 new schema(write-only) 狀態,要麼處於 new schema。此時 new insert 的資料都能正常維護索引,而存量歷史資料仍然存在缺失索引的問題。但是存量歷史資料是確定且有限的,我們只需要在所有節點過渡到 write-only 之後,進行歷史資料索引補全,再過渡到 new schema 狀態,就可以保證資料和索引都是完整的。此時處於 write-only 狀態的節點只能看到完整的資料,而 new schema 狀態的節點能看到完整的資料和索引,所以對於使用者而言資料都是一致的。
小節總結
通過上面對 delete-only 和 write-only 這兩個中間狀態的表述,我們可以看到,在 F1 Online DDL 流程中,原來的單步 schema 變更被兩個中間狀態分隔開了。每兩個狀態之間都是可以共存的,每次狀態變更都能保證資料一致性,全流程的資料變更也能保證資料一致性。
引入確定的隔離時間區間
為了保證同一時刻最多隻能存在 2 種狀態,需要約定服務層節點載入 schema 的行為:
-
所有的服務層節點在 lease 之後都需要重新載入 schema;
-
如果在 lease 時間內無法獲取 new schema,則下線拒絕服務;
通過對服務層節點載入行為的約定,我們可以得到一個確定的時間邊界,在 2*lease 的時間週期之後,所有正常工作的服務層節點都能從 schema state1 過渡到 schema state2, 如圖 5 所示:
中間狀態可見性
要正確理解原始論文的中間狀態,需要正確理解中間狀態的可見性問題。前面小節為了方便我們一直使用 add index 作為例子,然後表述 delete-only 和 write-only 狀態下索引對於使用者 select 是不可見的,但是 write-only 狀態下,delete/insert 都是可以操作索引的。如果 DDL 換成 add column,那節點處於 write-only 狀態時,使用者 insert 顯式指定新增列可以執行成功嗎?答案是不能。
總得來說,中間狀態的 delete/insert 可見性是內部可見性,具體而言是服務層節點對儲存層節點的可見性,而不是使用者可見性。對於 add column 這個 DDL,服務層節點在 delete-only 和 write-only 狀態下就能看到 new column,但是操作受到不同的限制。對使用者而言,只有到 new schema 狀態下才能看到 new column,才能顯式操作 new column,如圖 6 所示:
為了清晰表述可見性,我們舉個例子,如圖 7 所示。原始的表列資訊為 , DDL 操作之後表列資訊為 <c1,c2>。
-
小圖 (1) 中,服務層節點已經過渡到了場景 1,部分節點處於 old schema 狀態,部分節點處於 new schema(delete-only) 狀態。此時 c2 對使用者是不可見的,不管是 insert<c1,c2> 還是 delete<c1,c2> 的顯式指定 c2 都是失敗的。但是儲存層如果存在 [1,xxx] 這樣的資料是可以順利刪除的,只能插入 [7] 這樣的缺失 c2 的行資料。
-
小圖 (2) 中,服務層節點已經過渡到了場景 2,部分節點處於 new schema(delete-only) 狀態,部分節點處於 new schema(write-only) 狀態,此時 c2 對使用者仍是不可見的,不管是 insert<c1,c2> 還是 delete<c1,c2> 的顯式指定 c2 都是失敗的。但是處於 write-only 狀態的節點,insert [9] 在內部會被預設值填充成 [9,0] 插入儲存層。處於 delete-only 狀態的節點,delete [9] 會被轉成 delete [9,0]。
-
小圖 (3) 中,服務層所有節點都過渡到 write-only 之後,c2 對使用者仍是不可見的。此時開始進行資料填充,將歷史資料中缺失 c2 的行進行填充(實現時可能只是在表的列資訊中打上一個標記,取決於具體的實現)。
-
小圖 (4) 中,開始過渡到場景 3,部分節點處於 new schema(write-only) 狀態,部分節點處於 new schema 狀態。處於 new schema(write-only) 狀態的節點,c2 對使用者仍是不可見的。處於 new schema 狀態的節點,c2 對使用者可見。此時連線在不同服務層節點上的使用者,可以看到不同的的 select 結果,不過底層的資料是完整且一致的。
總結
上面我們通過 3 個小節對 F1 online Schema 機制進行了簡要描述。原來單步 schema 變更被拆解成了多箇中間變更流程,從而保證資料一致性的前提下實現了線上 DDL 變更。
對於 add index 或者 add column DDL 是上述的狀態變更,對於 drop index 或者 drop column 則是完全相反的過程。比如 drop column 在 write-only 階段及之後對使用者都不可見了,內部可以正確 insert/delete,可見性和之前的論述完全一樣。
TiDB Online DDL 實現
TiDB Online DDL 是基於 F1 Online Schema 實現的,整體流程如圖 8 所示:
簡單描述如下:
-
TiDB Server 節點收到 DDL 變更時,將 DDL SQL 包裝成 DDL job 提交到 TIKV job queue 中持久化;
-
TiDB Server 節點選舉出 Owner 角色,從 TiKV job queue 中獲取 DDL job,負責具體執行 DDL 的多階段變更;
-
DDL 的每個中間狀態(delete-only/write-only/write-reorg)都是一次事務提交,持久化到 TiKV job queue 中;
-
Schema 變更成功之後,DDL job state 會變更成 done/sync,表示 new schema 正式被使用者看到,其他 job state 比如 cancelled/rollback done 等表示 schema 變更失敗;
-
Schema state 的變更過程中使用了 etcd 的訂閱通知機制,加快 server 層各節點間 schema state 同步,縮短 2*lease 的變更時間。
-
DDL job 處於 done/sync 狀態之後,表示該 DDL 變更已經結束,移動到 job history queue 中;
詳細的 TiDB 處理流程可以參見: schema-change-implement.md 和 TiDB ddl.html
TiCDC 中 Data 和 Schema 處理關係
前面我們分別描述了 TiDB Online DDL 機制的原理和實現,現在我們可以回到最一開始我們提出的問題:在 TiDB Online DDL 機制下,是否還能滿足:
New data commitTs > New schema commitTs
答案是否定的。在前面 F1 Online Schema 機制的描述中,我們可以看到在 add column DDL 的場景下,當服務層節點處於 write-only 狀態時,節點已經能夠插入 new column data 了,但是此時 new column 還沒有處於使用者可見的狀態,也就是出現了 New data commitTs < New schema commitTs,或者說上述結論變成了:
New data commitTs > New schema(write-only) commitTs
但是由於在 delete-only + write-only 過渡狀態下,TiCDC 直接使用 New schema(write-only) 作為解析的 schema,可能導致 delete-only 節點 insert 的資料無法找到對應的 column 元資訊或者元資訊型別不匹配,導致資料丟失。所以為了保證資料正確解析,可能需要根據不同的 DDL 型別和具體的 TiDB 內部實現,在內部維護複雜的 schema 策略。
在當前 TiCDC 實現中,選擇了比較簡單的 schema 策略,直接忽略了各個中間狀態,只使用變更完成之後的 schema 狀態。為了更好表述在 TIDB Online DDL 機制下,當前 TiCDC 需要處理的不同場景,我們使用象限圖進行進一步歸類描述。
Old schema | New schema | |
---|---|---|
Old schema data | 1 | 2 |
New schema data | 3 | 4 |
-
1 對應 old schema 狀態
此時 old schema data 和 old schema 是對應的 *;*
-
4 對應 new schema public 及之後
此時 new schema data 和 new schema 是對應的;
-
3 對應 write-only ~ public 之間資料
此時 TiCDC 使用 old schema 解析資料,但是處於 write-only 狀態的 TiDB 節點已經可以基於 new schema insert/update/delete 部分資料,所以 TiCDC 會收到 new schema data。不同 DDL 處理效果不同,我們選取 3 個常見有代表性的 DDL 舉例。
- add column: 狀態變更 absent -> delete-only -> write-only -> write-reorg -> public。由於 new schema data 是 TiDB 節點在 write-only 狀態下填充的預設值,所以使用 old schema 解析後會被直接丟棄,下游執行 new schema DDL 的時候會再次填充預設值。對於動態生成的資料型別,比如 auto_increment 和 current timestamp,可能會導致上下游資料不一致。
- change column:有損狀態變更 absent -> delete-only -> write-only -> write-reorg -> public, 比如 int 轉 double,編碼方式不同需要資料重做。在 TiDB 實現中,有損 modify column 會生成不可見 new column,中間狀態下會同時變更新舊 column。對於 TiCDC 而言,只會處理 old column 下發,然後在下游執行 change column,這個和 TiDB 的處理邏輯保持一致。
- drop column:狀態變更 absent-> write-only -> delete-only -> delete-reorg -> public。write-only 狀態下新插入的資料已經沒有了對應的 column,TiCDC 會填充預設值然後下發到下游,下游執行 drop column 之後會丟棄掉該列。使用者可能看到預期外的預設值,但是資料能滿足最終一致性。
-
2 對應直接從 old schema -> new schema
說明這類 schema 變更下,old schema 和 new schema 是可以共存的,不需要中間狀態,比如 truncate table DDL。TiDB 執行 truncate table 成功後,服務層節點可能還沒有載入 new schema,還可以往表中插入資料,這些資料會被 TiCDC 直接根據 tableid 過濾掉,最終上下游都是沒有這個表存在的,滿足最終一致性。
總結
TiCDC 作為 TiDB 的資料同步元件,資料解析正確性問題是保證上下游資料一致性的核心問題。為了能充分理解 TiCDC 處理 data 和 schema 過程中遇到的各種異常場景,本文首先從 F1 Online Schema Change 原理出發,詳細描述在 schema 變更各個階段的資料行為,然後簡單描述了當前 TiDB Online DDL 的實現。最後引出在當前 TiCDC 實現下在 data 和 schema 處理關係上的討論。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69994146/viewspace-2862795/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- DM 分庫分表 DDL “悲觀協調” 模式介紹丨TiDB 工具分享模式TiDB
- DM 分庫分表 DDL “樂觀協調” 模式介紹丨TiDB 工具分享模式TiDB
- DM 是如何處理 DML 的丨TiDB 工具分享TiDB
- DM 中 relay log 效能優化實踐丨TiDB 工具分享優化TiDB
- TiDB 在小米的應用實踐TiDB
- TiDB 在量化派風控系統中的應用TiDB
- 備份的 “運算元下推”:BR 簡介丨TiDB 工具分享TiDB
- HTAP 還可以這麼玩?丨TiDB 在 IoT 智慧園區的應用TiDB
- TiDB 7.1 多租戶在中泰證券中的應用TiDB
- TiDB應用實踐TiDB
- TiDB 6.0:讓 TSO 更高效丨TiDB Book RushTiDB
- TiDB 在 Mobikok 廣告系統中的應用和實踐TiDB
- TiDB 在連鎖快餐企業丨海量交易與實時分析的應用探索TiDB
- TiDB 在餓了麼歸檔環境的應用TiDB
- 使用 TiDB Vector 搭建 RAG 應用 - TiDB 文件問答小助手TiDB
- TiDB 在摩拜單車的深度實踐及應用TiDB
- TiDB v6.0.0 (DMR) :快取表初試丨TiDB Book RushTiDB快取
- TiDB 在醫療保障資訊平臺的應用實踐TiDB
- TiDB x 漢口銀行丨分散式資料庫應用實踐TiDB分散式資料庫
- TiDB 分散式資料庫在轉轉公司的應用實踐TiDB分散式資料庫
- TiDB 5.4 發版丨新功能解讀TiDB
- TiDB 在特來電的實踐TiDB
- TiDB 在威銳達 WindRDS 遠端診斷及運維中心的應用TiDB運維
- TiDB在科捷物流神州金庫核心系統的應用與實踐TiDB
- tidb拓撲查詢工具qtidbTiDBQT
- 讓 TiDB 訪問多種資料來源 | TiDB Hackathon 優秀專案分享TiDB
- TiDB 在全球頭部物流企業計費管理系統的應用實踐TiDB
- TiDB 6.0 新特性解讀丨 Collation 規則TiDB
- TiDB 在轉轉的業務實戰TiDB
- TiDB HTAP 上手指南丨新增 TiFlash 副本的工作原理TiDB
- 這門面嚮應用開發者的 TiDB 使用教程,TiDB SQL、Connector API…你一定不能錯過!TiDBSQLAPI
- TiDB、TiDB Cloud 均已正式登陸 AWS Marketplace。TiDBCloud
- MySQL Online DDL詳解MySql
- TiDB x 阿里雲丨最長 30 天,最高節省 ¥33,000,免費試用雲資料庫 TiDB 的機會來啦!TiDB阿里資料庫
- Explore the Sky丨來 TiDB Hackathon 2021 探索無限可能TiDB
- MySQL DDL執行方式-Online DDL介紹MySql
- 吳鏑:TiDB 在今日頭條的實踐TiDB
- TiDB在轉轉公司的發展歷程TiDB