本文詳解canal的總體架構。mysql
1、總體架構
說明:sql
- server表明一個canal運行實例,對應於一個jvm
- instance對應於一個數據隊列 (1個server對應1..n個instance)
instance模塊:數據庫
- eventParser (數據源接入,模擬slave協議和master進行交互,協議解析)
- eventSink (Parser和Store連接器,進行數據過濾,加工,分發的工做)
- eventStore (數據存儲)
- metaManager (增量訂閱&消費信息管理器)
2、各模塊架構
2.1 Parser
整個parser過程大體可分爲幾步:架構
- Connection獲取上一次解析成功的位置(若是第一次啓動,則獲取初始制定的位置或者是當前數據庫的binlog位點)
- Connection創建鏈接,發生BINLOG_DUMP命令
- Mysql開始推送Binary Log
- 接收到的Binary Log經過Binlog parser進行協議解析,補充一些特定信息
- 傳遞給EventSink模塊進行數據存儲,是一個阻塞操做,直到存儲成功
- 存儲成功後,定時記錄Binary Log位置
2.2 Sink
說明:jvm
- 數據過濾:支持通配符的過濾模式,表名,字段內容等
- 數據路由/分發:解決1:n (1個parser對應多個store的模式)
- 數據歸併:解決n:1 (多個parser對應1個store)
- 數據加工:在進入store以前進行額外的處理,好比join
1 數據1:n業務 :
爲了合理的利用數據庫資源, 通常常見的業務都是按照schema進行隔離,而後在mysql上層或者dao這一層面上,進行一個數據源路由,屏蔽數據庫物理位置對開發的影響,阿里系主要是經過cobar/tddl來解決數據源路由問題。 因此,通常一個數據庫實例上,會部署多個schema,每一個schema會有由1個或者多個業務方關注。設計
2 數據n:1業務:
一樣,當一個業務的數據規模達到必定的量級後,必然會涉及到水平拆分和垂直拆分的問題,針對這些拆分的數據須要處理時,就須要連接多個store進行處理,消費的位點就會變成多份,並且數據消費的進度沒法獲得儘量有序的保證。 因此,在必定業務場景下,須要將拆分後的增量數據進行歸併處理,好比按照時間戳/全局id進行排序歸併.server
2.3 Store
目前實現了Memory內存、本地file存儲以及持久化到zookeeper以保障數據集羣共享。
Memory內存的RingBuffer設計:blog
定義了3個cursor排序
- Put : Sink模塊進行數據存儲的最後一次寫入位置
- Get : 數據訂閱獲取的最後一次提取位置
- Ack : 數據消費成功的最後一次消費位置
借鑑Disruptor的RingBuffer的實現,將RingBuffer拉直來看:隊列
實現說明:
Put/Get/Ack cursor用於遞增,採用long型存儲 buffer的get操做,經過取餘或者與操做。(與操做: cusor & (size – 1) , size須要爲2的指數,效率比較高)