Canal探究( 三 )

  • 一旦zookeeper发现canal server A创建的节点消失后 , 立即通知其他的canal server再次进行步骤1的操作 , 重新选出一个canal server启动instance.
  • canal client每次进行connect时 , 会首先向zookeeper询问当前是谁启动了canal instance , 然后和其建立链接 , 一旦链接不可用 , 会重新尝试connect.
  • Canal Client的方式和canal server方式类似 , 也是利用zookeeper的抢占EPHEMERAL节点的方式进行控制.
    canal丢失数据的情况:正常情况下 , 在canal server/client挂掉或切换的情况下不会丢失数据 , 因为zk会持久化server解析binlog及clinet消费数据的位置 , 重启时会重新读取 。 以下情况可能会丢失数据:
    • zk保存的元数据被人为修改 , 如server解析binlog及clinet消费数据的位置
    • client使用get方法而非getWithoutAck , 如果client消费数据时挂掉 , server会认为这部分数据已经被消费而丢失
    • MySQL binlog非正常运维 , 比如binglog迁移、重命名、丢失等
    • 切换MySQL源 , 比如原来基于M1实例 , 后来M1因为某种原因失效 , 那么Canal将数据源切换为M2 , 而且M1和M2可能binlog数据存在不一致
    Canal性能分析
    • canal处理数据流程为master-parse-sink-store-comsume , 整个流程中都是单线程、串行、阻塞式的 。 如果批量insert、update、delete , 都可能导致大量的binlog产生 , 也会加剧Master与slave之间数据同步的延迟 。 (写入频繁) 。
    • 如果client消费的效能较低 , 比如每条event执行耗时很长 。 这会导致数据变更的消息ACK较慢 , 那么对于Canal而言也将阻塞sotre , 没有有足够的空间存储新消息进而堵塞parse解析binlog 。
    • Canal本身非常轻量级 , 主要性能开支就是在binlog解析 , 其转发、存储、提供消费者服务等都很简单 。 它本身不负责数据存储 。 原则上 , canal解析效率几乎没有负载 , canal的本身的延迟 , 取决于其与slave之间的网络IO 。
    Canal导致重复消费
    • Canal instance初始化时 , 根据“消费者的Cursor”来确定binlog的起始位置 , 但是Cursor在ZK中的保存是滞后的(间歇性刷新) , 所以Canal instance获得的起始position一定不会大于消费者真实已见的position 。
    • Consumer端 , 因为某种原因的rollback , 也可能导致一个batch内的所有消息重发 , 此时可能导致重复消费 。
    因此Consumer端需要保持幂等 , 对于重复数据可以进行校验或者replace 。 对于非幂等操作 , 比如累加、计费 , 需要慎重 。
    destination的消费问题一个destination无法被多个client直接并行消费 , 解决方案:
    • client收到消息以后转发到kafka或者MQ中 , 后继的其他Consumer只与kafka或者MQ接入
    • 一个Canal中使用多个destination , 它们对应相同的MySQL源
    参考:
    对于canal设计的一些思考