阿里開源Canal--①簡介

canal是阿里巴巴旗下的一款開源項目,純Java開發(fā)糯笙”岽裕基于數(shù)據(jù)庫增量日志解析,提供增量數(shù)據(jù)訂閱&消費给涕,目前主要支持了MySQL(也支持mariaDB)豺憔。

背景

早期,阿里巴巴B2B公司因為存在杭州和美國雙機房部署够庙,存在跨機房同步的業(yè)務(wù)需求恭应。不過早期的數(shù)據(jù)庫同步業(yè)務(wù),主要是基于trigger的方式獲取增量變更耘眨,不過從2010年開始昼榛,阿里系公司開始逐步的嘗試基于數(shù)據(jù)庫的日志解析,獲取增量變更進行同步剔难,由此衍生出了增量訂閱&消費的業(yè)務(wù)胆屿,從此開啟了一段新紀元。ps. 目前內(nèi)部使用的同步偶宫,已經(jīng)支持mysql5.x和oracle部分版本的日志解析

基于日志增量訂閱&消費支持的業(yè)務(wù):

  1. 數(shù)據(jù)庫鏡像
  2. 數(shù)據(jù)庫實時備份
  3. 多級索引 (賣家和買家各自分庫索引)
  4. search build
  5. 業(yè)務(wù)cache刷新
  6. 價格變化等重要業(yè)務(wù)消息

項目介紹

名稱:canal [k?'n?l]

譯意: 水道/管道/溝渠

語言: 純java開發(fā)

定位: 基于數(shù)據(jù)庫增量日志解析非迹,提供增量數(shù)據(jù)訂閱&消費,目前主要支持了mysql

關(guān)鍵詞: mysql binlog parser / real-time / queue&topic

工作原理

mysql主備復(fù)制實現(xiàn)

從上層來看纯趋,復(fù)制分成三步:

  1. master將改變記錄到二進制日志(binary log)中(這些記錄叫做二進制日志事件憎兽,binary log events,可以通過show binlog events進行查看)吵冒;
  2. slave將master的binary log events拷貝到它的中繼日志(relay log)纯命;
  3. slave重做中繼日志中的事件,將改變反映它自己的數(shù)據(jù)桦锄。

canal的工作原理:

原理相對比較簡單:

  1. canal模擬mysql slave的交互協(xié)議扎附,偽裝自己為mysql slave,向mysql master發(fā)送dump協(xié)議
  2. mysql master收到dump請求结耀,開始推送binary log給slave(也就是canal)
  3. canal解析binary log對象(原始為byte流)

架構(gòu)

說明:

  • server代表一個canal運行實例留夜,對應(yīng)于一個jvm
  • instance對應(yīng)于一個數(shù)據(jù)隊列 (1個server對應(yīng)1..n個instance)

instance模塊:

  • eventParser (數(shù)據(jù)源接入匙铡,模擬slave協(xié)議和master進行交互,協(xié)議解析)
  • eventSink (Parser和Store鏈接器碍粥,進行數(shù)據(jù)過濾鳖眼,加工,分發(fā)的工作)
  • eventStore (數(shù)據(jù)存儲)
  • metaManager (增量訂閱&消費信息管理器)

知識科普

mysql的Binlay Log介紹

簡單點說:

  • mysql的binlog是多文件存儲嚼摩,定位一個LogEvent需要通過binlog filename + binlog position钦讳,進行定位
  • mysql的binlog數(shù)據(jù)格式,按照生成的方式枕面,主要分為:statement-based愿卒、row-based、mixed潮秘。
mysql> show variables like 'binlog_format';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | binlog_format | ROW   |
    +---------------+-------+
    1 row in set (0.00 sec)

目前canal支持所有模式的增量訂閱(但配合同步時琼开,因為statement只有sql,沒有數(shù)據(jù)枕荞,無法獲取原始的變更日志柜候,所以一般建議為ROW模式)

EventParser設(shè)計

大致過程:

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

  1. Connection獲取上一次解析成功的位置 (如果第一次啟動,則獲取初始指定的位置或者是當前數(shù)據(jù)庫的binlog位點)
  2. Connection建立鏈接躏精,發(fā)送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
  3. Mysql開始推送Binaly Log
  4. 接收到的Binaly Log的通過Binlog parser進行協(xié)議解析渣刷,補充一些特定信息
    // 補充字段名字,字段類型矗烛,主鍵信息辅柴,unsigned類型處理
  5. 傳遞給EventSink模塊進行數(shù)據(jù)存儲,是一個阻塞操作高诺,直到存儲成功
  6. 存儲成功后碌识,定時記錄Binaly Log位置

EventSink設(shè)計

說明:

  • 數(shù)據(jù)過濾:支持通配符的過濾模式碾篡,表名虱而,字段內(nèi)容等
  • 數(shù)據(jù)路由/分發(fā):解決1:n (1個parser對應(yīng)多個store的模式)
  • 數(shù)據(jù)歸并:解決n:1 (多個parser對應(yīng)1個store)
  • 數(shù)據(jù)加工:在進入store之前進行額外的處理,比如join

數(shù)據(jù)1:n業(yè)務(wù)

為了合理的利用數(shù)據(jù)庫資源开泽, 一般常見的業(yè)務(wù)都是按照schema進行隔離牡拇,然后在mysql上層或者dao這一層面上,進行一個數(shù)據(jù)源路由穆律,屏蔽數(shù)據(jù)庫物理位置對開發(fā)的影響惠呼,阿里系主要是通過cobar/tddl來解決數(shù)據(jù)源路由問題。

所以峦耘,一般一個數(shù)據(jù)庫實例上剔蹋,會部署多個schema,每個schema會有由1個或者多個業(yè)務(wù)方關(guān)注

數(shù)據(jù)n:1業(yè)務(wù)

同樣辅髓,當一個業(yè)務(wù)的數(shù)據(jù)規(guī)模達到一定的量級后泣崩,必然會涉及到水平拆分和垂直拆分的問題少梁,針對這些拆分的數(shù)據(jù)需要處理時,就需要鏈接多個store進行處理矫付,消費的位點就會變成多份凯沪,而且數(shù)據(jù)消費的進度無法得到盡可能有序的保證。

所以买优,在一定業(yè)務(wù)場景下妨马,需要將拆分后的增量數(shù)據(jù)進行歸并處理,比如按照時間戳/全局id進行排序歸并.

EventStore設(shè)計

  • 1. 目前僅實現(xiàn)了Memory內(nèi)存模式杀赢,后續(xù)計劃增加本地file存儲烘跺,mixed混合模式
  • 2. 借鑒了Disruptor的RingBuffer的實現(xiàn)思路

RingBuffer設(shè)計:

定義了3個cursor

  • Put : Sink模塊進行數(shù)據(jù)存儲的最后一次寫入位置
  • Get : 數(shù)據(jù)訂閱獲取的最后一次提取位置
  • Ack : 數(shù)據(jù)消費成功的最后一次消費位置

借鑒Disruptor的RingBuffer的實現(xiàn),將RingBuffer拉直來看:


image.png

實現(xiàn)說明:

  • Put/Get/Ack cursor用于遞增脂崔,采用long型存儲
  • buffer的get操作液荸,通過取余或者與操作。(與操作: cusor & (size - 1) , size需要為2的指數(shù)脱篙,效率比較高)

Instance設(shè)計

instance代表了一個實際運行的數(shù)據(jù)隊列娇钱,包括了EventPaser,EventSink,EventStore等組件。

抽象了CanalInstanceGenerator绊困,主要是考慮配置的管理方式:

  • manager方式: 和你自己的內(nèi)部web console/manager系統(tǒng)進行對接文搂。(目前主要是公司內(nèi)部使用)
  • spring方式:基于spring xml + properties進行定義,構(gòu)建spring配置.

Server設(shè)計

server代表了一個canal的運行實例秤朗,為了方便組件化使用煤蹭,特意抽象了Embeded(嵌入式) / Netty(網(wǎng)絡(luò)訪問)的兩種實現(xiàn)

  • Embeded : 對latency和可用性都有比較高的要求,自己又能hold住分布式的相關(guān)技術(shù)(比如failover)
  • Netty : 基于netty封裝了一層網(wǎng)絡(luò)協(xié)議取视,由canal server保證其可用性硝皂,采用的pull模型,當然latency會稍微打點折扣作谭,不過這個也視情況而定稽物。(阿里系的notify和metaq,典型的push/pull模型折欠,目前也逐步的在向pull模型靠攏贝或,push在數(shù)據(jù)量大的時候會有一些問題)

增量訂閱/消費設(shè)計

具體的協(xié)議格式,可參見:CanalProtocol.proto

get/ack/rollback協(xié)議介紹:

  • Message getWithoutAck(int batchSize)锐秦,允許指定batchSize咪奖,一次可以獲取多條,每次返回的對象為Message酱床,包含的內(nèi)容為:
    a. batch id 唯一標識
    b. entries 具體的數(shù)據(jù)對象羊赵,對應(yīng)的數(shù)據(jù)對象格式:EntryProtocol.proto
  • void rollback(long batchId),顧命思議扇谣,回滾上次的get請求昧捷,重新獲取數(shù)據(jù)揖闸。基于get獲取的batchId進行提交料身,避免誤操作
  • void ack(long batchId)汤纸,顧命思議,確認已經(jīng)消費成功芹血,通知server刪除數(shù)據(jù)贮泞。基于get獲取的batchId進行提交幔烛,避免誤操作

canal的get/ack/rollback協(xié)議和常規(guī)的jms協(xié)議有所不同啃擦,允許get/ack異步處理,比如可以連續(xù)調(diào)用get多次饿悬,后續(xù)異步按順序提交ack/rollback令蛉,項目中稱之為流式api.

流式api設(shè)計的好處:

  • get/ack異步化,減少因ack帶來的網(wǎng)絡(luò)延遲和操作成本 (99%的狀態(tài)都是處于正常狀態(tài)狡恬,異常的rollback屬于個別情況珠叔,沒必要為個別的case犧牲整個性能)
  • get獲取數(shù)據(jù)后,業(yè)務(wù)消費存在瓶頸或者需要多進程/多線程消費時弟劲,可以不停的輪詢get數(shù)據(jù)祷安,不停的往后發(fā)送任務(wù),提高并行化. (作者在實際業(yè)務(wù)中的一個case:業(yè)務(wù)數(shù)據(jù)消費需要跨中美網(wǎng)絡(luò)兔乞,所以一次操作基本在200ms以上汇鞭,為了減少延遲,所以需要實施并行化)

流式api設(shè)計:

  • 每次get操作都會在meta中產(chǎn)生一個mark庸追,mark標記會遞增霍骄,保證運行過程中mark的唯一性
  • 每次的get操作,都會在上一次的mark操作記錄的cursor繼續(xù)往后取淡溯,如果mark不存在读整,則在last ack cursor繼續(xù)往后取
  • 進行ack時,需要按照mark的順序進行數(shù)序ack血筑,不能跳躍ack. ack會刪除當前的mark標記绘沉,并將對應(yīng)的mark位置更新為last ack cusor
  • 一旦出現(xiàn)異常情況,客戶端可發(fā)起rollback情況豺总,重新置位:刪除所有的mark, 清理get請求位置,下次請求會從last ack cursor繼續(xù)往后取

數(shù)據(jù)對象格式:EntryProtocol.proto

Entry
    Header
        logfileName [binlog文件名]
        logfileOffset [binlog position]
        executeTime [binlog里記錄變更發(fā)生的時間戳]
        schemaName [數(shù)據(jù)庫實例]
        tableName [表名]
        eventType [insert/update/delete類型]
    entryType   [事務(wù)頭BEGIN/事務(wù)尾END/數(shù)據(jù)ROWDATA]
    storeValue  [byte數(shù)據(jù),可展開择懂,對應(yīng)的類型為RowChange]

RowChange
isDdl       [是否是ddl變更操作喻喳,比如create table/drop table]
sql     [具體的ddl sql]
rowDatas    [具體insert/update/delete的變更數(shù)據(jù),可為多條困曙,1個binlog event事件可對應(yīng)多條變更表伦,比如批處理]
beforeColumns [Column類型的數(shù)組]
afterColumns [Column類型的數(shù)組]

Column
index       [column序號]
sqlType     [jdbc type]
name        [column name]
isKey       [是否為主鍵]
updated     [是否發(fā)生過變更]
isNull      [值是否為null]
value       [具體的內(nèi)容谦去,注意為文本]

說明:

  • 可以提供數(shù)據(jù)庫變更前和變更后的字段內(nèi)容,針對binlog中沒有的name,isKey等信息進行補全
  • 可以提供ddl的變更語句

HA機制設(shè)計

canal的ha分為兩部分蹦哼,canal server和canal client分別有對應(yīng)的ha實現(xiàn)

  • canal server: 為了減少對mysql dump的請求鳄哭,不同server上的instance要求同一時間只能有一個處于running,其他的處于standby狀態(tài).
  • canal client: 為了保證有序性纲熏,一份instance同一時間只能由一個canal client進行g(shù)et/ack/rollback操作妆丘,否則客戶端接收無法保證有序。

整個HA機制的控制主要是依賴了zookeeper的幾個特性局劲,watcher和EPHEMERAL節(jié)點(和session生命周期綁定)勺拣,可以看下我之前zookeeper的相關(guān)文章。

Canal Server:

image.png

大致步驟:

  1. canal server要啟動某個canal instance時都先向zookeeper進行一次嘗試啟動判斷 (實現(xiàn):創(chuàng)建EPHEMERAL節(jié)點鱼填,誰創(chuàng)建成功就允許誰啟動)
  2. 創(chuàng)建zookeeper節(jié)點成功后药有,對應(yīng)的canal server就啟動對應(yīng)的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é)點的方式進行控制.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜡励,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子阻桅,更是在濱河造成了極大的恐慌凉倚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫂沉,死亡現(xiàn)場離奇詭異稽寒,居然都是意外死亡,警方通過查閱死者的電腦和手機趟章,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門杏糙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蚓土,你說我怎么就攤上這事宏侍。” “怎么了蜀漆?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵谅河,是天一觀的道長。 經(jīng)常有香客問我,道長绷耍,這世上最難降的妖魔是什么吐限? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮褂始,結(jié)果婚禮上诸典,老公的妹妹穿的比我還像新娘。我一直安慰自己崎苗,他們只是感情好狐粱,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著益缠,像睡著了一般脑奠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上幅慌,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天宋欺,我揣著相機與錄音,去河邊找鬼胰伍。 笑死齿诞,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的骂租。 我是一名探鬼主播祷杈,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼渗饮!你這毒婦竟也來了但汞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤互站,失蹤者是張志新(化名)和其女友劉穎私蕾,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胡桃,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡踩叭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了翠胰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片容贝。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖之景,靈堂內(nèi)的尸體忽然破棺而出斤富,到底是詐尸還是另有隱情,我是刑警寧澤闺兢,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布茂缚,位于F島的核電站戏罢,受9級特大地震影響屋谭,放射性物質(zhì)發(fā)生泄漏脚囊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一桐磁、第九天 我趴在偏房一處隱蔽的房頂上張望悔耘。 院中可真熱鬧,春花似錦我擂、人聲如沸衬以。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽看峻。三九已至,卻和暖如春衙吩,著一層夾襖步出監(jiān)牢的瞬間互妓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工坤塞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留冯勉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓摹芙,卻偏偏與公主長得像灼狰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浮禾,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容