Canal核心原理
Table of Contents
Canal是一个C/S架构模式,服务端复制拉取,解析,存储Mysql的binlog。客户端负责从服务器轮询获取binlog信息。 Canal服务端有一个核心功能,就是模拟mysql的slave节点去向master节点获取binlog。所以我们先要理解Mysql是怎么做主备复制的
MySQL主备复制原理
Server架构图
名词解释
CanalServerWithEmbeded:负责拉取和解析mysql binlog。
Server处理流程图
- 从 Log Position 管理器中获取上一次解析的日志位点。
- 向 Mysql Master 节点发送 BINLOG_DUMP 请求。
- Mysql Master 节点从 Slave 端传入的日志位点开始向从节点推送 binlog 日志。
- Slave 接收 binlog 日志,调用 BinlogParser 解析 binlog日志。
- 将解析后的结构化数据传入到 EventSink 组件。
- 定时记录解析 binlog 的日志,以便重启后继续进行增量订阅。
如果Mysql Master宕机了,Canal是不是不可用了? 上图中还罗列一个HA 特性,即需要同步的 Master 如果宕机,可以从它的其他从节点继续同步 binlog 日志,避免单点故障。
Client-Server时序图
左边Client,右边Server
Canal高可用架构(HA)
疑问
- 这个方式看起来可以做到Server的高可用架构。但是对于client,如果一个应用对应多个节点,就会对应多个client,怎么协调不同的client的数据拉取?
- 对于Server,多个instance拉同一个Mysql的binlog,怎么协调?
通过具体的实现流程来解答上面两个问题 canal server实现流程如下:
- canal server 要启动某个 canal instance 时都先向 zookeeper 进行一次尝试启动判断 (实现:创建 EPHEMERAL 节点,谁创建成功就允许谁启动);
- 创建 zookeeper 节点成功后,对应的 canal server 就启动对应的 canal instance,没有创建成功的 canal instance 就会处于 standby 状态;
- 一旦 zookeeper 发现 canal server A 创建的节点消失后,立即通知其他的 canal server 再次进行步骤1的操作,重新选出一个 canal server 启动instance;
- canal client 每次进行connect时,会首先向 zookeeper 询问当前是谁启动了canal instance,然后和其建立链接,一旦链接不可用,会重新尝试connect。
「PS」: 为了减少对mysql dump的请求,不同server上的instance要求同一时间只能有一个处于running,其他的处于standby状态。 canal client实现流程
- canal client 的方式和 canal server 方式类似,也是利用 zookeeper 的抢占EPHEMERAL 节点的方式进行控制
- 为了保证有序性,一份 instance 同一时间只能由一个 canal client 进行get/ack/rollback操作,否则客户端接收无法保证有序。
生产问题
- 消息堆积?本质上是client的消费能力跟不上
- canal重复拉取binlog (https://kb.cvte.com/pages/viewpage.action?pageId=209960949)
- canal更新es的document失败(https://kb.cvte.com/pages/viewpage.action?pageId=154110064)
参考
https://docs.google.com/presentation/d/1FDrfVEoNV7AlPOrgXYKo2L_70NDizhwrMpfCG0vztf8/edit#slide=id.gb0d10616_5_255 (otter设计ppt) https://github.com/alibaba/canal (官方) https://www.bookstack.cn/read/canal-v1.1.4/cd6a5ac129e1edb7.md (中文文档) https://www.modb.pro/db/79040 (canal原理详解) https://cloud.tencent.com/developer/article/1805726 (canal高可用架构) https://cloud.tencent.com/developer/article/1658839 (EventParser详解)