靠谱,是当前生产环境最主流、扩展性最强的MySQL到Redis同步方案,但要求MySQL开启ROW格式binlog,需搭配Kafka/RocketMQ兜底并正确处理事务、删除及幂等逻辑。

用 Canal 解析 Binlog 同步 MySQL 到 Redis,靠谱吗?
靠谱,而且是当前生产环境最主流、扩展性最强的方案。它不侵入业务代码,不依赖 MySQL 触发器,也不要求应用层双写,天然支持增量+全量、删除操作、多表监听,适合中大型系统。
但前提是:MySQL 必须开启 binlog,且格式设为 ROW(binlog_format = ROW),否则 Canal 无法准确捕获行级变更。如果线上库是 MIXED 或 STATEMENT,强行接入会导致数据丢失或解析失败——这不是 Canal 的问题,是 binlog 本身没记录足够信息。
- 确认方式:
SHOW VARIABLES LIKE 'binlog_format';,返回值必须是ROW - 若不可改:别硬上 Canal,退回到「定时任务 + updated_at」或「业务层发 MQ」更稳妥
- Canal Server 需单独部署,建议用 Docker 启动,避免 JDK 版本冲突(尤其 Canal 1.1.x 依赖 JDK 8,新版 1.2.x 起支持 JDK 11+)
Canal 客户端怎么写?Python 示例要避开哪些坑?
Canal 本身不直接写 Redis,它只负责把 binlog 变更推给你;真正同步逻辑得自己写。Python 常用 canal-python 或手撸 TCP client,但注意:官方 canal-client 是 Java 生态,Python 社区库维护较弱,容易卡在连接重试、event 解析、事务边界处理上。
一个典型错误是:把每条 INSERT event 单独塞进 Redis,却忽略了 MySQL 的事务批量提交。结果 Redis 写了 100 次,而 MySQL 是 1 次事务提交——性能差、还可能破坏原子语义。
- 务必检查
entry.getHeader().getEventType(),区分INSERT/UPDATE/DELETE,特别是UPDATE要用afterColumns而非beforeColumns - 遇到
TRANSACTIONBEGIN和TRANSACTIONEND,建议缓存变更再批量写 Redis,而非逐条 flush - Redis 写操作推荐用
pipeline,比如pipe.set(key, value)+pipe.execute(),100 条能压到 1 次网络往返 - 别用
redis-py默认连接池的max_connections=50,高并发下容易阻塞;设为200+并打开health_check_interval=30
为什么不用消息队列兜底?MQ 和 Canal 到底谁该在前?
Canal 客户端直连 Redis 看似简单,但一旦 Redis 临时不可用(如主从切换、OOM),event 就丢了——Canal 默认不保证 at-least-once。所以真实线上架构里,**Canal → Kafka/RocketMQ → 消费者写 Redis** 才是健壮链路。
这里的关键不是“加 MQ”,而是利用 MQ 的持久化和重放能力来解耦和容错。Canal 做好它的本职:稳定拉取 binlog;MQ 负责保底;消费者专注幂等写 Redis。
- Kafka topic 名建议按库表命名,例如
mysql_binlog_order_db_order_table,方便下游过滤 - 消费者必须实现幂等:用
event_id + table_name + pk构成唯一 key 存 Redis 或 DB,重复消息直接 skip - 不要在消费者里做复杂计算或远程调用,否则吞吐掉得快;同步逻辑越薄越好
- MQ offset 提交策略选
enable.auto.commit=false,等 Redis 写成功后再手动 commit,否则可能丢数据
删数据时 Redis 没清掉?Binlog 删除事件容易被忽略
很多团队测试时只验证增/改,上线后才发现删数据没同步——因为 DELETE 的 binlog event 中,beforeColumns 有主键,afterColumns 是空的,如果你只读 afterColumns,就拿不到要删的 key。
更隐蔽的问题是:有些 ORM(如 Django ORM)执行软删除(update is_deleted=1),根本不会触发 DELETE event,这时候 Canal 根本看不到“删”,只能靠业务约定或额外监听 update。
- 处理
DELETE一定要读entry.getRowChange().getBeforeColumnsList() - 拿到主键后,生成 Redis key 的逻辑必须和写入时完全一致,否则删错 key(比如写入用
f"order:{id}",删除却拼成f"order_{id}") - 如果业务存在软删除,需在 Canal 客户端里加规则:当检测到特定字段(如
is_deleted)从 0→1,也当作逻辑删除处理
Binlog 同步不是开箱即用的黑盒,它把数据库的变更裸露出来,也把数据库的细节——事务粒度、软硬删除、字段别名、大字段截断——一并甩给了你。越想省事跳过这些细节,后期排查数据不一致就越花时间。










