Mysql資料實時同步實踐

小米運維發表於2022-12-05

關於小米內部使用的資料庫你知道多少?

背景
Mysql由於自身簡單、高效、可靠的特點,成為小米內部使用最廣泛的資料庫,但是當資料量達到千萬/億級別的時候,mysql的相關操作會變的非常遲緩;如果這時還有實時BI展示的需求,對於mysql來說是一種災難。
為了解決sql查詢慢,查不了的業務痛點,我們探索出一套完整的實時同步,即席查詢的解決方案,本文主要從實時同步的角度介紹相關工作。
早期業務藉助Sqoop將Mysql中的資料同步到Hive來進行資料分析,使用過程中也帶來了一些問題:
  • 雖然Sqoop支援增量同步但還屬於粗粒度的離線同步,無法滿足實時性的需求
  • 每次同步Sqoop以sql的方式向Mysql發出資料請求也在一定程度上對Mysql帶來一定的壓力
  • 同時Hive對資料更新的支援也相對較弱
為了更有效地連線前端業務資料系統(Mysql)和後端統計分析系統(查詢分析引擎),我們需要一套實時同步mysql資料的解決方案。
小米內部實踐
如何能夠做到資料的實時同步呢?我們想到了Mysql主從複製時使用的binlog日誌,它記錄了所有的 DDL 和 DML 語句(除了資料查詢語句select、show等),以事件形式記錄,還包含語句所執行的消耗時間
下面來看一下Mysql主從複製的原理,主要有以下幾個步驟:
  1. master(主庫)在每次準備提交事務完成資料更新前,將改變記錄到二進位制日誌(binary log)中
  2. slave(從庫)發起連線,連線到master,請求獲取指定位置的binlog檔案
  3. master建立dump執行緒,推送binlog的slave
  4. slave啟動一個I/O執行緒來讀取主庫上binary log中的事件,並記錄到slave自己的中繼日誌(relay log)中
  5. slave還會起動一個SQL執行緒,該執行緒從relay log中讀取事件並在備庫執行,完成資料同步
  6. slave記錄自己的binlog   


Mysql資料實時同步實踐
binlog記錄了Mysql資料的實時變化,是資料同步的基礎,服務需要做的就是遵守Mysql的協議,將自己偽裝成Mysql的slave來監聽業務從庫,完成資料實時同步。
結合小米內部系統特點,構建了Mysql資料同步服務–-LCSBinlog,作為一種獨立的資料接入方式整合在Talos Platform中,Talos Platform作為大資料整合的基礎解決方案,以自研訊息佇列Talos為資料匯流排,連線各種系統為主要目標,提供豐富的資料Source輸入和資料Sink輸出,並且Talos天然支援流式計算,因此業務可以充分利用Talos Platform互聯互通的特性,並結合自身的業務需求實現更加高階的業務場景。
Mysql資料實時同步實踐
上圖是Talos Platform中的整體流程架構,其中標紅部分是目前LCSBinlog在小米內部使用最廣泛的一條鏈路:Mysql --->  Talos  --->   Kudu  --->   BI,資料同步到kudu後藉助Sparksql查詢引擎為上層BI系統提供即席查詢服務,Kudu和Sparksql的整合細節可以參見往期內容:告別”紛紛擾擾”—小米OLAP服務架構演進
LCSBinlog服務的主體架構
服務一共有兩種角色
   Master :主要負責作業的排程,
   Worker: 主要完成具體的資料同步任務
在Worker上執行兩種作業:
  1. BinlogSyncJob:每一個mysql庫都會對應這樣一個Job,將binlog日誌完整地寫入到服務建立的Talos topic中
  2. MysqlSyncJob:同步歷史資料,消費binlog資料,過濾特定庫表資料實時同步至使用者配置的topic中
服務整體依賴於Zookeeper來同步服務狀態,記錄作業排程資訊和標記作業執行狀態;在kudu表中記錄作業同步進度
Mysql資料實時同步實踐
控制流程如下:
  1. Worker節點透過在Zookeeper上註冊告知自己可以被排程
  2. 透過在Zookeeper上搶佔EPHEMERAL臨時節點實現Master的HA
  3. 使用者在融合雲(Web)上註冊BinlogSource同步任務
  4. Master週期性從配置服務讀取Binlog同步作業配置
  5. Master更新Zookeeper中的排程資訊
  6. Worker節點 根據Zookeeper上的排程資訊啟動新分配任務,停止配置失效任務;作業啟動後完成資料實時同步並週期性將同步進度記錄在kudu中
  7. 服務上報監控資訊到Falcon平臺,作業異常退出傳送報警郵件
 如何保障資料正確性
>>>>

順序性

使用者配置的每一個BinlogSource 都會繫結一個Talos的topic,在進行消費的時候需要保證同一條mysql記錄操作的順序性,訊息佇列Talos是無法保證全域性訊息有序的,只能保證partition內部有序。
對於配置分庫分表或者多庫同步任務的BinlogSource,服務會根據庫表資訊進行hash,將資料寫入相應的partiton,保證同一張表的資料在一個partition中,使得下游消費資料的順序性;
對於單表同步的作業目前使用一個partition保證其資料有序。
>>>>

一致性

如何保證在作業異常退出後,作業重新啟動能夠完整地將mysql中的資料同步到下游系統,主要依賴於以下三點
  1. 服務會記錄作業同步的offset,重啟後從上次commit的offset繼續消費   
  2. Binlog資料的順序性保證了即便資料被重複消費(未commit的資料),也能對同一條記錄的操作以相同的順序執行
  3. 下游儲存系統kudu,Es ,Redis基於主鍵的操作能夠保證binlog重複回放後資料的最終一致性
應用場景  
有了這份資料我們可以做些什麼事情呢,本節例舉了幾種常見的應用場景     
>>>>

實時更新快取

業務查詢類服務往往會在mysql之上架設一個快取,減少對底層資料庫的訪問;當mysql庫資料變化時,如果快取還沒有過期那麼就會拿到過期的資料,業務期望能夠實時更新快取;
利用binlog服務,根據策略實時將資料同步到redis中,這樣就能夠保證了快取中資料有效性,減少了對資料庫的呼叫,從而提高整體效能。
Mysql資料實時同步實踐
>>>>

非同步處理,系統解耦

隨著業務的發展,同一份資料可能有不同的分析用途,資料成功寫入到mysql的同時也需要被同步到其他系統;如果用同步的方式處理,一方面拉長了一次事務整個流程,另一方面系統間也會相互影響
資料在mysql中操作成功後才會記錄在binlog中,保證下游處理到時的一致性;使用binlog服務完成資料的下發,有助於系統的解耦
關於非同步處理,系統解耦在訊息佇列價值思考一文中有更深入的解讀 
>>>>

即席查詢的BI系統

就如文章開篇提到的,mysql在一定場景下的效能瓶頸,mysql資料同步到kudu後可以藉助sparksql完成效能的提升
因為同樣是sql介面,對使用者的切換成本也是較低的,資料同步到更適合的儲存中進行查詢,也能夠避免因大查詢而對原mysql庫其他查詢的影響
目前小米內部穩定執行3000+的同步作業,使用binlog服務同步資料到kudu中;小米內部BI明星產品XDATA藉助整套同步流程很好地支援了運營、sql分析同學日常統計分析的需求
如何使用Binlog資料
使用者接入資料的時候要求mysql庫開啟binlog日誌格式必須為Row模式:記錄的是每一行記錄的每個欄位變化前後的值,雖然會造成binlog資料量的增多,但是能夠確保每一條記錄準確性,避免資料同步不一致情況的出現
最終透過監聽binlog日誌,LCSBinlog服務將資料轉換成如下的資料結構,寫入使用者註冊的Topic中, 目前Sink服務使用SparkStreaming實時轉儲資料到kudu中,後續也將逐步遷移到Flink上以提升資源利用、降低延遲
Mysql資料實時同步實踐
業務使用者也可以根據我們提供的資料格式,實時消費Talos資料以實現更復雜的業務邏輯,下表為每一種資料操作,是否儲存修改前後的列表    
Mysql資料實時同步實踐
 疑難雜症
下面分享2個上線後遇到的有趣問題
>>>>

資料不一致問題,業務使用唯一索引

業務接入一段時間後, 發現部分表會偶爾存在kudu表的資料條目數多於同步的mysql表的資料條目數,我們將多出來的資料與mysql產生的binlog日誌經過一一對比,發現使用者在mysql表中設定了唯一索引,透過唯一索引修改了主鍵,而kudu中的資料是透過主鍵標識或更新一條記錄的,於是update操作變成了insert操作,這就造成了原來的1條記錄變成了2條。
解決辦法:對於這種型別的表,LCSBinlog服務會把一次Update操作轉換成一條Delete資料和一條Insert資料
>>>>

Full Dump同步歷史資料時,客戶端超時

服務剛上線的時候,透過jdbc 執行sql的方式完成全量歷史資料的同步,在同步的過程中會發現dump任務會卡頓很長時間才會返回結果,當資料量很大會出現超時同步失敗的情況,會造成資料的延遲。調研後發現使用mysql官方jdbc在客戶端查詢資料的時候,預設為從伺服器一次取出所有資料放在客戶端記憶體中,fetch size引數不起作用,當一條SQL返回資料量較大時可能會出現OOM
解決辦法:當statement設定以下屬性時,採用的是流資料接收方式,每次只從伺服器接收部份資料,直到所有資料處理完畢。最佳化後歷史資料同步穩定執行,對mysql端的壓力也很小        Mysql資料實時同步實踐    

總結

MySQL以Binlog日誌的方式記錄資料變化,基於流式資料的Change Data Caputre (CDC)機制實現了LCSBinlog服務,

本文主要對LCSBinlog的服務架構、應用場景以及在小米內部的實踐經驗進行了介紹,也和大家分享了我們實際中遇到的問題和解決方案,希望能夠幫助到大家理解服務的原理,帶來啟發,也歡迎大家和我們一起交流。

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

相關文章