摘要:這就衍生出來兩個方式:一是拿到增量消息的時候,我們會根據GTID的特性,檢測拿到消息的GTID的連續性,保證拿到這套增量數據的東西一定是準的,比如說GTID上一個拿到的是345,下一個如果拿到的是348,這個時候系統會認爲現在拿到這一條GTID跟上一個並不連續,並不連續的情況下我們就要進行容錯處理,比如會向主機補償或者向其他的節點切換補償等。基於這樣的要求以及上游數據寫到消息隊列裏面的現狀,TDSQL以此爲設計的原則,實現保證按照binlog事件本身的意圖對目標實例進行修改。

        <div> 

爲幫助開發者更好地瞭解和學習分佈式數據庫技術,2020年3月,騰訊雲數據庫、雲加社區聯合騰訊TEG數據庫工作組特推出爲期3個月的國產數據庫專題線上技術沙龍《你想了解的國產數據庫祕密,都在這!》,邀請數十位鵝廠資深數據庫專家每週二和週四晚上在線深入解讀TDSQL、CynosDB/CDB、TBase三款鵝廠自研數據庫的核心架構、技術實現原理和最佳實踐等。

本文將帶來直播回顧第五篇 《高性能、安全穩定、數據一致:TDSQL如何實現數據庫異構遷移》

點擊圖片收看直播回放

我今天的主題是關於TDSQL異構數據同步與遷移能力的建設以及應用方面的內容。整個內容分四個部分:

一是異構數據庫方面包括數據分發遷移同步的背景——我們爲什麼要發展這一塊的能力以及現在這部分服務的基本架構;

二是TDSQL異構遷移能力有哪些比較好的特性,以及在實現這些特性的過程中的難點問題和我們提出的特色的解決方案;

三是結合TDSQL現在在國產數據庫的一些推廣以及應用的經驗,我們針對在異構數據遷移或者同步的領域場景最佳實踐,也介紹一些好的用法和場景;

四是針對今天講的內容做一個總結。

事實上,作爲國產自研的成熟的分佈式數據庫產品,TDSQL對內穩定支撐騰訊海量計費業務,對外開放5年來也通過雲服務爲微衆銀行等超過500家金融政企機構提供高性能、高可用、高可靠、強一致的分佈式數據庫服務。TDSQL崇尚良性的競爭,也給予客戶強信任的保障:TDSQL具備開放的架構,不僅支持安全快速的數據庫數據遷入,同樣支持異構數據庫遷出。

從客戶的需求角度出發,持續打磨產品,是我們一貫的原則。當然,除了支持數據庫遷移,多源異構遷移方案也支撐數據彙總、分發等業務場景,這也是TDSQL具備完善的產品服務體系的體現。

1. TDSQL異構數據遷移分發的背景及架構方案

1.1 TDSQL異構數據遷移方案的場景

TDSQL作爲一個金融級數據庫,面對的更多是金融級場景以及金融機構客戶,金融機構往往有一些比較特殊的需求,比如說保險行業,他們基於TDSQL構建業務時會進行一些業務劃分,或者基於水平擴展的要求,數據會落在多個分庫上等,而有時又需要把多個區域或者多個分庫上的數據彙總到一個總庫上進行統計分析,TDSQL作爲數據層的服務必須具備高性能、準確可靠的將數據實時彙總的能力。也就是說,TDSQL遇到的第一個數據庫遷移場景需求就是要支持高速準確進行數據彙總的能力。

二是來自跨城容災場景的需求。舉個例子,騰訊內部金融級業務有跨城容災的需求,這也是大型互聯網公司中常見的容災級別要求,我們要求業務具備城市級別自動快速容災切換的能力。比如說在深圳和上海分別有一套數據庫並且支撐了相關業務SVR,我們就需要在這兩個城市間的數據庫DB之間實現數據實時同步,這樣有兩個好處: 1、這一套實時同步的東西可以在城市級切換的時候快速地將業務切換備城; 2、這一套實時同步做到足夠好,比如說實時性更好或者說數據準確度是完全沒有問題的情況下,我們可以做到業務的分流,比如有部分的業務是在主城的SVR上,當我們認爲主城SVR業務量過大或者說壓力太大時候,也可以切換一部分業務流量到備城的SVR上,實現兩個城市之間數據層的數據和數據同步。 我們遇到第二個需求就是在跨城容災或者跨城業務分流、跨城數據同步上我們需要DB側有這樣的能力提供給業務使用。

三是異構的數據分發和遷移。TDSQL作爲一個金融級數據庫,對外是非常開放的架構,我們支持將數據以各種各樣滿足業務的方式同步到外面的平臺,比如當有一些業務需要在Oracle上跑一些比較老的業務或請求等等;也有一些業務需要把數據同步到消息隊列給下游業務使用,比如大數據平臺、其他的檢索之類,我們可以通過消息隊列把數據抽出來。金融機構往往需要數據不僅能夠存進來而且能夠很好地按照要求分發出去,供下游業務使用,這也是我們遇到比較重要的需求。

針對上面提到的三種場景——數據彙總、跨城容災、異構數據庫間數據的分發和遷移TDSQL針對這些需求構建出一套叫做多源同步的系統。現在介紹一下多源同步的系統是通過什麼樣的架構來滿足我們提到的三個需求的。

1.2 開放的架構:TDSQL多源同步方案架構解讀

從圖上可以看到有三個組成部分:一是原數據的抽取;二是中間的存儲——這是一個消息隊列,三是目標實例。這是一個非常典型的CDC架構,通過獲取源端數據源的增量數據,通過消息隊列,下游消費的邏輯將數據進行分發。從左邊看到,這一套多源同步,源端支持MySQL,就是對MySQL系列的DB可以獲取它的增量數據;還有Oracle。。抽取完數據增量,比如說binlog日誌或者增量數據獲取服務抽取到的數據,我們會以一箇中間格式存放到消息隊列裏面;存到消息隊列以後,我們自己實現了一個消費邏輯——叫做consumer消費者,它可以實現將這一套存到消息隊列的數據按照不同的需求以及不同的目標端類型將數據推送到下游。

目前TDSQL多源同步方案支持的目標端類型有下面這幾種:PG, TDSQL, Oracle,還有一部分就是MySQL,另外還可以將增量數據再推往另外一個消息隊列,比如說有一些業務可能需要將這套增量的數據推往業務使用的隊列組件裏面,我們也是支持這樣做的。

最後,在這一套同步的數據鏈路過程中,我們有一個數據校驗的服務,包括兩個方面:一是增量校驗,含義就是會實時校驗這一筆數據從源端抽取,到它的增量變化,再到寫到目標端之後,這筆數據落庫落得準不準確,是不是在正確的目標上寫下這筆數據;二是存量校驗,可能是一些定時定期去跑批,比如說定期對源和目標的數據進行整體的校驗,我們能夠主動及時地發現整個數據通路上的問題和錯誤。

結合我們剛剛說的需求,基於數據同步的跨城雙活架構,也是騰訊內部現在在使用的架構。基於數據同步的跨城雙活架構是這樣的形式:

首先左邊和右邊代表不同的城市,這裏舉例左邊是深圳,右邊是上海。從圖上可以看到,TDSQL在SZ這套實例會將業務不斷寫入的增量數據源源不斷地寫入本城的消息隊列裏面。對城的SH也會將自己業務訪問的增量數據源源不斷寫到消息隊列裏面,同時在各個城市有一套自己的消費服務,這套消費服務會拉取對端的增量數據,也就是說會拉對城的消息隊列裏面的增量數據進行重放,這樣就實現了兩套基於數據同步的一套跨城雙活。這個雙活是有前提條件的——就是兩套業務在SZ和SH同時寫的時候,它的訪問主鍵一定是分離,在這一套邏輯下面沒有辦法做到同時對同一條主鍵進行修改。我們基於跨城的這套雙活架構也是要基於主鍵分離的做法。

2 TDSQL 多源同步方案的挑戰和特性

2.1 要求與挑戰

介紹完整體架構,我們繼續深入拆解下,這套架構所面對的業務場景,都有哪些要求?在這些要求實現的過程中是有哪些難點,並且針對這些難點我們是怎麼處理的?以下將介紹這其中的特性、難點、解決方案。

一是高性能:對實時性要求比較高的業務對數據同步的速率有比較高的要求,比如說秒級別等等。但無論如何,在這個互聯網時代,這套數據同步要快,不能說加了這套數據同步、異構分發的邏輯以後,它同步的速度非常慢,這肯定是不可以。

二是數據強一致性:在快的基礎上,同步的數據一定要準。這套數據同系統,分發的系統把數據從源端抽出來,往裏面寫的過程中,需要做到原來寫出來是什麼樣的,目標重放就是什麼樣的,兩邊的數據一致性一定要有保證,這裏面就包含了我們如何規避在抽取鏈路、重放鏈路這兩個數據鏈路上的錯誤;二是如何保證在異常情況下寫入的數據一定是對的。

三是服務高可用:這一套同步服務,一定是高可用的,體現在兩個方面:1、災難的情況下,本身消費者的服務能夠在假如機器出現一些不可恢復的故障時能夠及時地感知並且自動遷移和切換;2、要應對本身常規的擴容——垂直擴容或者水平擴容的伸縮性需求,這也是我們比較強調,這一套同步服務要能夠兼容各種災難情況和常規的運維場景下各種各樣的要求來做到服務的高可用。

接下來就針對上面這些點一個一個來看。

2.2 一致性保障

2.2.1 自動化消息連續性檢測

從上面的架構圖我們可以看出來,整個數據鏈路比較長,它要先把增量數據拿到,寫到消息隊列裏面去;再從消息隊列裏面消費出來。生產者這一套服務做的事情就是首先要拿到增量數據,二是要正確地把拿到的增量數據準確地投遞到消息隊列裏面,這裏面有兩個問題:1、如何判斷我拿到的消息——本身的增量數據,是對的;2、我如何確定寫到消息隊列裏面,消息隊列存的也是對的。

這就衍生出來兩個方式:一是拿到增量消息的時候,我們會根據GTID的特性,檢測拿到消息的GTID的連續性,保證拿到這套增量數據的東西一定是準的,比如說GTID上一個拿到的是345,下一個如果拿到的是348,這個時候系統會認爲現在拿到這一條GTID跟上一個並不連續,並不連續的情況下我們就要進行容錯處理,比如會向主機補償或者向其他的節點切換補償等。總結來說,TDSQL在拿增量消息這部分,是具備連續性檢測的能力,保證拿到的數據一定是準確、連續的。

二是系統如何保證寫到隊列裏面的數據一定是準?在寫到隊列過程中有可能出現重複、亂序等情況,TDSQL多源同步方案採用的策略是——利用Kafka本身在寫消息的回調通知的特性,我們在將消息推到Kafka的時候,會給每個消息賦予一個連續遞增的序列號,通過Kafka回調的寫入消息來確定系統寫入的消息是不是有序的。舉個例子,我們按[5,6,7,8,9]這樣的順序向Kafka生產一部分消息(寫),屆時收到的消息回調序號也應該是[5,6,7,8,9];當接收完9號這條消息回調的時候,下一條如果收到的回調序號是12、或者11,那麼就會認爲從9號往後的消息隊列消息不是一個有序的消息,這時系統會重新從9這條序號往後的消息重新上報kafka,最終保證寫到消息隊列裏面的數據是沒有空洞並且是連續遞增的。這是生產者服務在消息連續性異常檢測方面我們提供的兩種機制。

2.2.2 異常自動切換機制

以上介紹的機制可以保障多源同步、異構遷移中如何檢測到錯誤。那麼,檢測到錯誤之後如何處理呢?以下就介紹生產者異常自動切換的機制、切換的條件。

這裏面都以TDSQL的實踐爲例:獲取增量日誌必須要在一個合適的TDSQL角色上處理,TDSQL本身是一個一主多備的分佈式數據庫集羣,在選擇獲取數據庫增量日誌的角色上我們選擇從備機上獲取。

選擇一個合適的備機對增量數據獲取來說是非常重要的。當獲取增量日誌的備機的延遲比較大,或者這個備機本身不存活,或者這個冷備發生了遷移(什麼是冷備?離主機的距離最近,或者跟主機的差距最小的備機,我們叫它冷備),這個時候系統就會將解析日誌生產者的服務切換到另外一個節點,整個切換流程通過MetaCluster服務協調。也就是說當工作的數據庫節點本身的狀態發生躍遷之後,其他節點生產者服務就會通過MetaCluster來感知到狀態的躍遷,並且適當地啓動自己的服務——從一臺備機狀態躍遷到另外一臺備機,而躍遷前的備機的生產者服務會停掉,新的備機生產者服務會自動拉起來。這就是它的切換流程——通過MetaCluster進行下發協調。

切換是基於什麼樣的觸發條件?現在解析到的這臺備機本身狀態是正常的,比如延遲沒問題,存活性也正常,冷備角色一直沒有發生變化,但是發現它的binlog不連續。當我們檢測到拿到的這套binlog是不連續的時候,就可以認爲這裏面可能會出現binlog的丟失,這個時候就要發起補償的操作。怎麼補償呢,通過這個流程給大家介紹一下。

當系統發現解析到這套GTID不連續了,就會向ZK註冊一個節點。舉個例子,系統現在已經發現拿到的binlog不連續了,於是註冊一個補償節點,包含着“向主機補償”這樣的信號。當主機檢測到有這樣一個補償節點時,會將日誌解析的角色接管過來並開始工作。

接下來,我們如何確定主機從哪裏開始解析日誌?我們會從Kafka上讀取最後一條消息——最後一條消息包含GTID的信息。這時主機就會把這條消息對應的GTID轉化成本地的binlog文件名和偏移量開始解析。

主機的補償需要持續多長時間?持續一個文件處理的流程。當主機補償到解析的所在文件結束以後就會退出主機補償的流程,並將這個角色通過MetaCluster重新下放給備機的生產流服務,而備機的生產流服務接到這個請求以後會重新從Kafka上拉取上一次主機補償的日誌中最後一套消息。如果說找到了對應的GTID,並且往下解析的時候沒有發現不連續的情況,這一套補償流程就算結束,備機會繼續在自己的角色上持續地進行增量數據生產。

如果發現從Kafka拉下來的主機補償日誌最後一條本機找不到,就說明這個主機的補償不完整,有可能備機缺了兩三個文件,這個時候會持續向主機進行補償,通過註冊MetaCluster節點的方式一直重複這個流程,直到主機補償完成,備機在接管角色的時候能夠連續順利地接着解析,本身的日誌才認爲這套補償流程已經完全結束——這就是一個通過不斷向主補償日誌的方式來進行異常的切換的流程。

2.2.3 冪等重放機制

介紹完生產這套鏈路之後介紹一下下游的鏈路——消費,消費的鏈路中怎麼保證數據一致性?首先回顧一下剛剛提到的生產端的數據一致性保障——生產端在實現消息生產的時候實現的是一種at-lease-once的模式進行消息生產,這裏面就要求消費服務必須能夠確地處理消息重複這個問題,也就是說我們要支持所謂的冪等邏輯。

支持冪等之後有什麼好處?在binlog是連續無空洞的前提下,支持冪等機制的消費服務可以從任意一個時間點重放binlog消息,當重放結束以後目標的數據會達到最終一致,這就是消費鏈路實現冪等的動機和優勢。這個機制實現的難點在於要絕對的可靠——重放一定是要百分百沒有問題,準確無誤。

基於這樣的要求以及上游數據寫到消息隊列裏面的現狀,TDSQL以此爲設計的原則,實現保證按照binlog事件本身的意圖對目標實例進行修改。什麼叫做按照binlog事件的意圖去對目標進行修改呢?

增量數據無非就是三個方面:一是insert的寫入,二是更新,三是刪除。

1. insert寫入

在寫入的時候我們是如何做到insert事件冪等呢?一個start進來我們要重放insert:

當它的影響行數大於0,我們就認爲這套insert執行成功;如果執行失敗,我們認爲它可能有一些報錯,比如說語法錯誤或者目標的字段過小,並進行重試的邏輯。

當影響行數等於0,則判定可能會出現主鍵衝突——insert失敗影響行數爲0,這裏面唯一的可能就是出現了衝突。出現主鍵衝突的時候這個時候怎麼處理?insert這一條數據發生的時候意圖是什麼?在insert之前DB裏面是沒有insert這條數據,而當這條insert發生之後,DB裏面是有的——按照本身的意圖來做,意味着如果發生了主鍵衝突或者影響行數等於0的情況,裏面存在一個相同的記錄,這個時候系統會按照insert本身的值拼一個delete操作。這條delete操作下去後,就能保證在這條insert寫入之前,目標裏面是沒有這條數據的;當我這條delete做完之後,再把這條insert進行插入。這個時候如果影響行數大一點,可認爲這條insert被按照本身的意圖做完了。其實也就是說,要保證這條insert做的時候,只有當前這一條數據——這就是insert本身的冪等。

2. 更新

更新:首先一條update,如果影響行數大於0,可判定這條執行是正常的。如果小於0,則意味着可能出現一些執行錯誤,比如語法有問題或者字段長度有問題。

如果它的影響行數等於0,有兩種可能:一是沒有匹配到——進行update時是按照全字段進行匹配的,這一行改之前和改之後所有的字段都在這條消息裏面,原始更新也會按照所有字段來去拼裝,沒有匹配到則意味着某些字段沒有匹配到,這個時候會按主鍵更新——也就是匹配到這些值可能是全字段,執行更新的操作。

如果按照主鍵更新操作,影響行數還是0的話,則可以判定爲出現了主鍵操作的衝突。這個時候系統就會思考一下,這條update它的語義是什麼——update的語義是指這條update執行完以後,目標庫裏面第一個是沒有改之前的值,第二個是有且只有改之後的值,所以我們按照這個語義做接下來的操作,按照所有的唯一鍵去構造一個刪除的操作,操作完了以後再按照update裏面改後的,構造一條插入操作,將這條插入操作寫入目標DB——如果影響行數大於0,實際可認爲這條update就是按照它本身的意圖對目標實例進行了修改。

3. 刪除

我們來看一下刪除的過程。相對於update來說簡單多了。這個過程中,delete結束後大於0就成功;小於0就是失敗;等於0的時候我們認爲它可能沒有匹配到行,這個時候我就按照主鍵操作——因爲刪除的操作最終的結果就是目標一定沒有了當前刪除的消息主鍵所標識的這一行——這條操作完成後,DB裏一定沒有這行數據,因此僅僅是按照主鍵進行刪除就可以了。這個時候如果影響行數大於0,則刪除成功。如果等於0,就認爲按照主鍵去匹配,本身刪除不到,匹配不到——意思是本身目標就沒有這條要刪的主鍵所標識的數據——所以實際上它的結果跟要做完刪除的結果,影響是一樣,也就結束這一條刪除的冪等。

回顧三種類型的時候,我們比較關注這條數據在執行前後的狀態,它執行前是什麼樣的,執行後是什麼樣的,我們在重放這條消息的時候,嚴格按照這個來做,insert就是執行前沒有這條數據,執行後有這條數據,如果遇到衝突就先刪除後insert,update執行後它的結果,一定沒有改之前的值,有且只有改之後的值,刪除也是一樣,目標裏面一定沒有主鍵所標識的這一行在目標實例裏面,我們按照這個邏輯設置冪等的流程,就是這樣的過程。

2.2.4 跨城數據同步如何規避數據迴環

接下來看一下在跨城數據同步如何規避數據迴環。跨城的架構中,本城的一套數據實例會把增量數據寫到消息隊列,對城會有一個服務從消息隊列裏面把這個數據拉出來——對城的消息也會落到對城的消息隊列,本城有一些消費服務會把這些數據拉過來,也就是說數據具有一個環路。如果不做迴環檢測和規避,比如插入這一條數據,這條數據的目標又插入了,並且也落了一個日誌,做了這個日誌又寫回來,這相當於同一個主鍵的數據來來回回在寫,這樣會把數據寫髒。

我們是如何來規避跨城數據同步的迴環,以及對它進行檢測的?TDSQL結合DB內核的改造,通過SERVERID來規避數據在跨城雙活數據同步架構裏面的迴環問題。

假如說左右兩端是兩個DB,這兩個DB對應的SERVER ID不一樣:一個是23243,一個是43423。現在有一條叫做insert的數據寫入目標,寫入目標之後會設置當前這個SERVER ID跟原來的SERVER ID一樣——23243的ID。這條insert落到DB裏面,會記錄成它的對應日誌的SERVER ID 23243,而不是記錄它本身備城的43423的ID。

當消費服務拿到增量日誌——拿到的這條日誌所對應的SERVER ID跟目標DB的SERVER ID是一樣時,則認爲拿到這條日誌一定是目標寫過來的日誌,然後執行跳過的操作。只有當拿到的這條日誌對應的SERVER ID跟目標的SERVER ID不匹配的時候,纔會把這條數據寫到目標裏面去。這樣一來,才能保證只有是真正業務訪問到源端的DB,並落下來的那條日誌,纔會被成功寫入到目標上——這就形成一個通過SERVER ID將環路里面的數據過濾的機制。

2.3高性能保障

2.3.1 有序消息併發重放

現在介紹一下關於高性能的優化實現。

MySQL本身在落日誌的時候是有序的消息,就是說binlog是有序的。如果按照binlog的數據來重放,是沒有問題的——按照一個事務一個事務進行串行解析。但這會帶來一個問題——就是慢。

對於這個問題,TDSQL想辦法對有序消息進行併發重放來提升數據同步的效率。採取通過基於row格式binlog日誌的hash併發策略來實現。

這個hash策略就是根據表名和主鍵來做:首先從消息隊列拿到數據之後,系統會進行派發,派發過程中根據消息裏面的主鍵和表名進行hash,將消息hash到不同的工作隊列。

這樣的hash策略有一個什麼樣的結果?相同表的同一行操作的序列一定會被劃分在同一個工作現場,只要保證對某一張表其中固定一行的操作是串行有序的,就認爲這套數據在併發重放結束之後數據是最終一致的。

總結而言,TDSQL多源同步併發策略就是按照主鍵和表名進行hash,保證每一個表裏面的固定一行的操作序列在同一個工作隊列裏面串行化。併發的數據同步和串行數據同步區別就是一致性的問題,可以看到這種併發策略相當於把事務打散。這裏面併發重放的時候就會產生事務一致性的問題,有可能會非常小的幾率讀到中間狀態,在數據同步速率有保障的情況下說不會出現這種問題的。如果說這個業務本身對事務一致性要求非常嚴格——當然我們現在還沒有碰到這樣的場景。這就是一個有序消息的併發重放。

2.3.2 有序消息併發解析

以上是消費端性能優化的過程,首先就是要寫得更快,通過各種優化把hash併發到多個現場去寫。那麼寫完之後,消費端的性能瓶頸在哪裏?在解析上。

大家如果有印象的話,我們寫到Kafka裏面的數據是中間格式——json格式。json格式需要一個解析過程。當我們解決了重放性能瓶頸之後,原始的消息包拿到後解析的過程又變成性能優化的瓶頸。針對這個問題TDSQL同樣做了有序消息的併發解析優化。

併發解析的策略就是,維持一個線程池。從Kafka上拉下來的這條消息,本身是一個原始沒有解析的包,當拉下來這條消息包時會從這個池子裏面撈一個空閒隊列,並把這個包給空閒的線程,這個線程拿到這個包以後就開始解析,當它拿到包這一刻就會進入到另外一個busy隊列裏面。它在忙隊列裏面會不停地解析拿到的這些原始消息,解析完之後會有一個協調線程,從忙隊列面不斷把解析線程摘出來喚醒,把解析後的消息再併發地分往後面的工作線程。源源不斷從Kafka拉消息,拉完之後就把這些沒有解析的消息分給一組線程去解析,這一組線程在解析的時候——雖然解析是併發的,但在被喚醒派發的時候有一個出隊的操作——也就是派發是按照順序派發——這就做到有序消息的併發解析:通過一個忙隊列、一個閒暇隊列,兩個協調線程把整個流程串起來,這樣基本解決了在json解析上的瓶頸。

2.4 高可用保障:多機容災保護

2.4.1 多機容災保護

現在介紹一下消費者高可用保障。消費者服務本身無狀態,所有的任務下發通過MetaCluster實現,可以通過多臺機器去部署同步服務,這套容災機制通過manager進程來實現,也就是說當整個機器掉電,運營這個機器的consumer已經不存活,這個時候這些consumer在MetaCluster上的存活節點的失效就會被其他機器的manager節點感知——認爲另外一些機器的consumer已經不存活,這個時候就會把任務接管過來,並且在自己機器上重新拉起這些服務。

二是我們要做到同一個數據同步的鏈路不能在兩臺機器上同時拉起,這是一個互斥的要求。高可用機制會通過一些像唯一標識或者當前的分派節點做到,同一個數據同步的任務在被拉起的時候一定是發生在不同的機器上來實現漂移與互斥的操作,這個多機容災保護總體上就是通過MetaCluster和監控的進程,比如說manager這樣的服務進行協調完成,保證在機器級別災難或者其他災難情況下這些任務能夠在十秒以內成功遷移到其他的存活節點上。

2.4.2 擴容場景的高可用設計

可用性一方面在災難情況下需要保證服務可用,另一方面則是在擴容等數據庫常規運營場景下保證這個數據同步有效且不會中斷。

首先來說一下爲什麼在擴容的場景下,有可能造成數據同步異常?以垂直擴容來說,是相當於重新買了一套實例,然後經過數據的搬遷來實現數據同步的。這個時候我們是通過TOPIC唯一性來保證服務可用。擴容中從一個實例遷移到另外一個實例的時候,兩個實例之間關係是什麼?它們會往同一個Kafka上TOPIC去打增量數據。新實例打增量數據的起始點是什麼?生產者在工作的時候會從Kafka上拿起始點,上一個服務結束的位置就是這個服務開始的位置。

關於水平擴容,則是新擴出一個set來,然後建立數據同步,對重複的分區進行切割和刪除。如果現在有兩套分佈式實例進行數據同步,比如源端有一個分佈式實例,這裏面對應會有兩個同步任務寫到目標上,如果對其中一個分片進行水平拆分之後,就會拆出另外一個實例來,這個實例在拆分中有一個數據同步的過程,這個過程會產生問題——在set 3 binlog裏面,會有一些set2上寫的數據,並且SERVER ID跟set 2一樣,如果單純對set 3新擴出來的分片創建一個數據同步任務,將數據寫到目標上的話,我們認爲這裏面可能會把SET2已經寫進去的部分數據重複。這個TDSQL的數據同步服務針對水平擴容的這個場景也是實現了高可用保障,比如我們會針對擴容前的SERVER ID進行過濾,過濾水平擴容前set的原實例的SERVERID,這個跟跨城的迴環操作是比較類似的。通過這樣的方式,來保證新創建出來的這部分增量數據開始往目標上寫的時候,一定是這套擴容流程已經結束了,並且是有真的業務數據寫到新擴的分片上來,不會出現同樣的數據反覆寫兩遍的情況。

3 TDSQL 多源同步金融級應用場景和最佳實踐

上面我們解釋了這個模塊的特性、難點、解決的方式,現在介紹這些應用場景以及案例,包括TDSQL在多個客戶場景中的最佳實踐。

3.1 實現業務驗證

關於實現業務的驗證,比如可以對兩個DB進行實時的數據同步。新的業務系統升級時,不可能直接把新的業務系統放到老的DB上直接跑,這時可以把新的業務系統先落到新的DB上做相關業務驗證,或者在異構數據庫的DB層變更上,把數據先同步到新的DB上來做業務上新老系統並行跑的驗證——一方面是保證了原先業務系統的安全性,另一方面也可以讓業務切割更加方便,因爲數據已經實時同步了。

3.2 實現業務灰度

二是業務的灰度,以張家港農商銀行的實踐爲例,在覈心繫統上線的過程中,我們把數據通過主鍵同步到TDSQL或者Oracle上,主庫如果發生了一些比較小概率的災難性實踐,這時可以將這個業務系統迅速地切入到備庫上,可以是TDSQL也可以是PG、Oracle,相當於是實時的數據備份來形成備份的DB,走備庫上把這些業務拉起來在備份的DB上跑起來。

3.3 實現業務割接

三是在實現分佈式改造、進行業務割接過程中,可以將單實例的操作同步到分佈式的實例上——這個過程先將數據通過多源同步組件同步到分佈式的實例上,之後將業務的流量逐漸地從單實例往分佈式實例上切,同時在分佈式實例上也可以去相關業務驗證,這也是我們的應用場景。

3.4 金融級最佳案例實踐

我們可以通過多源同步對業務進行分佈式的改造,將數據直接通過實時的同步將單實例往分佈式的架構上遷移。比如說保險客戶通過多個分庫、多個分片區或者多個單的業務、邏輯上的劃分,把這些數據通過TDSQL這套服務同步到存量庫裏面。

我們在雲上也有一些客戶。公有云上,TDSQL的實例是通過公網實時寫入自建的IDC裏面,不管是Oracle還是TDSQL——寫到Oracle我們也支持,我們可以直接把MySQL的DDL轉換成Oracle可以兼容的DDL,實現雲上的生產業務在跑的同時,本身之前IDC離線業務的老舊業務系統也可以在自建IDC的老實例上運行。

在張家港行實踐中,核心交易集羣是TDSQL,我們數據同步通過內部的局域網,將存量和增量數據,寫入到備份機房,同時也通過全量的數據校驗服務保證數據源、目標是完全一致的來做風險控制。當核心交易系統如果出現一些小概率不可恢復的災難時候,系統可以在短時間內將交易的服務全部切換到備份機房的Oracle上。

四 總結

以上介紹TDSQL對外分發解耦,數據分發、遷移、同步的能力,承載這部分能力的模塊叫做多源同步模塊,在應對金融級別或者金融場景客戶的對外解耦、遷移的需求時候,所衍生出來的,高一致、高性能、高可用這“三高”的特性,並且介紹了針對這些特性我們是如何通過技術手段來實現的。

Q&A

Q:全量檢測的效率怎麼樣?

A:單表的話全量校驗一分鐘可以校驗5個G的數據,但是表和表之間本身是可以併發,也就是說單表一分鐘5個G,但是可以多個表併發去跑,這個上限就是機器本身的上限,比如說網卡。這套全量校驗也是通過主鍵去把數據值拉出來走內存去做MD5。這套效率目前來看還可以,但是校驗速度也不適宜過快,本身它去拉取數據時候對數據庫也是有一些影響的,我們本身做校驗的時候也會在業務低峯或者晚上去做。

Q:如何實現抽取binlog到Kafka不丟事務?

A:這就是前面介紹的,系統去做GTID連續性檢測,我們知道在記錄binlog的時候,GTID一定是連續的,如果不連續則可判定認爲它丟了,繼而會到主機上補償。就是通過這樣的方式保證我們拿到的數據一定是沒問題的。

Q:DDL同步嗎?

A:DDL同步。因爲DDL同步是會進行一次語法解析,解析出來相關的操作的,比如要改的哪些表、哪些字段,哪些類型需要改,針對目標的不同類型去做類型的轉換,將這個DDL重放到目標上。

Q:原抽取和目標回放支持按條件抽取、按條件回放嗎?

A:抽取我們支持按白名單去抽。爲什麼要支持白名單抽?我們原先的策略是全量上報到Kafka,有的時候會帶來一些問題,比如說業務去清理一些歷史的表,比如說一些流水的大表可能去做日誌的刪除等等,會批量去做一些操作,這個時候會產生一些瘋狂往Kafka上打一些業務並不關心、同步並不關心的數據,這個時候我們也支持源端配白名單的方式,我抽取哪些庫表的數據。目標重放更靈活一些,目標重放的時候是通過一個同步規則去配,同步規則本身支持精確匹配,同時也支持政策匹配。精確匹配就是一個表同步到另外一個表,精確匹配支持表名的變換,比如說我在原實例上表名是A表,同步到B實例上表名是B表,這裏面強調的是表名可以不一樣,但是它的表結構是要一樣的。也支持我可以匹配源端多個表同步到目標的一張表裏面,也可以支持彙總的方式,就是表名在映射這一塊也是比較靈活的。

以上是今天的提問解答。謝謝大家。

TDSQL是騰訊TEG數據庫工作組三大產品系之一,在國產數據庫領域屢次率先突破,包括助力微衆銀行搭建首個全行級互聯網銀行核心系統,以及助力張家港農商行實現傳統核心系統數據庫首次國產化等。目前,TDSQL已廣泛應用於金融、政務、物聯網、智慧零售等行業,擁有大量分佈式數據庫最佳實踐。

推薦閱讀:

億級流量場景下的平滑擴容:TDSQL的水平擴容方案實踐

流量洪峯成爲常態,騰訊數據庫如何高性能支撐海量SQL查詢?

相關文章