读写分离如何在业务中落地?
0. 引言
绝大多数业务是读多写少(读:写可达 10:1 甚至更高)。读写分离的核心思路:主库承接写,从库承接读,通过主从复制把写入同步到只读副本,把读压力横向摊开。它是数据库扩展的第一级台阶(比分库分表简单、成本低)。本文讲解复制原理、路由落地与主从延迟的治理。
1. 为什么需要读写分离
| 痛点 | 读写分离的收益 |
|---|---|
| 单库连接数打满、读 QPS 高 | 读流量分发到 N 个从库,容量线性扩展 |
| 慢查询拖垮写入 | 分析查询(报表/统计)打到从库,主库专注 OLTP |
| 备份/分析任务影响线上 | 从库承担备份导出、数据仓库 ETL |
2. 主从复制原理(基于 binlog)
图表渲染中…
| 版本 | 复制方式 | 说明 |
|---|---|---|
| 5.6+ | GTID 复制 | 全局事务 ID,主从切换无需手动找 binlog 位点 |
| 5.7+ | 多源复制 / 并行复制 | 从库多线程回放,缓解延迟 |
| 8.0 | 并行复制增强(WRITESET)、CHANGE REPLICATION SOURCE TO 新语法 | 语句级/事务级并行,主从延迟大幅下降 |
sql
-- MySQL 8.0 GTID 复制配置(从库)
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='10.0.0.1', SOURCE_PORT=3306,
SOURCE_USER='repl', SOURCE_PASSWORD='xxx',
SOURCE_AUTO_POSITION=1;
START REPLICA;复制异步性根源:主库提交即返回,从库异步回放——**主从延迟(Seconds_Behind_Source)**由此而来,是读写分离必须面对的问题。
3. 读写路由的两种落地方式
3.1 应用层路由(代码/框架)
java
// ShardingSphere-JDBC 示例:一主一从
spring.shardingsphere.rules.readwrite-splitting.data-sources.rw.master-data-source-name=ds-master
spring.shardingsphere.rules.readwrite-splitting.data-sources.rw.slave-data-source-names=ds-slave-0,ds-slave-1
spring.shardingsphere.rules.readwrite-splitting.data-sources.rw.load-balancer-name=round_robin- 优点:性能优(直连数据库)、灵活(可编程路由规则);
- 缺点:侵入应用(引入 SDK)、多语言需各自实现。
3.2 中间件路由(代理层)
| 中间件 | 说明 |
|---|---|
| ProxySQL | MySQL 原生代理:读写分离、连接池、故障转移,规则灵活 |
| ShardingSphere-Proxy | 兼容 MySQL 协议,读写分离 + 分库分表一体 |
| MyCat | 老牌中间件,读写分离 + 分片 |
- 优点:应用零侵入、集中管理、多语言通用;
- 缺点:多一跳代理(延迟 + 运维成本)、要保高可用(代理自身不能单点)。
4. 主从延迟:读写分离的头号问题
4.1 问题场景
text
用户下单成功(写主库)→ 立即查询订单(路由到从库)→ 复制未完成 → 查不到!4.2 解决方案
| 方案 | 说明 | 适用 |
|---|---|---|
| 关键读走主库 | 订单/支付等强一致读强制路由主库 | 资金、订单类核心链路 |
| 延迟容忍 | 设置读从库延迟阈值,超阈值自动切主库(ShardingSphere hint) | 通用 |
| 半同步复制 | rpl_semi_sync_source_enabled=ON:主库等至少一个从库 ack 再提交 | 缩小延迟窗口 |
| 缓存标记 | 写后 1s 内读缓存(Redis 写后置),避开窗口期 | 高并发场景 |
| 并行复制调优 | 8.0 开启 WRITESET 并行,减少从库回放延迟 | 大事务多的系统 |
通用原则:能容忍延迟的读走从库,不能容忍的读走主库——路由规则要按"数据维度"配置,而不是一刀切。
5. 落地检查清单
- 从库只读(
read_only=ON,防误写造成主从不一致) - 监控主从延迟(
SHOW REPLICA STATUS的 Seconds_Behind_Source + 延迟告警) - 链路保活:从库宕机自动摘除(健康检查)
- 复制冲突处理:从库唯一索引冲突(如重复插入)及时告警
- 主库 binlog 保留策略(
binlog_expire_logs_seconds,8.0 按秒配置)
6. 小结
- 读写分离 = 主库写 + 从库读 + binlog 复制,是读扩展的第一级台阶;
- 落地两种方式:应用层 SDK(ShardingSphere-JDBC) 与 代理中间件(ProxySQL);
- 核心问题是主从延迟:关键读走主库、半同步缩小窗口、并行复制降延迟;
- 8.0 建议 GTID + 增强并行复制,监控延迟与复制异常是运维底线。
下一章讲解分库分表:为什么拆分、如何拆分与中间件选型。