读写分离仅在读多写少、主从延迟可控、接受弱一致性时有效;主从延迟会导致脏读;事务内读、强一致查询、锁读、跨库JOIN必须走主库;中间件透明但缺乏上下文感知,应用层灵活但需处理异步场景一致性。

读写分离在 MySQL 并发场景下是否真能提升性能
不能一概而论。读写分离只有在读多写少、主从延迟可控、业务能接受弱一致性的前提下才有效。高并发写入密集型场景(如秒杀扣库存、高频日志写入)下,强行读写分离反而会因主从同步延迟导致脏读,或因路由逻辑增加额外开销。
MySQL 主从复制延迟如何影响读写分离效果
主从延迟是读写分离失效的最常见原因。一旦 Seconds_Behind_Master 持续大于 0,所有发往从库的 SELECT 都可能读到过期数据。尤其在以下情况中风险突出:
- 大事务提交后,从库需重放 binlog,延迟可能达秒级甚至分钟级
- 从库配置低于主库(如磁盘 I/O 更慢、CPU 核数更少)
- 开启了
read_only=1但未设置super_read_only=1,导致从库被误写,进一步破坏数据一致性 - 应用未做
SELECT路由兜底——比如用户刚下单(写主库),立刻查订单列表(可能路由到从库),结果查不到
哪些查询必须强制走主库
不是所有读操作都适合下推到从库。以下几类 SELECT 必须直连主库,否则逻辑错误:
- 事务内后续读:在
BEGIN→INSERT/UPDATE→SELECT流程中,该SELECT必须看到刚写的变更 - 依赖最新状态的判断逻辑:例如
SELECT COUNT(*) FROM orders WHERE status = 'pending'用于触发补单任务,延迟会导致漏处理 - 涉及
SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE的语句——从库不支持写锁,执行会直接报错ERROR 1290 (HY000): The MySQL server is running with the --read-only option - 跨库关联查询(如
JOIN主库 db1 和从库 db2 的表)——架构上无法支持,必须统一走主库
中间件 vs 应用层实现读写分离的取舍
选择实现方式直接影响稳定性与可控性:
- 用
ShardingSphere-JDBC或MyCat等中间件:配置简单,对应用透明,但版本升级易引发 SQL 兼容问题;且无法感知业务上下文(比如无法自动识别“刚写完就查”这种场景) - 在应用层用
AbstractRoutingDataSource(Spring)或自定义DBConnectionPool控制路由:可结合 ThreadLocal 记录写标记,实现“本请求内后续读走主库”,灵活性高;但需团队具备数据库连接治理能力,且容易在异步线程(如@Async、线程池)中丢失上下文 - 完全不用中间件/框架,靠 DNS 或 VIP 切换:仅适用于读写流量物理隔离的极简场景,无法解决单请求内的强一致性需求
if (isWriteInThisRequest.get()) {
return "master";
} else if (isInTransaction.get()) {
return "master";
} else {
return roundRobinSlave();
}
上面这段路由逻辑看似合理,但要注意:isWriteInThisRequest 在 WebFlux 或 CompletableFuture 链路中极易失效;isInTransaction 若用 Spring 的 TransactionSynchronizationManager,需确认传播行为是 REQUIRED 而非 REQUIRES_NEW,否则嵌套事务里会误判。
真正难的不是配通读写分离,而是厘清每条 SQL 的一致性边界,并让路由策略在各种调用链路(HTTP、RPC、定时任务、消息回调)中保持行为一致。多数线上事故,都出在“以为从库能读,其实不能”的那一瞬间。










