數(shù)據(jù)庫增量訂閱中間件--canal

背景


工作中有很多場景意蛀,比如某些場景為了加快接口響應速度,加入緩存夺饲;實現(xiàn)數(shù)據(jù)持久化的同時奸汇,還要滿足搜索引擎,需要一份數(shù)據(jù)多處存儲等往声。思考:以上場景均為一份數(shù)據(jù)多份存儲擂找,這種情況下如何實現(xiàn)數(shù)據(jù)的同步,且保證數(shù)據(jù)一致性浩销?
無可厚非贯涎,可將數(shù)據(jù)的多寫,嵌入在業(yè)務代碼里慢洋。但有些場景無權限侵入項目代碼塘雳;且這種實現(xiàn)方式存在代碼片段到處分布、事務無法保障等問題且警。由此粉捻,是否可將數(shù)據(jù)變更的訂閱、同步抽象獨立出來斑芜?canal即是這種思想下的產物組件之一肩刃。抽象業(yè)務實現(xiàn)如下圖:


數(shù)據(jù)訂閱業(yè)務流程

目錄

目錄

canal是什么


數(shù)據(jù)庫增量日志解析、訂閱杏头、消費盈包。阿里開源數(shù)據(jù)庫訂閱組件

使用場景


● 數(shù)據(jù)庫鏡像
● 數(shù)據(jù)庫實時備份
● 索引構建和實時維護(拆分異構索引、倒排索引等)
● 業(yè)務 cache 緩存刷新
● 帶業(yè)務邏輯的增量數(shù)據(jù)處理


canal工作原理

數(shù)據(jù)庫主從同步

canal 模擬 MySQL slave 的交互協(xié)議醇王,偽裝自己為 MySQL slave 呢燥,向 MySQL master 發(fā)送dump 協(xié)議
MySQL master 收到 dump 請求,開始推送 binary log 給 slave (即 canal )
canal 解析 binary log 對象(原始為 byte 流)


canal實戰(zhàn)

1.服務端

1寓娩、開啟mysql的binlog寫入功能叛氨,并且配置binlog模式為row
2呼渣、分配slave角色賬號
以上可聯(lián)系DBA操作
3、搭建高可用zookeeper集群
4寞埠、下載部署包屁置、解壓
wget http://canal4mysql.googlecode.com/files/canal.deployer-1.0.1.tar.gz

解壓列表

5、配置
/opt/soft/canal/canal.deployer-1.0.24/conf/canal.properties


canal.properties

/opt/soft/canal/canal.deployer-1.0.24/conf/huangye-evaluation/instance.properties


instance.properties

也可搭建canal-admin界面化部署
6仁连、啟動
sh /opt/soft/canal/canal.deployer-1.0.24/bin/startup.sh
日志:
tail -f /opt/soft/canal/canal.deployer-1.0.24/logs/canal/canal.log


2.客戶端


業(yè)務代碼

協(xié)議解析

3.協(xié)議格式

Entry
Header
        logfileName [binlog文件名]
        logfileOffset [binlog position]
        executeTime [binlog里記錄變更發(fā)生的時間戳]
        schemaName [數(shù)據(jù)庫實例]
        tableName [表名]
        eventType [insert/update/delete類型]
        entryType   [事務頭BEGIN/事務尾END/數(shù)據(jù)ROWDATA]
        storeValue  [byte數(shù)據(jù),可展開蓝角,對應的類型為RowChange]
RowChange
         isDdl       [是否是ddl變更操作,比如create table/drop table]
         sql     [具體的ddl sql]
         rowDatas    [具體insert/update/delete的變更數(shù)據(jù)饭冬,可為多條使鹅,1個binlog 
         event事件可對應多條變更,比如批處理]
         beforeColumns [Column類型的數(shù)組]
         afterColumns [Column類型的數(shù)組]
Column
          index       [column序號]
          sqlType     [jdbc type]
          name        [column name]
          isKey       [是否為主鍵]
          updated     [是否發(fā)生過變更]
          isNull      [值是否為null]
          value       [具體的內容昌抠,注意為文本]

canal源碼解讀

canal源碼

1.基礎模塊

● common
公共工具模塊一些util患朱、另外還有canal的server、client啟動關閉相關的生命周期的基礎接口定義炊苫。
● protocol
協(xié)議模塊麦乞,主要是canal-sever和canal-client之間的信息傳輸序列化方式,采用protocobuffer序列化劝评。
● driver
封裝數(shù)據(jù)庫建立連接姐直,獲取并解析二進制流的方法。獲取原始的二進制流蒋畜,因為單純的jdbc無法滿足獲取二進制日志声畏,所以他自己封裝,又因為未來可能支持mix姻成,statement模式所以查庫的邏輯也一起封裝了插龄。
● dbsync
定義了大量的event類對應各種不同格式的二進制日志。
● filter
用于canal-server過濾掉不想關注的某些科展,某個表均牢,某個字段,的二進制日志等等才睹。還可以可以過濾是否處理ddl徘跪、dml等等。
● sink
調用filter進行過濾琅攘,將結果交給store進行緩存
● store
維護一個ringbuffer隊列將解析后的二進制日志結果緩存垮庐,提供給下游消費。為了消息消費可靠坞琴,使用ack方式哨查;為了提高性能,使用ringbuffer剧辐,消息投遞方面是可靠的寒亥,順序的邮府,數(shù)組比鏈表快,不進行垃圾回收
● meta
定義了各種元數(shù)據(jù)的修改溉奕,查詢操作挟纱,但是修改時可能涉及到原子性操作,需要在對應的store腐宋、sink等模塊兒里加鎖等方式操作。
● parser
調用dbsync解析二進制日志檀轨,并且維護二進制日志的位點胸竞,下次請求二進制日志時從對應的位點開始。位點分為本地位點儲存参萄,集群位點儲存卫枝。位點有多種實現(xiàn):canalconfspring下
base:基本的內存存儲位點
default:基于zookeeper位點存儲
file:本地存儲位點
group:為了分庫分表設計的位點存儲,可以支持配置多個數(shù)據(jù)源讹挎,但是微端存儲在內存不建議使用
● instance
調用底層模塊校赤,串起來整個流程。一個server對應多個instance筒溃,每個instance里有自己的parser马篮、store、sink怜奖。在代碼里叫instance浑测,在配置文件instance也叫destination。一個server對應多個instance歪玲,每個instance里有自己的parser迁央、store、sink滥崩。在代碼里叫instance岖圈,在配置文件instance也叫destination。一個instance封裝了一個連接數(shù)據(jù)庫的實例钙皮,一個client的注冊蜂科,zookeeper的交互。
● server
canal-sever的運行實例短条,抽象出2種實現(xiàn)崇摄,基于嵌入式和jetty獨立部署的方式,抽象出一種對接kafka的實現(xiàn)慌烧。


2.可獨立部署模塊

● deployer
模擬主從協(xié)議逐抑,從主庫拉取二進制日志,解析二進制日志屹蚊,并且將解析后的結果存儲在本地隊列厕氨,提供給下游消費进每,以后稱之為canal-server。
● example
從canal-server獲取解析后的二進制日志命斧,進行定制化處理田晚,這個工程里可以放一些定制化消費canal-server消息的代碼,以后稱之為canal-client国葬。
● canal-admin
由于canal-server負責連接mysql贤徒,解析二進制日志,canal-server不進行任何定制化的業(yè)務編碼汇四,僅需簡單配置接奈,因此canal-server的工作更偏向于運維。canal-admin就是用于運維在線部署配置canal-server的通孽。


3.對外支持

● client
是連接client-server的組件包序宦,通過這個包可以連接到客戶端上面的example就是依賴了client這個模塊的一個demo。
● docker
對接docker背苦,用于支持在docker里面部署canal-server。
● prometheus
對接監(jiān)控秕噪,prometheus相當于一個鍵值對的數(shù)據(jù)庫巢价,canal-server每間隔一段時間將prometheus格式的信息通過http端口傳遞給prometheus數(shù)據(jù)庫。通過這些數(shù)據(jù)可以監(jiān)控canal-server的情況固阁。


canal架構

1.架構


canal架構.jpeg

說明:
server代表一個canal運行實例壤躲,對應于一個jvm
instance對應于一個數(shù)據(jù)隊列(1個server對應1..n個instance)


2.canal業(yè)務架構


canal業(yè)務架構

EventParser:數(shù)據(jù)源接入,模擬slave協(xié)議和master進行交互备燃,協(xié)議解析
EventSink:Parser和Store連接器碉克,主要進行數(shù)據(jù)過濾,加工并齐,分發(fā)的工作
EventStore:負責存儲
MemoryMetaManager:增量訂閱和消費信息管理器


3.EventParse


EventParse

整個parser過程大致可分為以下幾步:

  1. Connection獲取上一次解析成功的log position(如果是第一次啟動漏麦,則獲取初始指定的位置或者是當前數(shù)據(jù)庫的binlog log position)
  2. Connection建立連接,向MySQL master發(fā)送BINLOG_DUMP請求
  3. MySQL開始推送binary Log接收到的binary Log
  4. 通過BinlogParser進行協(xié)議解析朋蔫,補充一些特定信息测垛。如補充字段名字捏膨、字段類型、主鍵信息、unsigned類型處理等
  5. 將解析后的數(shù)據(jù)傳入到EventSink組件進行數(shù)據(jù)存儲(這是一個阻塞操作链快,直到存儲成功)
  6. 定時記錄binary Log位置誉己,以便重啟后繼續(xù)進行增量訂閱
    如果需要同步的master宕機,可以從它的其他slave節(jié)點繼續(xù)同步binlog日志域蜗,避免單點故障巨双。

4.Event Sink設計:


Event Sink設計

EventSink主要作用如下:
數(shù)據(jù)過濾:支持通配符的過濾模式,表名霉祸,字段內容等
數(shù)據(jù)路由/分發(fā):解決1:n(1個parser對應多個store的模式)
數(shù)據(jù)歸并:解決n:1(多個parser對應1個store)
數(shù)據(jù)加工:在進入store之前進行額外的處理筑累,比如join
數(shù)據(jù)1:n業(yè)務
為了合理的利用數(shù)據(jù)庫資源, 一般常見的業(yè)務都是按照schema進行隔離脉执,然后在MySQL上層或者dao這一層面上,進行一個數(shù)據(jù)源路由戒劫,屏蔽數(shù)據(jù)庫物理位置對開發(fā)的影響半夷。所以,一般一個數(shù)據(jù)庫實例上迅细,會部署多個schema巫橄,每個schema會有由1個或者多個業(yè)務方關注。
數(shù)據(jù)n:1業(yè)務
同樣茵典,當一個業(yè)務的數(shù)據(jù)規(guī)模達到一定的量級后湘换,必然會涉及到水平拆分和垂直拆分的問題,針對這些拆分的數(shù)據(jù)需要處理時统阿,就需要鏈接多個store進行處理彩倚,消費的位點就會變成多份,而且數(shù)據(jù)消費的進度無法得到盡可能有序的保證扶平。所以帆离,在一定業(yè)務場景下,需要將拆分后的增量數(shù)據(jù)進行歸并處理结澄,比如按照時間戳/全局id進行排序歸并哥谷。


5.Event Store設計:

支持多種存儲模式,比如Memory內存模式麻献。采用內存環(huán)裝的設計來保存消息们妥,借鑒了Disruptor的RingBuffer的實現(xiàn)思路。
RingBuffer設計


Event Store設計

定義了3個cursor:
put:Sink模塊進行數(shù)據(jù)存儲的最后一次寫入位置(同步寫入數(shù)據(jù)的cursor)
get:數(shù)據(jù)訂閱獲取的最后一次提取位置(同步獲取的數(shù)據(jù)的cursor)
ack:數(shù)據(jù)消費成功的最后一次消費位置
借鑒Disruptor的RingBuffer的實現(xiàn)勉吻,將RingBuffer拉直來看:


水平結構

實現(xiàn)說明:

  1. put/get/ack cursor用于遞增监婶,采用long型存儲。三者之間的關系為put>=get>=ack
  2. buffer的get操作齿桃,通過取余或者&操作压储。(&操作:cusor & (size - 1) , size需要為2的指數(shù)鲜漩,效率比較高)

6.Instance設計


Instance設計

instance代表了一個實際運行的數(shù)據(jù)隊列,包括了EventPaser集惋、EventSink孕似、EventStore等組件。抽象了CanalInstanceGenerator刮刑,主要是考慮配置的管理方式:
manager方式:和你自己的內部web console/manager系統(tǒng)進行對接喉祭。(目前主要是公司內部使用)
spring方式:基于spring xml + properties進行定義,構建spring配置雷绢。


7.Server設計


Server

server代表了一個canal運行實例泛烙,為了方便組件化使用,特意抽象了Embeded(嵌入式)/Netty(網絡訪問)的兩種實現(xiàn)翘紊。

8.增量訂閱/消費設計


訂閱/消費

針對上述的補充說明:
1.可以提供數(shù)據(jù)庫變更前和變更后的字段內容蔽氨,針對binlog中沒有的name、isKey等信息進行補全
2.可以提供ddl的變更語句


9.canal HA機制

Canal的HA實現(xiàn)機制是依賴zookeeper實現(xiàn)的帆疟,主要分為Canal server和Canal client的HA鹉究。

Canal server:為了減少對MySQL dump的請求,不同server上的instance要求同一時間只能有一個處于running狀態(tài)踪宠,其他的處于standby狀態(tài)自赔。
Canal client:為了保證有序性,一份instance同一時間只能由一個Canal client進行get/ack/rollback操作柳琢,否則客戶端接收無法保證有序绍妨。


10.Canal Server HA架構


csha

大致步驟:

  1. Canal server要啟動某個Canal instance時都先向Zookeeper進行一次嘗試啟動判斷 (實現(xiàn):創(chuàng)建EPHEMERAL節(jié)點,誰創(chuàng)建成功就允許誰啟動)
  2. 創(chuàng)建Zookeeper節(jié)點成功后柬脸,對應的Canal server就啟動對應的Canal instance他去,沒有創(chuàng)建成功的Canal instance就會處于standby狀態(tài)
  3. 一旦Zookeeper發(fā)現(xiàn)Canal server A創(chuàng)建的節(jié)點消失后,立即通知其他的Canal server再次進行步驟1的操作倒堕,重新選出一個Canal server啟動instance
  4. Canal client每次進行connect時孤页,會首先向Zookeeper詢問當前是誰啟動了Canal instance,然后和其建立鏈接涩馆,一旦鏈接不可用行施,會重新嘗試connect
    Canal Client的方式和Canal server方式類似,也是利用Zookeeper的搶占EPHEMERAL節(jié)點的方式進行控制魂那。

踩過的坑

1.消費要冪等

canal-server在請求二進制日志時需要得到上次請求到哪個位置即位點蛾号,位點canal又分為了兩種方式持久化。
a涯雅、本地文件位點:默認的存儲位點方式鲜结;將位點記錄在緩存中,定時刷新到本地的meta.log文件中。
b精刷、集群存儲位點:將位點存儲于緩存中拗胜,定時刷到zookeeper的臨時節(jié)點里,多個節(jié)點間可以共享位點
均需注意消費要冪等怒允。


2.拷貝一個已有的server埂软,需要刪掉meta.log和修改tsdb配置

meta.log是本地存儲位點方式記錄的位點信息,因此拷貝一個server做部署時要刪掉舊的位點信息文件纫事,否則server啟動不起來
tsdb文件是canal為了加快解析二進制日志勘畔,將表的元數(shù)據(jù)存儲到了本地,因此拷貝一個server時這個文件還是舊的會導致server能啟動丽惶,但是解析二進制日志失敗炫七。


3.建議不要使用tsdb,默認是開啟的钾唬,而且默認緩存15天

為了提升解析二進制的速度万哪,canal將表結構信息進行了tsdb緩存,因此當表結構發(fā)生變化時緩存的表結構可能導致解析失敗抡秆。禁用掉tsdb緩存:
canal.instance.tsdb.enable = false


4.消費注意多線程操作

canal為了保證消息順序消費奕巍,一個canal-server只能有一個canal-client與之對應。對應到api就是getWithoutAck這些api琅轧,如果多線程操作這些api會引起非順序性消費

5.數(shù)據(jù)庫遷移伍绳,binlog同步中斷找不到位點信息踊挠,server卡住不消費

解決:
1) 確認事故時間點乍桂,修改配置從事故點開始繼續(xù)消費
2) 刪除meta.log文件或者刪除zookeeper記錄位置的臨時節(jié)點(不同版本記錄位置方式不同),從當前時刻的 binlog 開始消費效床,手動補充事故時間段遺漏數(shù)據(jù)
以上兩種方式均需手動重啟

6.binlog模式為row

開啟其他模式睹酌,導致filter規(guī)則失效,或者binlog解析eventType類型出錯剩檀。如Query解析為DML

總結&思考


可使用canal組件的場景憋沿,可否用業(yè)務+MQ中間件,業(yè)務雙寫模式實現(xiàn)沪猴?
業(yè)務+MQ中間件
優(yōu)點:實現(xiàn)簡單辐啄,不需要引入過多組件;維護成本低
缺點:不能保證數(shù)據(jù)實時性运嗜、一致性壶辜、業(yè)務控制事務、相同代碼片段分布各處担租、與業(yè)務耦合
canal
優(yōu)點:可保證數(shù)據(jù)實時性砸民、一致性、解藕
缺點:單獨部署,增加維護成本
具體使用哪種方案岭参,可根據(jù)具體業(yè)務場景選擇合適的方案

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末反惕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子演侯,更是在濱河造成了極大的恐慌姿染,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,686評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚌本,死亡現(xiàn)場離奇詭異盔粹,居然都是意外死亡,警方通過查閱死者的電腦和手機程癌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評論 3 385
  • 文/潘曉璐 我一進店門舷嗡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嵌莉,你說我怎么就攤上這事进萄。” “怎么了锐峭?”我有些...
    開封第一講書人閱讀 158,160評論 0 348
  • 文/不壞的土叔 我叫張陵中鼠,是天一觀的道長。 經常有香客問我沿癞,道長援雇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,736評論 1 284
  • 正文 為了忘掉前任椎扬,我火速辦了婚禮惫搏,結果婚禮上,老公的妹妹穿的比我還像新娘蚕涤。我一直安慰自己筐赔,他們只是感情好,可當我...
    茶點故事閱讀 65,847評論 6 386
  • 文/花漫 我一把揭開白布揖铜。 她就那樣靜靜地躺著茴丰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪天吓。 梳的紋絲不亂的頭發(fā)上贿肩,一...
    開封第一講書人閱讀 50,043評論 1 291
  • 那天,我揣著相機與錄音龄寞,去河邊找鬼汰规。 笑死,一個胖子當著我的面吹牛萄焦,可吹牛的內容都是我干的控轿。 我是一名探鬼主播冤竹,決...
    沈念sama閱讀 39,129評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼茬射!你這毒婦竟也來了鹦蠕?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,872評論 0 268
  • 序言:老撾萬榮一對情侶失蹤在抛,失蹤者是張志新(化名)和其女友劉穎钟病,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刚梭,經...
    沈念sama閱讀 44,318評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡肠阱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,645評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了朴读。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屹徘。...
    茶點故事閱讀 38,777評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖衅金,靈堂內的尸體忽然破棺而出噪伊,到底是詐尸還是另有隱情,我是刑警寧澤氮唯,帶...
    沈念sama閱讀 34,470評論 4 333
  • 正文 年R本政府宣布鉴吹,位于F島的核電站,受9級特大地震影響惩琉,放射性物質發(fā)生泄漏豆励。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,126評論 3 317
  • 文/蒙蒙 一瞒渠、第九天 我趴在偏房一處隱蔽的房頂上張望良蒸。 院中可真熱鬧,春花似錦在孝、人聲如沸诚啃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至和橙,卻和暖如春仔燕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背魔招。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評論 1 267
  • 我被黑心中介騙來泰國打工晰搀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人办斑。 一個月前我還...
    沈念sama閱讀 46,589評論 2 362
  • 正文 我出身青樓外恕,卻偏偏與公主長得像杆逗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鳞疲,可洞房花燭夜當晚...
    茶點故事閱讀 43,687評論 2 351

推薦閱讀更多精彩內容