简介
本文主要以Mysql为例,分析canal的parser模块是如何从mysql拉取数据的。
核心
canal的官网中介绍到,canal的工作原理简单分为如下几步:
- canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
- mysql master收到dump请求,开始推送binary log给slave(也就是canal)
- canal解析binary log对象(原始为byte流)
在canal的parser模块中,有一个抽象类AbstractEventParser
,该类中定义了一个线程,该线程每10秒向Mysql的Master节点发送一次dump请求,用于请求binlog日志数据,然后把binlog数据存储到一个大小为1024的ringbuffer缓存队列中,整个流程如下图所示:
下面将详细介绍一个完整的canal请求binlog日志的过程:
-
首先会启动一个心跳线程,该心跳线程只作用于parser模块和sink模块,每秒向sink模块推送一个心跳报文。
-
在创建与Mysql节点的连接之前,需要做一些准备工作,比如确定binlog的FORMAT以及binlog_row_image参数的值
-
建立与Mysql的连接,在instance.properties文件中会配置Master的地址端口以及对应的数据库用户名密码,此处就是利用这些信息建立与Master的连接。
-
获取到Mysql的ServerId
-
获取最后的位置信息,也就是上一次与Master通信后读取到的binlog的位置,该位置信息也会写入meta.dat文件中,因此如果内存中没有,会尝试从该文件中读取。
-
重新链接,因为在找position过程中可能有状态变更,需要断开后重建。
-
调用dump()方法开始获取pbinglog数据,同时注册一个回调事件用于接收返回的binlog数据。
-
sleep10秒,重新执行上述流程。
当有回调事件返回时,处理流程如下
- 调用BinlogParser类的parse()方法将返回的二进制binlog数据LogEvent,解析成canal封装好的Entry事件,LogEvent中包含一个事件类型eventType,详细区分了该事件是查询操作还是写操作,或者是心跳等各种类型。
- 调用EventTransactionBuffer类的add()方法将Entry事件添加到一个大小为1024的ringbuffer中。
- EventTransactionBuffer会在一定的条件下把ringbuffer中的Entry事件推送到sink模块。
至此,parser模块下的canal与mysql的通信过程全部结束。