读写分离需显式路由SELECT至从库,主库仅处理写操作;主流方案有代理层、中间件和应用层直连;须监控真实复制延迟、限制从库权限与负载、确保同步稳定性。

读写分离不是自动发生的,得靠应用层或中间件显式把 SELECT 请求发给从库,主库只处理 INSERT/UPDATE/DELETE。否则所有查询压在主库,CPU 和连接数很快飙高。
选对路由方式,别让架构反成负担
三种主流路径:代理层(如 ProxySQL)、中间件(如 ShardingSphere-JDBC)、应用层直连(如 Spring 的 AbstractRoutingDataSource)。代理层对业务透明,适合不想改代码的团队;中间件适合已用分库分表的复杂系统;应用层控制最灵活,但需统一规范——比如用 @Transactional(readOnly = true) 触发读库,同时注意事务内哪怕只读也会走主库。
- ProxySQL 支持 SQL 注释路由(如 /*+ READ_FROM_SLAVE */)或正则匹配 SELECT,但 SELECT FOR UPDATE 必须强制走主库,否则会报错
- 应用层若用多数据源,建议封装统一的读写标记机制(如 ThreadLocal + 注解),避免开发随意切换导致误走从库
- 不推荐直接用 MySQL Router 做核心路由——功能简单,缺乏延迟感知和自动摘除能力
盯住延迟,它决定读写分离是否真正有效
Seconds_Behind_Master 在大事务或 IO 压力下常失真,不能单靠它判断真实延迟。更可靠的做法是建一张心跳表:
- 主库每秒插入 INSERT INTO heartbeat(ts) VALUES (NOW())
- 从库查该记录时间戳与当前 NOW() 的差值,才是真实复制延迟
- 延迟超过 2 秒时,强一致性场景(如注册后立即查用户信息)必须绕过读写分离逻辑,直连主库
- 从库可调低 innodb_flush_log_at_trx_commit=2 和 sync_binlog=0 加速回放,但要接受极端宕机下最多丢 1 秒事务
从库不是“副主库”,得按角色设权限和负载
从库只该干一件事:快速、稳定地提供读服务。其他操作会破坏这个目标:
- 禁止在从库执行 ALTER TABLE 或 OPTIMIZE TABLE,这类操作会阻塞 SQL 线程,瞬间拉高延迟
- 大表 JOIN 查询尽量不下推到从库——CPU 和内存压力会拖慢复制线程,反而加剧延迟
- 从库账号必须仅限 SELECT 权限,且只允许应用服务器 IP 连接;绝不能复用主库管理员账号,否则等于暴露高危入口
- 从库配置中务必开启 read_only = ON,防止误写;同时设 log_slave_updates = 1,方便级联复制
复制本身要稳,才能撑起读写分离
主从同步质量直接决定读写分离的可用性:
- binlog 格式必须用 ROW,避免语句级复制在函数、触发器等场景下的不一致风险
- 启用并行复制(slave_parallel_workers > 0),尤其在多库多表更新频繁时,能显著缩短延迟
- 半同步复制(semi-sync)值得开启——至少一个从库落盘才返回写成功,把延迟上限压到 1 秒内,代价是写响应时间略增
- 定期用 SHOW SLAVE STATUS 检查 Slave_IO_Running 和 Slave_SQL_Running 是否均为 Yes,任一为 No 都需立刻介入



















