中介軟體---Binlog傳輸同步---Canal
背景
早期,阿里巴巴B2B公司因為存在杭州和美國雙機房部署,存在跨機房同步的業務需求。不過早期的資料庫同步業務,主要是基於trigger的方式獲取增量變更,不過從2010年開始,阿里系公司開始逐步的嘗試基於資料庫的日誌解析,獲取增量變更進行同步,由此衍生出了增量訂閱&消費的業務,從此開啟了一段新紀元。ps. 目前內部使用的同步,已經支援mysql5.x和oracle部分版本的日誌解析
基於日誌增量訂閱&消費支援的業務:
- 資料庫映象
- 資料庫實時備份
- 多級索引 (賣家和買家各自分庫索引)
- search build
- 業務cache重新整理
- 價格變化等重要業務訊息
專案介紹
名稱:canal [kə'næl]
譯意: 水道/管道/溝渠
語言: 純java開發
定位: 基於資料庫增量日誌解析,提供增量資料訂閱&消費,目前主要支援了mysql
工作原理
mysql主備複製實現
從上層來看,複製分成三步:
- master將改變記錄到二進位制日誌(binary log)中(這些記錄叫做二進位制日誌事件,binary log events,可以通過show binlog events進行檢視);
- slave將master的binary log events拷貝到它的中繼日誌(relay log);
- slave重做中繼日誌中的事件,將改變反映它自己的資料。
canal的工作原理:
原理相對比較簡單:
- canal模擬mysql slave的互動協議,偽裝自己為mysql slave,向mysql master傳送dump協議
- mysql master收到dump請求,開始推送binary log給slave(也就是canal)
- canal解析binary log物件(原始為byte流)
架構
說明:
- server代表一個canal執行例項,對應於一個jvm
- instance對應於一個資料佇列 (1個server對應1..n個instance)
instance模組:
- eventParser (資料來源接入,模擬slave協議和master進行互動,協議解析)
- eventSink (Parser和Store連結器,進行資料過濾,加工,分發的工作)
- eventStore (資料儲存)
- metaManager (增量訂閱&消費資訊管理器)
知識科普
mysql的Binlay Log介紹
- http://dev.mysql.com/doc/refman/5.5/en/binary-log.html
- http://www.taobaodba.com/html/474_mysqls-binary-log_details.html
簡單點說:
- mysql的binlog是多檔案儲存,定位一個LogEvent需要通過binlog filename + binlog position,進行定位
- mysql的binlog資料格式,按照生成的方式,主要分為:statement-based、row-based、mixed。
Java程式碼- mysql> show variables like 'binlog_format';
- +---------------+-------+
- | Variable_name | Value |
- +---------------+-------+
- | binlog_format | ROW |
- +---------------+-------+
- 1 row in set (0.00 sec)
目前canal只能支援row模式的增量訂閱(statement只有sql,沒有資料,所以無法獲取原始的變更日誌)
EventParser設計
大致過程:
整個parser過程大致可分為幾步:
- Connection獲取上一次解析成功的位置 (如果第一次啟動,則獲取初始指定的位置或者是當前資料庫的binlog位點)
- Connection建立連結,傳送BINLOG_DUMP指令
// 0. write command number
// 1. write 4 bytes bin-log position to start at
// 2. write 2 bytes bin-log flags
// 3. write 4 bytes server id of the slave
// 4. write bin-log file name - Mysql開始推送Binaly Log
- 接收到的Binaly Log的通過Binlog parser進行協議解析,補充一些特定資訊
// 補充欄位名字,欄位型別,主鍵資訊,unsigned型別處理 - 傳遞給EventSink模組進行資料儲存,是一個阻塞操作,直到儲存成功
- 儲存成功後,定時記錄Binaly Log位置
mysql的Binlay Log網路協議:
說明:
- 圖中的協議4byte header,主要是描述整個binlog網路包的length
- binlog event structure,詳細資訊請參考: http://dev.mysql.com/doc/internals/en/binary-log.html
EventSink設計
說明:
- 資料過濾:支援萬用字元的過濾模式,表名,欄位內容等
- 資料路由/分發:解決1:n (1個parser對應多個store的模式)
- 資料歸併:解決n:1 (多個parser對應1個store)
- 資料加工:在進入store之前進行額外的處理,比如join
資料1:n業務
為了合理的利用資料庫資源, 一般常見的業務都是按照schema進行隔離,然後在mysql上層或者dao這一層面上,進行一個資料來源路由,遮蔽資料庫物理位置對開發的影響,阿里系主要是通過cobar/tddl來解決資料來源路由問題。
所以,一般一個資料庫例項上,會部署多個schema,每個schema會有由1個或者多個業務方關注
資料n:1業務
同樣,當一個業務的資料規模達到一定的量級後,必然會涉及到水平拆分和垂直拆分的問題,針對這些拆分的資料需要處理時,就需要連結多個store進行處理,消費的位點就會變成多份,而且資料消費的進度無法得到儘可能有序的保證。
所以,在一定業務場景下,需要將拆分後的增量資料進行歸併處理,比如按照時間戳/全域性id進行排序歸併.
EventStore設計
- 1. 目前僅實現了Memory記憶體模式,後續計劃增加本地file儲存,mixed混合模式
- 2. 借鑑了Disruptor的RingBuffer的實現思路
RingBuffer設計:
定義了3個cursor
- Put : Sink模組進行資料儲存的最後一次寫入位置
- Get : 資料訂閱獲取的最後一次提取位置
- Ack : 資料消費成功的最後一次消費位置
借鑑Disruptor的RingBuffer的實現,將RingBuffer拉直來看:
實現說明:
- Put/Get/Ack cursor用於遞增,採用long型儲存
- buffer的get操作,通過取餘或者與操作。(與操作: cusor & (size - 1) , size需要為2的指數,效率比較高)
Instance設計
instance代表了一個實際執行的資料佇列,包括了EventPaser,EventSink,EventStore等元件。
抽象了CanalInstanceGenerator,主要是考慮配置的管理方式:
- manager方式: 和你自己的內部web console/manager系統進行對接。(目前主要是公司內部使用)
- spring方式:基於spring xml + properties進行定義,構建spring配置.
Server設計
server代表了一個canal的執行例項,為了方便元件化使用,特意抽象了Embeded(嵌入式) / Netty(網路訪問)的兩種實現
- Embeded : 對latency和可用性都有比較高的要求,自己又能hold住分散式的相關技術(比如failover)
- Netty : 基於netty封裝了一層網路協議,由canal server保證其可用性,採用的pull模型,當然latency會稍微打點折扣,不過這個也視情況而定。(阿里系的notify和metaq,典型的push/pull模型,目前也逐步的在向pull模型靠攏,push在資料量大的時候會有一些問題)
增量訂閱/消費設計
具體的協議格式,可參見:CanalProtocol.proto
get/ack/rollback協議介紹:
- Message getWithoutAck(int batchSize),允許指定batchSize,一次可以獲取多條,每次返回的物件為Message,包含的內容為:
a. batch id 唯一標識
b. entries 具體的資料物件,對應的資料物件格式:EntryProtocol.proto - void rollback(long batchId),顧命思議,回滾上次的get請求,重新獲取資料。基於get獲取的batchId進行提交,避免誤操作
- void ack(long batchId),顧命思議,確認已經消費成功,通知server刪除資料。基於get獲取的batchId進行提交,避免誤操作
canal的get/ack/rollback協議和常規的jms協議有所不同,允許get/ack非同步處理,比如可以連續呼叫get多次,後續非同步按順序提交ack/rollback,專案中稱之為流式api.
流式api設計的好處:
- get/ack非同步化,減少因ack帶來的網路延遲和操作成本 (99%的狀態都是處於正常狀態,異常的rollback屬於個別情況,沒必要為個別的case犧牲整個效能)
- get獲取資料後,業務消費存在瓶頸或者需要多程式/多執行緒消費時,可以不停的輪詢get資料,不停的往後傳送任務,提高並行化. (作者在實際業務中的一個case:業務資料消費需要跨中美網路,所以一次操作基本在200ms以上,為了減少延遲,所以需要實施並行化)
流式api設計:
- 每次get操作都會在meta中產生一個mark,mark標記會遞增,保證執行過程中mark的唯一性
- 每次的get操作,都會在上一次的mark操作記錄的cursor繼續往後取,如果mark不存在,則在last ack cursor繼續往後取
- 進行ack時,需要按照mark的順序進行數序ack,不能跳躍ack. ack會刪除當前的mark標記,並將對應的mark位置更新為last ack cusor
- 一旦出現異常情況,客戶端可發起rollback情況,重新置位:刪除所有的mark, 清理get請求位置,下次請求會從last ack cursor繼續往後取
資料物件格式:EntryProtocol.proto
Java程式碼
- Entry
- Header
- logfileName [binlog檔名]
- logfileOffset [binlog position]
- executeTime [發生的變更]
- schemaName
- tableName
- eventType [insert/update/delete型別]
- entryType [事務頭BEGIN/事務尾END/資料ROWDATA]
- storeValue [byte資料,可展開,對應的型別為RowChange]
- RowChange
- isDdl [是否是ddl變更操作,比如create table/drop table]
- sql [具體的ddl sql]
- rowDatas [具體insert/update/delete的變更資料,可為多條,1個binlog event事件可對應多條變更,比如批處理]
- beforeColumns [Column型別的陣列]
- afterColumns [Column型別的陣列]
- Column
- index
- sqlType [jdbc type]
- name [column name]
- isKey [是否為主鍵]
- updated [是否發生過變更]
- isNull [值是否為null]
- value [具體的內容,注意為文字]
說明:
- 可以提供資料庫變更前和變更後的欄位內容,針對binlog中沒有的name,isKey等資訊進行補全
- 可以提供ddl的變更語句
HA機制設計
canal的ha分為兩部分,canal server和canal client分別有對應的ha實現
- canal server: 為了減少對mysql dump的請求,不同server上的instance要求同一時間只能有一個處於running,其他的處於standby狀態.
- canal client: 為了保證有序性,一份instance同一時間只能由一個canal client進行get/ack/rollback操作,否則客戶端接收無法保證有序。
整個HA機制的控制主要是依賴了zookeeper的幾個特性,watcher和EPHEMERAL節點(和session生命週期繫結),可以看下我之前zookeeper的相關文章。
Canal Server:
大致步驟:
- canal server要啟動某個canal instance時都先向zookeeper進行一次嘗試啟動判斷 (實現:建立EPHEMERAL節點,誰建立成功就允許誰啟動)
- 建立zookeeper節點成功後,對應的canal server就啟動對應的canal instance,沒有建立成功的canal instance就會處於standby狀態
- 一旦zookeeper發現canal server A建立的節點消失後,立即通知其他的canal server再次進行步驟1的操作,重新選出一個canal server啟動instance.
- canal client每次進行connect時,會首先向zookeeper詢問當前是誰啟動了canal instance,然後和其建立連結,一旦連結不可用,會重新嘗試connect.
Canal Client的方式和canal server方式類似,也是利用zokeeper的搶佔EPHEMERAL節點的方式進行控制.
最後
專案的程式碼: https://github.com/alibabatech/canal
這裡給出瞭如何快速啟動Canal Server和Canal Client的例子,如有問題可隨時聯絡
Quick Start
Client Example
Reference
相關文章
- 中介軟體---Binlog傳輸同步---Maxwell
- 開源 | MySQL資料傳輸中介軟體—DTLEMySql
- 實戰!Spring Boot 整合 阿里開源中介軟體 Canal 實現資料增量同步!Spring Boot阿里
- Redis中介軟體與Web中介軟體RedisWeb
- 同步傳輸字串字串
- 中介軟體之訊息中介軟體-pulsar
- canal資料同步
- 訊息中介軟體—RocketMQ訊息傳送MQ
- laravel11:中介軟體傳遞引數Laravel
- 用canal監控binlog並實現mysql定製同步資料的功能MySql
- 開源基於Canal的開源增量資料訂閱&消費中介軟體
- 優雅的redux非同步中介軟體 redux-effectRedux非同步
- 資料同步利器 - canal
- 鐳速傳輸,大檔案傳輸軟體的快速通道
- ThinkPHP 中介軟體PHP
- redux中介軟體Redux
- golang 中介軟體Golang
- 中介軟體整理
- django中介軟體Django
- Laravel 中介軟體Laravel
- Django——中介軟體Django
- MySQL中介軟體MySql
- 中介軟體-NginxNginx
- 中介軟體漏洞
- Koa和Express的非同步中介軟體解決辦法Express非同步
- Redux 入門教程(2):中介軟體與非同步操作Redux非同步
- Redux 入門教程(二):中介軟體與非同步操作Redux非同步
- 訊息中介軟體Notify和MetaQ-阿里中介軟體阿里
- 自定義 ocelot 中介軟體輸出自定義錯誤資訊
- 大檔案傳輸軟體的優勢有哪些?-鐳速傳輸
- 什麼是中介軟體?Linux常用中介軟體都有哪些?Linux
- 監聽MySQL的binlog日誌工具分析:CanalMySql
- 安全設計:加速傳輸軟體鐳速傳輸安全技術解讀
- MySQL中介軟體--ProxySQLMySql
- websocket gateway 中介軟體WebGateway
- 理解Redux中介軟體Redux
- golang http 中介軟體GolangHTTP
- Django-中介軟體Django