一、what
阿里开源,mysql增量数据订阅与消费服务,文档:https://github.com/alibaba/canal/wiki
工作原理:canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送 dump 协议
MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
canal 解析 binary log 对象(原始为 byte 流)
二、why
工作中遇到一个查询场景,需要多张表的数据(8张)做聚合,且某些表数据量较大,还需要反复join,导致sql极复杂&查询速度极慢,于是打算将这些数据聚合成一张宽表,每次查询直接从宽表中查询。
三、how
1. 整体架构:canal-server监听mysql的binlog ------→ canal-client接收来自canal-server发出的数据变更消息&计算宽表数据 -------→ 写入宽表。canal-client是自己搭建的java服务,实现宽表聚合的具体计算逻辑。canal-server实际是帮我们做了binlog的解析,将解析后的数据发送给canal-client
2. 步骤
1. 运维同学搭建canal-server,监听对应mysql的binlog服务并做相关配置
2. 开发同学搭建canal-client,连上canal-server,消费数据变更,开发程序,根据业务场景集合宽表
四、其他
1. 问题:mysql数据变更后,canal-client未收到数据变更消息
原因:binlog过期自动被清除,canal server还未来得及解析,导致canal server每次启动时都从binlog的144文件开始读,但是现在最早的位置在146文件,146之前的binlog都已被删除,canal-server读取binlog失败。
具体情况说明:(基于”canal-client消费后才会驱动canal-server解析binlog的游标移动,否则canal-server的游标停留在原位置"的原理)。DBA设置的binlog为7天有效期,过期删除,运维同学搭建好canal-server后,我这边因为有其他事,一直未开始投入client的开发,所以一直未启动canal-client消费,那天启动canal-client消费过程中,一开始是正常的,后边突然收不到数据变更消息,其实是某些binlog刚好到期时间被删除,导致canal-server读取binlog失败。
解决方案:重新初始化server读取binlog的游标,并且延长binlog的过期时间。
2. 问题:收到的数据与配置的监听表不一致,eg. 配置的监听表A,但是收到了表B的变更消息
原因:canal-client未进行监听表过滤。不写connector.subscribe()或者写成connector.subscribe()都会把服务端的规则覆盖掉,需要显示指定监听规则。(无论 server filter 配置成什么,都会被 client 的 subscribe 参数替换掉,奇葩)
3. Q:可以多个client连接同一个server下的instance吗?
A:可以,数据分发方式是:串联&轮训的方式给每个client提供数据,也就是消息发给clientA就不会再发给其他的client了,非广播发送。(待验证)
4. 消息、乱序重复:做幂等处理
增加:按照业务主键做幂等,若已记录已存在,则忽略消息
修改:按照业务主键+更新时间做幂等,若数据变更事件发生的时间 < 宽表数据的更新时间,说明是过期消息,需要忽略消息,否则可能出现ABA问题
删除:无影响