基于MySql BinLog的增量订阅和消费组件:Canal
- Cancal是阿里13年1月开源的一个基于MySql数据库Binlog实现的增量订阅和消费的组件。项目取名Canal取自管道的英文单词,流转的医生,是一个定位于基于MySql数据库Binlog增量日志来实现数据库镜像,试试备份和怎梁书记消费的通用组件。
- 早期的数据库同步业务,大多使用MySql数据库的触发器机制(Trigger)来获取数据库的增量变更,之后逐步阐释基于数据库日志解析来获取数据,再次激起上实现数据同步,由此衍生出了数据库增量订阅和消费业务----Canal项目。
Canal核心思想
- Canal工作原理比较简单,核心思想就是模拟MySql Slave的交互协议,将字节伪装称为一个MySql的Slave激起,不断向Master发送Dump请求。Master收到Dump后,开始推送对应Binary Log给这个Slave(其实是Canal)。Canal收到Binary log,解析出对应的Binary Log对象后就可以进行二次消费了,基本工作如下:
Canal Server主备切换设计
- 在Canal的设计中,基于对容灾的设计,会配置两个或者更多的Canal Server负责一个MySql数据库实例的数据增量复制,另外一个方面,为减少CanalServer的Dump请求对MySql Master带来的影响,要求不同Canal Server上的Instance在同一个时刻只能有一个处于Running状态,其他的instance都处于Standby状态,这就使得Canal必须具备主从切换能力,此部分功能利用Zookeeper来完成,如下图:
- 尝试启动: 每个Canal Server在启动某个Canal instance的时候,都会首先向Zookeeper进行一次阐释启动判断,都想Zookeeper创建同一个临时节点,那个Canal Server创建成功,就让哪一个启动。以“example”这个instance为例,都创建“/otter/canal/destinations/example/running”节点,Zookeeper保证只有一个成功
- 启动instance: 假设最终IP:10.1.12.211的Canal Server成功创建,会将字节机器信息写入节点中,并同时启动instance,其他CanServer会将字节状态设置Standby同时对成功节点注册Watch监听,以监听节点变化情况。成功节点注册数据如下:
{"active":true,"address":"10.1.12.211:11111","cid":1}
-
主备切换:CanalServer在运行过程中,发送异常,因为创建的是Zookeeper的临时节点,当Running状态的CanalServer挂点或者网络原因断开,那么“/otter/canal/destinations/example/running”节点就会在一段时间后消失。其他Standby状态的CanalServer已经添加过Watch,因此会接受到Zookeeper发来的通知,重复1 步骤以此实现主备切换
-
特殊设计:Canal设计中,当有那种服务器网络闪断的假死清,导致Zookeeper任务其会话失效,此时其实CanalServer对应JVM并没有退出,状态正常,CanalServer做了一个策略:
- 状态为Standby的CanalServer收到Running节点释放的通知后,会延迟一段时间抢占Running节点,而原来的Running状态的instance不需要等待直接获取Running节点。这样就尽可能保证瞬时假死情况下不需要切换避免了五位的资源释放和重新分配,目前延迟时间是5秒,即Running节点针对假死状态的保护器为5秒
Canal Server的HA设计
- Canal Servers进行数据消费钱,需要找到Master的CanalServer节点,在上文中已经讲了,针对每一个数据复制实例,例如example,都会在“/otter/canal/destinations/example/running” 节点记录正在运行的CanalServer,所有CanalServer链接Zookeeper后读取这个节点信息即可
- 从Zookeeper中读取当前处于Running状态的server:CanalClient启动会首先从“/otter/canal/destinations/example/running” 节点读取当前Running状态的Server,同时客户端也会将字节的信息注册到Zookeeper的“/otter/canal/destinations/example/1001/running” 下面,其中1001目录层级是代表客户端唯一标识节点内容如下:
{"active":true,"address":"10.1.12.211:50544","clientId":1001}
- 注册Running节点数据变化的监听: 由于CanalServer有挂掉的风险,CanalClient还会对“/otter/canal/destinations/example/running”节点注册一个监听,一旦server主备切换,Client随时能感知到。
- 链接对应RunningServer进行数据消费。
数据消费点位记录
- 由于存在CanalClient重启或者其他变化,为避免数据消费顺序错乱,Canal必须对数据消费点位进行实时的记录,也就是记录下本次读取到的Binlog日志到第几行了,数据消费后,CanalServer会在Zookeeper上记录当前最后一次消费成功的Binarylog点位,一旦发生Client重启,只需从这个点位后一个点位开始消费,具体做法如下:
- 在Zookeeper的“/otter/canal/destinations/example/1001/cursor”节点中记录下客户端消费的详细点位信息:
- 具体内容如下:
{"@type":"com.alibaba.otter.canal.protocol.position.LogPosition","identity":{"slaveId":-1,"sourceAddress":{"address":"10.21.16.8","port":3306}},"postion":{"gtid":"","included":false,"journalName":"mysql-bin.004073","position":82751773,"serverId":109065,"timestamp":1589508966000}}