2026年7月13日 · 4 分钟阅读

MySQL 读写分离:复制原理、主从延迟与读一致性设计

从 binlog 复制和路由机制出发,分析读写分离的收益、主从延迟、读后写一致性、故障回退、连接池和生产监控。

读写分离把写请求和强一致读取送到主库,把可容忍延迟的查询送到副本。它扩展的是读能力,不会提高主库写吞吐,也不会自动解决慢 SQL。

复制链路

主库事务提交后产生 binlog,副本拉取并重放日志。复制通常异步,因此存在:

主库已提交 → binlog 尚未传到副本 → 副本尚未应用

网络、长事务、大 DDL、单线程瓶颈或副本负载都会扩大延迟。高可用、数据安全和读一致性是不同问题,不能用“有副本”概括。

请求如何路由

常见实现包括应用数据源路由、数据库中间件或 Proxy。路由规则不能只看 SQL 第一个单词:事务中的读、加锁读、写后立即读、会话变量和存储过程都可能要求主库。

普通列表、报表、推荐 → 副本
支付结果确认、下单后详情、事务内查询 → 主库

连接池应按主库和副本隔离,设置独立容量、超时和熔断,避免副本异常耗尽所有业务线程。

读后写一致性

用户刚修改昵称,刷新页面却看到旧值,就是典型 replication lag。方案按成本选择:

  • 写后的一段时间内,按用户或会话强制读主库。
  • 写接口返回新值,前端短时使用响应结果。
  • 为数据携带版本号,副本版本不足时回主库。
  • 等待副本应用到特定日志位置,但会增加延迟和可用性风险。
  • 对余额、库存等关键状态始终读主库或权威服务。

“延迟一秒后再读”不是可靠协议:延迟不是固定值。业务应明确能容忍多旧的数据,并制定超出窗口后的回退。

副本故障与降级

副本不可用时全部回主库可能形成流量雪崩。正确做法是:

  1. 健康检查摘除异常副本。
  2. 对非关键读限流、降级或使用短时缓存。
  3. 只把主库安全容量内的请求回退。
  4. 恢复后逐步加流,确认复制追平再提供读取。

负载均衡也不能纯随机:应考虑复制延迟、连接数、节点权重和可用区。明显落后的副本要自动退出读池。

监控与容量

最低监控集合:主库写 QPS、各副本读 QPS、复制位置与延迟、relay log 积压、应用线程状态、长事务、磁盘 IO、连接池等待和错误率。还要从业务端监控陈旧读,因为“复制线程正常”不代表用户一定读到正确版本。

上线前演练副本宕机、网络隔离、延迟突增、主库切换和全量重建。切主后要确认应用路由、只读标志和复制拓扑同步更新,避免双主写入。

什么时候不该做读写分离

  • 系统主要瓶颈是写入或锁竞争。
  • 读请求必须始终强一致。
  • 查询本身低效,复制只会把低效 SQL 复制到更多机器。
  • 规模很小,额外拓扑和故障处理成本高于收益。

此时应先做索引、SQL、缓存、归档或业务拆分。

工程检查清单

  • 每类查询是否标注一致性级别和允许陈旧时间。
  • 事务内查询、加锁读和写后读是否路由主库。
  • 延迟副本能否自动摘除,恢复是否逐步加流。
  • 主库是否能承受受控回退,而不是所有读流量。
  • 连接池、超时、监控和故障演练是否覆盖主从两侧。

面试回答要点

先说明主写副本读、binlog 异步复制和读扩展价值,再主动指出主从延迟。解决写后读问题可用会话粘主、版本检查或关键读主库;副本故障时需要摘除、限流降级和受控回退,不能把全部流量直接压到主库。

总结

读写分离是一种带一致性成本的读扩展方案。设计重点不是配置两个数据源,而是给查询分级、处理读后写、管理落后副本,并确保故障时不会反向压垮主库。

参考资料