1. 读写分离的本质与业务痛点
当数据库访问量突破单机性能上限时,最直接的感受就是系统响应变慢、超时增多。去年我们电商大促时就遇到过这种情况:凌晨秒杀活动开始后,订单库的CPU直接飙到100%,大量用户卡在支付页面转圈圈。事后分析发现,当时95%的请求都是查询订单状态的读操作,真正下单的写操作只占5%。这种典型的"读多写少"场景,正是读写分离技术要解决的核心问题。
读写分离的基本思想很直观——把读和写的操作分流到不同的数据库实例上。主库(Master)负责处理INSERT、UPDATE、DELETE等写操作,从库(Slave)专门处理SELECT查询。就像餐厅把下单和取餐的流程分开:顾客在前台点单(写操作),然后去专门的取餐窗口排队(读操作),这样既避免了收银台拥堵,又提高了整体吞吐量。
2. 技术实现的三层架构
2.1 主从复制机制
MySQL的主从复制就像复印机工作流程:
- 主库的binlog记录所有数据变更(相当于原稿)
- 从库的IO线程实时拉取binlog(扫描原稿)
- 从库的SQL线程重放这些变更(打印复印件)
我们曾经踩过一个坑:某次大促前给商品表新增了索引,结果从库同步延迟突然飙升到10分钟。后来发现是因为主库用Online DDL加了索引,导致binlog量暴增。解决方法是用pt-online-schema-change工具分批处理。
2.2 流量分发策略
常见的路由方式有三种:
- 代码层封装:在DAO层通过注解或配置指定读写路由
java复制@ReadOnly
public List<Order> queryUserOrders(Long userId) {
// 自动路由到从库
}
- 中间件代理:比如用ShardingSphere的MasterSlaveRule配置
yaml复制masterSlaveRules:
ds_ms:
masterDataSourceName: master_ds
slaveDataSourceNames:
- slave_ds_0
- slave_ds_1
- 数据库驱动层:像MySQL Connector/J支持readFromMasterWhenNoSlaves参数
2.3 一致性保障方案
读写分离最头疼的就是主从延迟问题。我们遇到过用户刚下单后立即查询却显示未支付的客诉,后来采用了这些方案:
- 关键业务强制读主库(比如支付结果查询)
- 根据GTID判断从库是否已同步
- 使用HLC(Hybrid Logical Clock)时间戳判断
3. 生产环境部署要点
3.1 从库扩容策略
当QPS达到5万+时,我们采用树状复制结构:
code复制Master -> Slave1 (L1)
-> Slave2 (L1) -> Slave3 (L2)
-> Slave4 (L2)
这样既缓解了主库复制压力,又能实现机房就近读取。但要注意级联复制会增加延迟,需要监控每个节点的Seconds_Behind_Master值。
3.2 故障转移方案
去年某次机房断电时,我们的切换流程是:
- 监控系统检测到主库不可用(30秒超时)
- 自动禁用读写分离中间件的写路由
- 提升从库为新的主库(先执行STOP SLAVE,再RESET MASTER)
- 其他从库CHANGE MASTER到新主库
- 应用层配置热更新
关键是要保证binlog位置正确,我们每次切换后都会用pt-table-checksum校验数据一致性。
4. 典型问题排查实录
4.1 从库延迟飙升
现象:监控显示Slave延迟持续超过5分钟
排查步骤:
- 检查主库写入量(show master status)
- 分析从库性能(top -H查看SQL线程CPU)
- 检查网络延迟(tcpdump抓包)
- 查看是否有大事务(show processlist)
最近一次原因是开发在主库执行了百万级UPDATE,我们后来加了这些限制:
sql复制-- 限制单次操作行数
SET SESSION sql_safe_updates=1;
-- 大事务拆分批处理
UPDATE orders SET status=1 WHERE id BETWEEN 1 AND 10000;
COMMIT;
4.2 读负载不均
当使用多个从库时,经常出现某些实例负载过高。我们的解决方案是:
- 在代理层增加权重配置
yaml复制slaveDataSourceNames:
- slave_ds_0:weight=30
- slave_ds_1:weight=70
- 实现基于SQL指纹的路由,把复杂查询导向高性能实例
- 定期轮训从库性能指标自动调整权重
5. 架构演进建议
对于日均百万级请求的系统,我们逐步演进到这样的架构:
- 写操作:主库集群(双主互相同步)
- 实时读:Redis集群+本地缓存
- 准实时读:从库集群(延迟控制在1秒内)
- 离线分析:通过CDC同步到数据仓库
这种混合架构既保证了核心业务的实时性,又减轻了数据库压力。最近我们还在测试MySQL Group Replication,它的多主模式可以避免单点故障。