erosa mysql_MySQL协议和canal实现
前言
前面的文章里,我們了解到 canal 可以從 MySQL 中感知數據的變化。這是因為它模擬 MySQL slave 的交互協議,偽裝自己為 MySQL slave ,從而實現了主從復制。
正是了解到這一點,筆者有兩個問題便一直縈繞于心:它是如何模擬 MySQL slave 交互協議的?
它又是怎么解析 binlog 日志的呢?
今天,筆者準備就著這兩個問題,扒拉扒拉 canal 的代碼,一探究竟。
一、MySQL 主從復制
在談 canal 之前,我們有必要再重溫下 MySQL 主從復制的原理。
總結上圖的流程如下:MySQL master 將數據變更寫入二進制日志 (binary log , 其中記錄叫做二進制日志事件binary log events);
MySQL slave 將 master 的 binary log events 拷貝到它的中繼日志 (relay log);
MySQL slave 重放 relay log 中的事件,將數據變更反映到自己的數據庫。
二、canal 原理
上圖就很形象的描述了 canal 的角色。它的原理也很簡單:canal模擬mysql slave的交互協議,偽裝自己為mysql slave,向mysql master發送dump協議;
mysql master收到dump請求,開始推送binary log給slave(也就是canal);
canal解析binary log對象(原始為byte流);
canal將解析后的對象,根據業務場景,分發到比如 MySQL 、RocketMQ 或者 ES 中。
三、源碼啟動
看完了 MySQL 主從復制和 canal 原理之后,為了方便 debug ,筆者已經在 GitHub Fork 了源碼,并導入本地。
可以找到?com.alibaba.otter.canal.deployer.CanalLauncher?類,它就是 canal 獨立版本啟動的入口類。
在這里,直接運行 main 方法即可運行 canal ,和在?/canal/bin/startup.sh?中效果一樣。
事實上,canal 的代碼比較多,在架構上又分了很多模塊設計,比如事件解析器、事件消費、內存存儲、服務實例、元數據、高可用等。
本文不打算面面俱到介紹每一個的實現,那就得正兒八經寫一個 canal 系列才行。主要還是為了開頭我們提出的那兩個問題。
四、如何模擬slave ?
上面我們已經說到,?CanalLauncher是canal 啟動的入口類。
運行 main 方法之后, canal 會先做很多準備工作。比如加載配置文件、初始化消息隊列、啟動 canal Admin、加載Spring配置、注冊鉤子程序等。
canal 模擬 slave 協議,是在?EventParser模塊中開始進行的。
在 canal 代碼中,整個流程簡化如下://?開始執行replication//?1.?構造Erosa連接ErosaConnection?erosaConnection?=?buildErosaConnection();//?2.?啟動一個心跳線程startHeartBeat(erosaConnection);//?3.?執行dump前的準備工作preDump(erosaConnection);erosaConnection.connect();//?鏈接//?查詢master?serverIdlong?queryServerId?=?erosaConnection.queryServerId();if?(queryServerId?!=?0)?{????serverId?=?queryServerId;}//?4.?獲取binlog最后的位置信息EntryPosition?position?=?findStartPosition(erosaConnection);final?EntryPosition?startPosition?=?position;//?加載元數據processTableMeta(startPosition);//?重新鏈接,因為在找position過程中可能有狀態,需要斷開后重建erosaConnection.reconnect();//?4.?開始dump數據erosaConnection.dump(startPosition.getJournalName(),startPosition.getPosition(),sinkHandler);
1、握手、驗證
在開始之前,canal 必須先要和 MySQL 服務器建立連接,并完成客戶端身份驗證。
在 MySQL 中,連接過程協議如下:
在代碼中,我們看一下它的連接方法:
其中,?negotiate方法是握手協議和客戶端驗證的具體實現。就是按照 MySQL 的協議規范,通過上面創建的?Socketchannel來讀寫網絡數據。
2、dump前的準備
正確連接到 MySQL 后,在開始執行 dump 指令之前,還要初始化一些配置信息。
思路就是通過 MySQL 執行器,執行 SQL 語句,獲取信息。
代碼就不粘了,不過它們執行的語句如下:show?variables?like?'binlog_format'??????#獲取binlog?format格式show?variables?like?'binlog_row_image'???#獲取binlog?image格式show?variables?like?'server_id'??????????#獲取matser?serverIdshow?master?status???????????????????????#獲取binlog名稱和position
3、注冊slave
現在開始調用?erosaConnection.dump(binlogfilename,binlogPosition,func)方法,來注冊slave和發送dump命令。
在使用?COM_BINLOG_DUMP請求binlog事件之前發送,在主服務器上注冊一個從服務器,它的指令是?COM_REGISTER_SLAVE。
注冊完之后,就是發送dump請求,它的指令是?COM_BINLOG_DUMP。
在執行完這段代碼后,我們通過?show processlist;查看進程,就可以看到這個dump線程的狀態。
其中 command =?Binlog Dump
state = Master has sent all binlog to slave; waiting for more updates。
五、如何解析binlog數據 ?
在上面章節中,我們已經看到,MySQL主服務器已經接受了 canal 這個從服務器,那么當canal拿到binlog內容后, 又是怎么解析它的呢?
首先,還記得在配置MySQL服務器的時候,我們將?binlog-format設置為ROW模式,它是基于行的復制。
binlog中每一個數據變更可以叫做事件,在ROW模式下,有幾個主要的事件類型:事件SQL命令rows 內容TABLEMAPEVENTnull定義將要更改的表。
WRITEROWSEVENT插入要插入的行數據
DELETEROWSEVENT刪除被刪除的數據
UPDATEROWSEVENT更新原數據+要更改的數據
每一次數據的變更,都會觸發2個事件,先把要更改的表信息告訴你,然后再告訴你更改的row內容。
比如?TABLE_MAP_EVENT+WRITE_ROWS_EVENT。
canal在接收到binlog數據后,并不會馬上把它解析成我們熟悉的JSON數據,而是在發送的時候才開始。
比如我們選擇使用?RocketMQ,那么在發送之前才開始將binlog里面的byte數組轉化為對象。//?并發構造EntryRowData[]?datas?=?MQMessageUtils.buildMessageData(message,?executor);//?串行分區List?flatMessages?=?MQMessageUtils.messageConverter(datas,?message.getId());
在這兩個方法里,就完成了byte數組到對象的轉化。轉化成的?FlatMessage對象,就成了我們在消息隊列中消費到的數據結構。public?class?FlatMessage?implements?Serializable?{????private?long??????????????????????id;????private?String????????????????????database;????private?String????????????????????table;????private?List??????????????pkNames;????private?Boolean???????????????????isDdl;????private?String????????????????????type;????//?binlog?executeTime????private?Long??????????????????????es;????//?dml?build?timeStamp????private?Long??????????????????????ts;????private?String????????????????????sql;????private?Map??????sqlType;????private?Map???????mysqlType;????private?List>?data;????private?List>?old;}
總結
正如本文開頭所言,筆者在剛了解到canal機制的時候,確實覺得很不可思議。
咦,它是怎么模擬MySQL slave的呢 ?總覺得是不是有啥黑科技在里面。。。
事實上,這是源于筆者對MySQL的無知。
MySQL早就制定好了各種接口協議,怎么連接、驗證、注冊和dump都明明白白的寫在那兒啦。
總結
以上是生活随笔為你收集整理的erosa mysql_MySQL协议和canal实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国瓷砖十大名牌排行榜(中国十大一线品牌
- 下一篇: ofbiz修改mysql_如何将OFBI