Canal 通过伪装成 MySQL 从库,向主库发送 dump 请求获取 row 格式 binlog,解析出 insert/update/delete 结构化事件并投递下游;不侵入业务,实现缓存异步更新与最终一致性。

Canal 监听 MySQL Binlog 实现 Redis 异步更新,核心是让缓存脱离业务代码,由独立服务捕获数据库变更并驱动缓存操作,从而规避双写时序和并发竞争问题。
Canal 是怎么工作的?
Canal 模拟 MySQL 从库行为,伪装成 slave 向主库请求 binlog,解析后将 insert/update/delete 事件转换为结构化消息(如 JSON),再投递到下游。它不修改业务逻辑,也不依赖应用层触发,属于“旁路监听”架构。
- MySQL 必须开启 row 格式 binlog,并配置 server-id、binlog-do-db 等参数
- Canal Server 连接 MySQL 获取 binlog 流,Canal Client 订阅指定表的变更事件
- Client 收到 event 后,提取主键、新旧值、操作类型,决定对 Redis 执行 delete / set / expire 等动作
典型同步逻辑怎么写?
重点不是“更新缓存”,而是“响应变更”。多数场景下,推荐删除缓存而非写入,避免反序列化错误或字段映射遗漏。例如订单库存变更:
- 监听 order 表的 update 事件 → 提取 order_id → 执行
DEL order:1001 - 监听 product 表的 update 事件 → 若 price 或 stock 字段变化 → 删除对应 product:123 缓存
- 对 insert/delete 事件也统一走 delete,读请求自然触发重建,保证数据来源唯一
如何保障最终一致性?
Canal 本身不提供强一致保证,需叠加机制兜底:
- 启用 Canal 的 ack 机制:Client 处理成功后手动提交 offset,失败则重推
- Redis 操作失败时,把失败事件写入本地重试队列(如 Redis List + 延迟任务),避免丢事件
- 关键业务加“幂等判断”:用 event 的唯一 ID(如 GTID 或 timestamp+log_pos)去重,防止重复消费
- 定期跑补偿脚本:对比 MySQL 和 Redis 中热点 key 的值,发现不一致自动修复
要注意哪些坑?
Binlog 同步不是开箱即用的银弹,几个高频问题要提前防住:
- 大事务导致延迟:单个 binlog event 包含上千条 update?Canal 消费会卡住。建议 MySQL 层控制单事务行数 ≤ 500
- DDL 变更中断同步:新增字段或改表结构可能让 Canal 解析失败。上线前先在测试环境验证 schema 兼容性
- 主从延迟影响感知:Canal 接的是主库还是从库?必须连主库,否则读到的是过期 binlog
- 缓存穿透风险:delete 后大量并发查询击穿到 DB?需配合布隆过滤器或空值缓存兜底


















