SQL读写分离优化与主从负载均衡策略,是解决数据库高并发访问瓶颈的常用手段。其核心思想是把写操作交给主库,把读操作分散到多个从库,通过主从复制保持数据同步,再借助负载均衡算法将读流量合理调度。

一、读写分离的基本架构
在典型的主从架构中,主库负责 INSERT、UPDATE、DELETE 等写操作,并通过 binlog 或 WAL 将变更同步给一个或多个从库。从库承接 SELECT 查询,从而实现写读压力的拆分。
1.1 常见部署形态
- 一主一从:适合读压力中等的业务
- 一主多从:适合读多写少、读流量大的场景
- 多级从库:从库之下再挂从库,减轻主库同步负担
二、主从负载均衡策略
当存在多个从库时,需要决定把读请求发给哪一个节点。常用策略如下:
| 策略 | 说明 | 优缺点 |
|---|---|---|
| 轮询 | 依次将请求分给每个从库 | 简单,但忽略节点真实负载 |
| 加权轮询 | 按机器性能配置权重 | 兼顾异构机器,仍无实时反馈 |
| 最小连接数 | 发给当前连接最少的节点 | 更均衡,但需维护状态 |
| 健康检查路由 | 屏蔽故障或延迟过高节点 | 提升可用性,依赖探测机制 |
2.1 基于中间件的实现示例
使用代理层(如 MySQL Router 思路)做路由时,可参考下面简化逻辑:
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
// 简单的加权轮询负载均衡器
public class ReadLoadBalancer {
private List<String> slaves; // 从库地址列表
private List<Integer> weights;
private AtomicInteger current = new AtomicInteger(0);
public ReadLoadBalancer(List<String> slaves, List<Integer> weights) {
this.slaves = slaves;
this.weights = weights;
}
// 获取下一个应处理的从库
public String nextSlave() {
int total = weights.stream().mapToInt(Integer::intValue).sum();
int idx = current.getAndIncrement() % total;
int sum = 0;
for (int i = 0; i < slaves.size(); i++) {
sum += weights.get(i);
if (idx < sum) {
return slaves.get(i);
}
}
return slaves.get(0);
}
}
三、读写分离中的关键问题
3.1 主从延迟
由于复制存在延迟,刚写入主库的数据可能在从库查不到。对于强一致要求的接口,可通过 强制走主库 或 写后读主 策略规避。在代码层可用注解标记:
# 伪代码:读策略路由
def query(sql, force_master=False):
if sql.strip().lower().startswith("select") and not force_master:
return slave_db.execute(sql) # 走从库
else:
return master_db.execute(sql) # 走主库
3.2 故障转移
某从库宕机时,负载均衡器应将其剔除,并周期性探活。主库故障时则需借助 MHA 或 Orchestrator 等工具做主从切换。
四、优化建议
- 监控主从延迟,设置阈值告警
- 读流量按业务重要级分组,核心读可绑定低延迟从库
- 避免大事务,减少复制阻塞
- 在 ORM 层封装数据源路由,降低业务侵入
通过合理的 SQL 读写分离设计与主从负载均衡策略,可以显著提升数据库集群的整体吞吐与稳定性,但必须结合业务特性持续调优。