京東物流資料同步平臺“資料蜂巢”架構演進之路

劉美利發表於2018-08-21

導語: 本文根據賀思遠老師在2018年5月12日【第九屆中國資料庫技術大會(DTCC)】現場演講內容整理而成。

京東物流系統架構師賀思遠

9年網際網路/大資料領域研發、架構經驗,2015年加入京東物流,主要負責大資料相關架構與開發工作。

摘要: 資料蜂巢平臺是京東物流自主研發的分散式、高效能、高可用、支援異構,離線和實時的大資料同步與管理平臺。關鍵技術:HA;離線與實時同步整合;binlog採集,儲存與訂閱;客戶端併發消費;一致性校驗與修復;任務隔離。 目前已經在京東物流系統中大規模應用,比如單源和多源複製,從全國各地倉儲園區叢集(上百個)實時複製到IDC,從mysql到ES,從mysql到cassandra等等。倉儲園區硬體、網路環境複雜,資料蜂巢平臺需要考慮硬體設施和網路故障的容錯性。議題主要分享平臺誕生的背景,使用的關鍵技術,架構的演進過程,演進過程中所踩過的坑。

正文:

京東物流一線資料大部分都存在MySQL資料庫上,分佈比較廣,包括國內外園區庫房和IDC,這樣資料使用起來極不方便,各業務系統為了使用資料,開發出多種版本的同步工具,結果導致管理非常困難以及資源的浪費。這時就需要一個統一的平臺把這些資料管理起來。

架構設計

關於資料同步,主要分為:批量同步、實時訂閱和實時同步。

批量同步: 採用sqoop的模式,把資料分片,然後進行多機併發複製,用以提升效率。

實時訂閱:使用訊息佇列,即將binlog事件解析生成對應的訊息儲存在佇列中;

實時同步:通過客戶端去消費佇列將資料寫入目標儲存,從而實現資料的實時同步。

如何中將以上三個功能整合到一個平臺?

首先,適配批量同步,參照sqoop, sqoop是藉助於hadoop叢集提交一個mr作業, 類似的,蜂巢系統也提供一個叢集,將一個批量同步作業分為多task去執行。實時訂閱也可使用這種思路,不同的是每一個task即對應一臺mysql例項的binlog採集;同理實時同步也可分成多個task,每一個task即為一個訊息佇列的消費客戶端。

架構圖如下所示:

採用了經典的master、slave結構,每一個slave上可以跑三種對應的任務。BatchWorker負責把MySQL資料批量同步到storage裡面,這裡的storage是一個抽象,不一定就是儲存之類的系統,也有可能是一些業務的處理。StreamWorker負責binlog的採集和訊息佇列的維護,如果有訂閱需求,使用系統提供的客戶端Consumer就可以直接消費。

Pieworker則是Consumer的分裝,只不過這個客戶端由叢集去管理維護。  

BatchWorker結構比較簡單,主要由Fetcher、Sinker和Storage(與整體架構圖中的storage不同,此處為一個buffer)組成。Fetcher介面負責抽取資料,Storage負責快取資料,Sinker介面負責資料的寫入。

StreamWorker模仿MySQL的主從複製機制, RelayLogTask負責binlog的抽取;HHLTask負責解析binlog,生成訊息體,最後存在hhl中,hhl即為上文提到訊息佇列。

客戶端: StreamJob除了採集binlog,維護訊息佇列外,還提供了一個ClientServer模組,用於接收客戶端的消費請求。當Consumer需要消費的時候,請求會傳送到ClientServer,ClientServer通過索引快速的定位到hhl檔案的某一個位置,然後把資料讀取出來,然後經過客戶端的指定過濾規則進行過濾,最終將訊息體傳送給客戶端。

訊息的位點由三部分組成的:Serverld對應的就是MySQL的Serverld;binlogPosition是一個長整型數字,高32位為binlog檔案下標,低32位為檔案內部的位置;time為對應的binlog事件產生的時間。

為解決效能問題,客戶端支援多種並行模式。

第一種是以事務為單位序列處理,;

第二種是在第一種基礎上進行了一個簡單的優化,比如:一個事務內只對單表操作,那麼這個事務是完全可以併發的,不同表間的事務順序並不會影響最終結果的一致性;但事務內對多表操作就需要繼續序列。所以第二種併發模式就是不斷序列並行轉變的過程。

以上兩種消費模式是以事務為單位,以下兩種以行為單位

第三種是表級併發,將事務拆分為多個行級操作,同表操作由同一執行緒完成,保障同一表操作的有序性;

第四種是行級併發,主要是把MySQL的資料同步到NOSQL上時使用,關係型資料庫同步時侷限性較大,因為行級併發只保障同一主鍵的操作有序,而關係型資料庫會存在多個唯一約束,這樣即使保障了主鍵的操作有序也可能引起資料不一致。

叢集的特性:作為一個叢集都需要要保證高可用、資料本地性和負載均衡。高可用這一塊主要分為三部分:

MySQL: 由DBA保證資料庫的高可用,但當Mysql主從切換時,binlog的位點是不一致的,此時系統通過Serverld的檢測發現該變更,然後通過時間在新的mysql實列上定位正確的binlog位點。

master(Queen):基於Zookeeper完成Active角色的選舉

Bee(Slave):Bee當機後由Master將其執行的任務遷移到其他的Slave上。

資料本地性:每一個Bee在啟動時都配置了機房,分組等資訊,作業提交時可以指定自己期望的執行位置,與hadoop,spark類似。

負載均衡: 每一個Bee會將自己的負載資訊通過心跳發給Queen,queen進行作業排程時,會在滿足資料本地性的前提下選擇壓力最小的機器去執行新任務。

演進

HHL檔案丟失:上文提到過,如果Streamworker的執行主機當機,Master會把它遷移到另外一臺機器上,但是Streamworker採集解析的binlog存在本地,遷移後會引起資料丟失,解決這個問題通用的方案是多副本,但大資料量下的多複本會造成磁碟空間的浪費,尤其是在庫房環境下;並且這些資料有一個特點,就是發生遷移時,雖然解析過的資料丟失,但是原始binlog都會在機器上儲存(dba會保留n天的binlog資料),最終可以通過資料補全來保證資料不丟失。

上圖為第一版streamworker的擴充套件,最右面的可以認為是這一組的主執行緒,虛線位置發生任務遷移,切換到了新的主機上,此時虛線左邊的資料全部丟失。如果有客戶端需要消費丟失的資料,服務端則啟動一組新執行緒,然後進行catchup,catchup會把丟失的部分補齊並提供給客戶端消費。

後設資料: binlog是不記錄欄位名等後設資料的,而客戶端消費時需要。最簡單的方式是收集到binlog之後,去源庫上查詢,但在binlog採集延遲期間如果有ddl操作,會導致後設資料不準確。為解決該問題系統實現了一個快照模組。在StreamJob初次啟動的時候,把對應的MySQL裡面所有表都做一份快照,在此後的執行期間監控DDL操作,當解析到DDL操作時會將原快照取出生成一個複本,並在這個複本上應用這個ddl,生成新的快照 。這樣系統可以保證任何時刻binlog對應的後設資料都是正確的,方便使用者使用。

客戶端:服務端並不記錄客戶端的消費位點,消費的位置由客戶端自行儲存。由於客戶端採用的是併發消費模式,訊息又是嚴格有序的,此時位點記錄就必須保障每一個記錄下的位點之前的所有訊息都被正確處理了,此處引入了一個環形提交佇列(具體實現與disruptor類似),當連續的多個訊息被正確處理,並達到記錄位點的間隔,此時提交佇列會將一個位點寫入對應的儲存介質。比如1,2,3,4,5,8,10,14被處理完成,位點提交間隔為5,則5位置對應的位點被記錄,當6,7,9被處理完成後10再被記錄。

以下主要為易用性的改進:

SQL: 使用者通過SQL描述需要同步哪些欄位,同步條件等資訊,服務端通過解析sql執行對應的同步邏輯。

Union: 用於處理多表合一的場景,通過加入來源標識欄位來解決唯一約束。

Join: 在同步的過程中完成寬表的加工,內部通過快取,布隆過濾器等優化方案來提升效能。

 一致性較驗:

系統提供了兩種模型:

第一種是使用pt_table_checksum的思路,比如要較驗一張表的資料,先把這張表的資料分成多個片段,然後對這些片段進行crc計算,並將結果和計算的範圍儲存到同一個資料庫的表裡去,此時會觸發一個binlog事件,當消費者消費到這個事件後重現該操作,通過比對計算結果值來確定資料是否一致,這種方式一是侵入性比較強,需要在原庫上建對應的比對結果表,二是需要加鎖,三是對延遲的要求很高,當延遲較大時,消費端拿不到對應的比對事件,將無法確定資料一致性。

第二種資料校驗的模型是基於BatchJob實現。

Fetcher抽取源和目標雙方的資料,排序後通過storage把資料傳遞給sinker,Sinker根據使用者自定義的比較介面對資料進行比較,最後將差異通過Collector進行收集。這種比對方式的缺點是不能保證時間序列,在比對的時候資料是變更的,比對出來的結果可能並不是真正的差異,此時我們需要修復比對結果,首先在比對開始時把消費端的位點記錄下來,比對完成後,如果有差異則從比對開始前記錄的位點進行binlog重放,通過分析binlog中操作,對差異進行修復,輸出最終結果。 該比對模型最大的問題是需要抽取比對雙方的資料,對頻寬佔用較大,為減少網路傳輸,內部會對資料進行初步的篩選,將要比對的資料分成多個片段,在儲存端對每個片段進行md5計算,fetcher只收集md5值 ,只有雙方md5值不同時才將真正的資料抽取到計算端進行比較。

修復:

系統提供兩種修復方式:

一是基於binlog事件傳遞,當比對出差異資料後,只需要在源庫上對差異資料進行一個偽操作(比如更改update_time欄位),觸發binlog事件的產生,消費端收到該事件即可修復錯誤資料(事件對應的訊息體內包含了所有對應欄位的值,並不只限於update_time欄位),該方式缺點是受延遲的影響,同時還需要源庫的寫許可權。

二是直接修復,即直接在目標上將差異資料修正。在修復資料時需要加鎖或暫停同步,避免併發問題。

 

資源的隔離: 系統預設只提供了常用的同步功能,當預設實現無法滿足客戶需求時,使用者需要自行編寫程式碼來實現對應的介面來完成他們的邏輯。Bee開始使用的執行緒模型,即每一個Bee可以看做一個執行緒池,多個任務都在同一執行緒池內執行,而使用者自定義程式碼又無法控制,導致不同任務相互影響,更有甚者任務結束後資源不釋放。為保證資源隔離,將執行緒改為程式,將不同作業的任務交由不同的子程式去執行,子程式啟動時會指定額定執行資源;所有子程式由Bee統一管理,Bee不再執行具體任務,作業結束後,Bee將未退出的子程式全部強制殺死。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31542119/viewspace-2212425/,如需轉載,請註明出處,否則將追究法律責任。

相關文章