MySQL 主从复制本身不提供读写分离功能
主从复制只是数据同步机制,
INSERT/
UPDATE/
DELETE写操作必须发往主库,
SELECT读操作可以发往从库——但这个路由决策不在 MySQL 自带能力范围内。MySQL 官方没有内置读写分离代理或驱动层自动路由,必须靠外部组件或应用层控制。
常见读写分离实现方式及选型要点
实际落地有三类主流路径,各自适用不同阶段和约束:
应用层硬编码:在业务代码中显式指定数据源,比如用masterDataSource和
slaveDataSource两个连接池,DAO 层按方法名(如
getUserById)或注解(如
@ReadOnly)分发。适合小团队、强可控场景,但侵入性强、易出错 中间件代理:部署
ProxySQL或
MaxScale,配置规则将
SELECT转发到从库、其余语句打向主库。需注意:
SELECT ... FOR UPDATE必须走主库,否则会报
Lock wait timeout exceeded;事务内所有语句默认应落在同一节点,ProxySQL 的
transaction_persistent需开启 智能驱动(如 ShardingSphere-JDBC):以 JDBC Driver 形式嵌入应用,通过配置
readwrite-splitting规则实现透明路由。优势是零代理运维,缺点是升级驱动版本可能影响 SQL 兼容性,且对
UNION ALL、子查询等复杂语句的解析存在边界 case
从库延迟导致读取脏数据的应对策略
即使读写分离配置正确,从库延迟(
Seconds_Behind_Master > 0)仍会让应用读到过期数据。这不是配置问题,而是架构权衡: 监控必须覆盖
Seconds_Behind_Master,告警阈值建议设为 5 秒以上(取决于业务容忍度) 对一致性要求高的读操作(如订单支付后查状态),强制走主库,可用
/*+ FORCE_MASTER */注释(ProxySQL 支持)或应用层直连
masterDataSource避免依赖从库做“先读后写”逻辑,例如
SELECT count(*) FROM t WHERE status=1后再
INSERT,这类场景本质不适合读写分离
主从角色切换后读写分离链路是否自动恢复?
不会自动恢复。当发生主从切换(如 MHA、Orchestrator 故障转移后),原主库变从库、原从库变主库,但 ProxySQL 或应用里的连接池仍按旧地址和角色缓存工作:
ProxySQL 需配合脚本监听mysql_servers表变更,或通过
mysql_replication_host_groups+
monitor_username自动识别新主 ShardingSphere-JDBC 依赖注册中心(ZooKeeper/Nacos)感知拓扑变化,若未启用
orchestration模块,则需重启应用 最稳妥的做法仍是把主从地址抽象为逻辑名(如
mysql-primary、
mysql-replica),由服务发现或 DNS 动态解析,而非写死 IP+端口 真正难的不是配通读写分离,而是厘清哪些读可以下推、哪些必须保主、以及切换后如何让整个链路不裂开。这些细节往往在压测或故障时才暴露。
