<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          TiDB 原理 | TiDB 數(shù)據(jù)一致性校驗實現(xiàn):Sync-diff-inspector 優(yōu)化方案

          共 4580字,需瀏覽 10分鐘

           ·

          2021-11-30 01:57

          作者介紹

          廖堅鈞,PingCAP Data Platform 研發(fā)工程師,專注于數(shù)據(jù)庫架構(gòu)和生態(tài)工具方向。
          張文珺,華中科技大學研究生,database enthusiast,rust learner。


          簡介

          在數(shù)據(jù)同步的場景下,上下游數(shù)據(jù)的一致性校驗是非常重要的一個環(huán)節(jié),缺少數(shù)據(jù)校驗,可能會對商業(yè)決策產(chǎn)生非常負面的影響。Sync-diff-inspector 是 PingCAP Data Platform 團隊開發(fā)的一款一致性校驗工具,它能對多種數(shù)據(jù)同步場景的上下游數(shù)據(jù)進行一致性校驗,如多數(shù)據(jù)源到單一目的(MySQL 中分庫分表到 TiDB 中)、單一源到單一目的( TiDB 表到 TiDB 表)等,在數(shù)據(jù)校驗過程中,其效率和正確性是至關(guān)重要的。首先我們看下 Sync-diff-inspector 的架構(gòu)圖,對 Sync-diff-inspector 的作用和實現(xiàn)原理有一個大致的認知。


          Sync-diff-inspector 2.0 架構(gòu)圖


          Why Sync-diff-inspector 2.0 ?

          在 1.0 版本中,我們遇到客戶反饋的一些問題,包括:

          • 針對大表進行一致性校驗時出現(xiàn) TiDB 端發(fā)生內(nèi)存溢出。

          • 不支持 Float 類型數(shù)據(jù)校驗的問題。

          • 結(jié)果輸出對用戶不友好,需要對校驗結(jié)果進行精簡。

          • 檢驗過程中發(fā)生 GC,導(dǎo)致校驗失敗。


          造成以上問題的原因與原版的實現(xiàn)方式有關(guān):
          • 采用單線程劃分 Chunk,該表中所有已被劃分的 Chunk 需要等待該表中所有 Chunk 全部被劃分才會開始進行比對,這會導(dǎo)致這段時間內(nèi),TiKV 的使用率降低

          • Checkpoint 功能將校驗過的每個 Chunk 的狀態(tài)寫入數(shù)據(jù)庫,所以寫入數(shù)據(jù)庫的 IO 成為校驗過程的瓶頸。

          • 當 chunk 范圍內(nèi)的 checksum 不同時,直接進行按行比對,消耗大量 IO 資源。

          • 缺少自適應(yīng) GC 的功能,導(dǎo)致正在校驗的 Snapshot 被 GC,使得校驗失敗

          ??????

          Sync-diff-inspector 2.0 新特性

          Chunk 劃分

          對于比較兩個表數(shù)據(jù)是否相同,可以通過分別計算兩個表的 checksum 來判斷,但是確定哪一行出現(xiàn)了不同則需要逐行比對。為了縮小 checksum 不一致時需要進行逐行比對的行數(shù), Sync-diff-inspector 采用了折衷的方案:將表按照索引的順序劃分成若干塊(chunk),再對每個 chunk 進行上下游數(shù)據(jù)比對。

          chunk 的劃分沿用了之前的方法。TiDB 統(tǒng)計信息會以索引作為范圍將表劃分為若干個桶,再對這些桶根據(jù) chunk 的大小進行合并或切分。切分過程則選擇隨機行作為范圍。

          原版 Sync-diff-inspector 采用單線程劃分 chunk,已被劃分的 chunk 需要等待該表劃分完所有 chunk 才會開始比對,這里采用異步劃分 chunk 的方法來提高這段時間的資源利用率。這里有兩種降低資源利用的情況:


          1. chunk 劃分過程中可能由于 chunk 的預(yù)定大小小于一個桶的大小,需要切分這個桶為若干個 chunk,這是個相對比較慢的過程,因此消費端也就是 chunk 的比對線程會出現(xiàn)等待的情況,資源利用率會降低。這里采用兩種處理方法:采用多個桶異步劃分來提高資源利用率;有些表沒有桶的信息,因此只能把整個表當作一個桶來切分,采用多表劃分來提高總體的異步劃分桶數(shù)。


          2. chunk 的劃分也會占用一定的資源,chunk 劃分過快會一定程度減慢 chunk 比對的速度,因此這里在消費端通過 channel 來限制多表劃分chunk的速度。


          總結(jié)來說,優(yōu)化后的 Sync-diff-inspector 對 chunk 的劃分由三部分組成。如下圖所示,這里指定存在 3 個 chunk_iter,每個 chunk_iter 劃分一個表,這里通過全局的 channel 調(diào)整 chunks_iter 劃分的進度。注意這里只按表限流,每個 chunk_iter 開始劃分時,會異步劃分所有 chunk,當全局的 channel 的 buffer 滿了,chunk_iter 會阻塞。當 chunk_iter 的所有 chunk 都進入全局 channel 的 buffer 后,該 chunk_iter 會開始劃分下一個表。


          Checkpoint 和修復(fù) SQL

          Sync-diff-inspector 支持在斷點處繼續(xù)進行校驗的功能。Diff 進程每十秒鐘會記錄一次斷點信息,當校驗程序在某個時刻發(fā)生異常退出的時候,再次運行 Sync-diff-inspector 會從最近保存的斷點處繼續(xù)進行校驗。如果在下一次運行時,Sync-diff-inspector 的配置文件發(fā)生改變,那么 Sync-diff-inspector 會拋棄斷點信息,重新進行校驗。

          該功能的完整性和正確性依賴于在 Chunk 劃分過程中定義的全局有序性和連續(xù)性。相比于原版,Sync-diff-inspector 2.0 實現(xiàn)的 checkpoint 不需要記錄每個 chunk 的狀態(tài),只需要記錄連續(xù)的、最近校驗完成的 chunk 的狀態(tài),大大減少了需要記錄的數(shù)據(jù)量。chunk 的全局有序特性由一個結(jié)構(gòu)體組成,結(jié)構(gòu)體包含了該 chunk 屬于第幾個表,屬于該表的第幾個桶到第幾個桶(如果該 chunk 由兩個或多個桶合并而成,則記錄桶的首末),這個桶被切分成多少個 chunk,這個 chunk 是切分后的 chunk 的第幾個。同時這種特性也可以判斷兩個 chunk 是不是連續(xù)的。每次斷點時鐘觸發(fā)時,會選擇已完成比對的連續(xù)的 chunk 的最后一個 chunk 作為檢查點,寫入該 chunk 的信息到本地文件。

          當校驗出不同行時,Sync-diff-inspector 會生成修復(fù) SQL 并保存在本地文件中。因為檢驗的 chunk 是亂序且并行的,所以這里為每個 chunk 創(chuàng)建(若該 chunk 存在不同行)一個文件來保存修復(fù) SQL,文件名是該 chunk 的全局有序的結(jié)構(gòu)體。修復(fù) SQL 和 checkpoint 的記錄肯定存在先后順序:

          1. 如果先寫入修復(fù) SQL 的記錄,那么此時程序異常退出,這個被寫入修復(fù) SQL 但沒被 checkpoint 記錄的 chunk 會在下一次生成,一般情況下,這個修復(fù) SQL 文件會被重新覆蓋。但是由于桶的切分是隨機分的,因此盡管切分后的 chunk 個數(shù)固定,上一次檢查出的不同行在切分后 chunks 的第三個,這次可能跑到了第四個chunk 的范圍內(nèi)。這樣就會存在重復(fù)的修復(fù) SQL。


          2. 如果先寫入 checkpoint,那么此時程序異常退出,下一次執(zhí)行會從該 checkpoint 記錄的 chunk 的后面范圍開始檢驗,如果該 chunk 存在修復(fù) SQL 但還沒有被記錄,那么這個修復(fù) SQL 信息就丟失了。


          這里采用了先寫入修復(fù) SQL 記錄,下一次執(zhí)行時會將排在 checkpoint 記錄的 chunk 后的所有修復(fù) SQL 文件(文件是以該 chunk 的全局有序結(jié)構(gòu)體命名,因此可以很容易判斷兩個 chunk 的先后順序)都移到 trash 文件夾中,以此避免出現(xiàn)重復(fù)的修復(fù) SQL

          二分校驗和自適應(yīng) chunkSize

          大表做 checksum 和切分成 chunks 做 checksum 的性能損耗在于每次做 checksum 都會有一些額外消耗(包括一次會話建立傳輸?shù)臅r間),如果把 chunk 劃分的很小,那么這些額外消耗在一次 checksum 花費的時間占比會變大。通常需要把 chunk 的預(yù)定大小 chunkSize 設(shè)置大一些,但是 chunkSize 設(shè)置的過大,當上下游數(shù)據(jù)庫對 chunk 做 checksum 的結(jié)果不同時,如果對這個大 chunk 直接進行按行對比,那么開銷也會變得很大。

          在數(shù)據(jù)同步過程中,一般只會出現(xiàn)少量的數(shù)據(jù)不一致,基于這個假定,當校驗過程中,發(fā)現(xiàn)某個 chunk 的上下游的 checksum 不一致,可以通過二分法將原來的 chunk 劃分成大小接近的兩個子 chunk,對子 chunk 進行 checksum 對比,進一步縮小不一致行的可能范圍。這個優(yōu)化的好處在于,checksum 對比所消耗的時間和內(nèi)存資源遠小于逐行進行數(shù)據(jù)比對的消耗,通過 checksum 對比不斷的縮小不一致行的可能范圍,可以減少需要進行逐行對比的數(shù)據(jù)行,加快對比速度,減少內(nèi)存損耗。并且由于每次計算 checksum 都相當于遍歷一次二分后的子 chunk,理論上不考慮多次額外消耗,二分檢驗的開銷相當于只對原 chunk 多做兩次 checksum。

          由于做一次 checksum 相當于遍歷范圍內(nèi)的所有行,可以在這個過程中順便計算這段范圍的行數(shù)。這樣做是因為 checksum 的原理是對一行的數(shù)據(jù)進行 crc32 運算,再對每一行的結(jié)果計算異或和,這種 checksum 的無法校驗出三行重復(fù)的錯誤,在索引列不是 unique 屬性的情況下是存在這種錯誤的。同時計算出每個 chunk 的行數(shù),可以使用 limit 語法定位到該 chunk 的中間一行數(shù)據(jù)的索引,這是二分方法使用的前提。

          但是 chunkSize 也不能設(shè)定的過大,當一次二分后兩邊的子 chunk 都存在不同行,那么會停止二分,進行行比對。過大的 chunk 就更有可能同時包含多個不同行,二分校驗的作用也會減小。這里設(shè)置每張表默認的 chunkSize 為 50000 行,每張表最多劃分出 10000 個 chunk。

          索引處理

          上下游數(shù)據(jù)庫的表可能會出現(xiàn) schema 不同,例如下游表只擁有一部分上游的索引。不恰當?shù)乃饕倪x擇會造成一方數(shù)據(jù)庫耗時加大。在做表結(jié)構(gòu)校驗時,只保留上下游都有的索引(若不存在這種索引,則保留所有索引)。另一方面,某些索引包含的列并不是 unique 屬性的,可能會有大量的行擁有相同的索引值,這樣 chunk 會劃分的不均勻。Sync-diff-inspector 在選擇索引時,會優(yōu)先選擇 primary key 或者 unique 的索引,其次是選擇重復(fù)率最低的索引。

          where 處理

          假設(shè)存在一張表 create table t (a int, b int, c int, primary key (a, b, c));

          并且一個劃分后的 chunk 范圍是 ((1, 2, 3),? (1, 2, 4)]

          原版 Sync-diff-inspector 會生成 where 語句:
          • ((a > 1) OR (a = 1 AND b > 2) OR (a = 1 AND b = 2 AND c > 3))

          • ((a < 1) OR (a = 1 AND b < 2) OR (a = 1 AND b = 2 AND c <= 4))


          可以優(yōu)化為 (a = 1) AND (b = 2) AND ((c > 3) AND (c <= 4))

          自適應(yīng) GC

          在原版 Sync-diff-inspector 中,校驗過程中可能會出現(xiàn)大量表被 GC 導(dǎo)致校驗失敗。Sync-diff-inspector 工具支持自適應(yīng) GC 的功能,在 Diff 進程初始化階段啟動一個后臺 goroutine,在檢驗過程中不斷的更新 GC safepoint TTL 參數(shù),使得對應(yīng)的 snapshot 不會被 GC,保證校驗過程的順利進行。

          處理 Float 列

          根據(jù) float 類型的特性,有效精度只有 6 位,因此在 checksum SQL 中對 float 類型的列使用 round(%s, 5-floor(log10(abs(`column`)))) 取 6 位有效數(shù)字作為 checksum string 的一部分,當 column 取特殊值為 0 時,該結(jié)果為 NULL,但是 ISNULL(NULL) 也作為 checksum string 的一部分,此時不為 true,這樣可以把 0 和 NULL 區(qū)分開來。

          用戶交互優(yōu)化

          Sync-diff-inspector 顯示如下信息:

          1. 將日志寫入到日志文件中。

          2. 在前臺顯示進度條,并提示正在比較的表。

          3. 記錄每個表校驗相關(guān)結(jié)果,包括整體對比時間、對比數(shù)據(jù)量、平均速度、每張表對比結(jié)果和每張表的配置信息。

          4. 生成的修復(fù) SQL 信息。

          5. 一定時間間隔記錄的 checkpoint ?信息。


          其效果如下圖:

          具體細節(jié)可參考 overview

          性能提升

          基于以上的優(yōu)化手段,我們進行了性能測試,在 Sysbench中, 構(gòu)造 668.4GB 數(shù)據(jù),共 190 張表,每張表一千萬行數(shù)據(jù),測試結(jié)果如下:

          從測試結(jié)果可以看出,Sync-diff-inspector 2.0 相比于原版, 校驗速度有明顯提升,同時在TiDB 端內(nèi)存占用顯著減少。


          未來展望

          開放性的架構(gòu)

          在 Sync-diff-inspector 中我們定義了 Source 抽象,目前只支持 TiDB 端到 TiDB 端,MySQL 端到 MySQL 端以及 MySQL 端到 TiDB 端的數(shù)據(jù)一致性校驗,但是在未來,通過實現(xiàn) Source 對應(yīng)的方法,可以適配多種其他數(shù)據(jù)庫進行數(shù)據(jù)一致性校驗,例如 Oracle, Aurora 等。

          支持更多類型

          由于部分列類型特殊,目前 sync-diff-inspector 暫不支持(例如 json,bit,binary,blob )。需要在 checksum SQL 語句中對它們特殊處理,例如對于 json 類型的列,需要通過 json_extract 提取出現(xiàn)在 json 中的每一個 key 的值。


          更激進的二分 checksum

          新版 Sync-diff-inspector 采用二分 checksum 方法來減小逐行比對的數(shù)據(jù)量,但是在發(fā)現(xiàn)二分后的兩個 chunk 都存在不一致數(shù)據(jù)時就停止繼續(xù)二分,進行逐行比對。這種方法比較悲觀,認為此刻 chunk 可能存在多個不一致的地方。但是根據(jù)實際情況,sync-diff-inspector 的應(yīng)用場景一般是只存在少量不一致的情況,更加激進的做法是,繼續(xù)二分,最后得到的是一組擁有最小行數(shù)(默認 3000 行)的且存在不一致數(shù)據(jù)的 chunk 數(shù)組,再對這些數(shù)組分別進行逐行比對。


          ??Tip:上文劃線部分均有跳轉(zhuǎn),由于微信外鏈限制,大家可以點擊【閱讀原文】查看原文~更多 TiDB、TiKV、TiSpark、TiFlash 技術(shù)問題或生態(tài)應(yīng)用可登錄?tidb.io?,與更多 TiDB User 隨時隨地交流使用心得~


          瀏覽 83
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久精品国产一区二区 | 日韩成人av影视 日韩成人一级AV 日韩电影无码麻豆 | 色老板在线观看视频 | 自拍偷拍字幕第9页 | 中日韩欧美一级A片 |