MySQL主从复制本身不提供读写分离能力,需依赖应用层或中间件(如ProxySQL、ShardingSphere)实现SQL路由;必须处理主从延迟、事务一致性、故障切换后配置同步等核心问题。

MySQL 主从复制本身不提供读写分离能力
主从复制只是把主库的写操作通过 binlog 同步到从库,它不参与 SQL 路由、连接分发或负载决策。读写分离需要额外组件在应用层或中间件层完成请求识别与转发。
常见错误现象:SELECT 语句仍发到主库、从库延迟导致读到旧数据、事务内混用读写引发不一致。
- 应用直连多实例时,必须自己判断
INSERT/UPDATE/DELETE走主库,SELECT走从库(需注意显式事务和SELECT ... FOR UPDATE) - 用
ProxySQL或MaxScale时,要配置mysql_query_rules匹配SELECT并路由到hostgroup 2(从库组),否则默认全走主库 - Spring Boot +
AbstractRoutingDataSource需重写determineCurrentLookupKey(),且@Transactional方法内默认强制走主库,否则可能报错
从库延迟会直接破坏读写分离效果
主从延迟不是理论风险,而是常态。一旦 Seconds_Behind_Master > 0,应用从从库读取刚写入的数据就会失败——比如用户注册后立刻查个人页,返回 404。
使用场景中容易忽略:高并发写入、大事务、从库 IO 或 CPU 过载、网络抖动都会放大延迟。
- 监控必须包含
SHOW SLAVE STATUS\G中的Seconds_Behind_Master和Exec_Master_Log_Pos与主库File/Position的差值 - 关键业务读操作可加
SELECT /*+ MAX_EXECUTION_TIME(1000) */ ...配合超时重试,或临时切回主库 - 避免在从库执行
pt-online-schema-change等长耗时操作,这类操作会阻塞 SQL 线程
GTID 模式下主从切换后读写分离更难维持
启用 gtid_mode=ON 后,主从关系可通过 GTID_SUBSET 自动定位位点,但读写分离中间件往往无法感知新主库身份,仍按旧拓扑转发请求。
典型问题:CHANGE MASTER TO ... GTID_SET 执行后,ProxySQL 的 mysql_servers 表未更新,导致 SELECT 继续发向已下线的旧从库。
- 切换前必须调用
SAVE MYSQL SERVERS TO DISK并确认mysql_servers中status字段为ONLINE或SHUNNED - Ansible 或脚本触发 failover 时,需同步更新中间件配置 + 应用侧数据源地址(如 Spring Cloud Config 中的
spring.datasource.url) - 不要依赖
read_only=ON判断主从角色——故障切换后新主库可能仍残留该参数,造成写入被拒
真正可用的读写分离必须处理事务一致性边界
一个事务里既有写又有读,或者读操作依赖刚写的值(如生成订单号后立即查详情),此时强行把 SELECT 转给从库必然出错。
这是最容易被“自动读写分离”宣传误导的地方:没有中间件能 100% 正确解析 SQL 语义并保证事务上下文完整。
- ShardingSphere-JDBC 的
master-slave规则默认在事务内禁用从库路由,但若用@Transactional(propagation = Propagation.NOT_SUPPORTED)就会失效 - MyCat 不支持跨库事务,遇到
XA START会直接报错ERROR 1105 (HY000): Unknown command - 最稳妥的做法是:对强一致性读,显式指定数据源(如
DataSourceType.MASTER),而非依赖自动识别










