1. MySQL主从复制与读写分离实战指南
在数据库架构设计中,高可用性和性能扩展是永恒的主题。作为最流行的开源关系型数据库,MySQL通过主从复制(Master-Slave Replication)和读写分离(Read-Write Splitting)机制,为中小规模应用提供了经济高效的解决方案。我在电商和金融行业的多套生产环境中,这套方案成功支撑了日均百万级请求的业务场景。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 主从复制原理与配置
2.1 复制工作原理剖析
MySQL主从复制的核心是基于二进制日志(binlog)的异步复制机制。当主库执行写操作时,所有数据变更会以事件形式记录到binlog中。从库的I/O线程会实时拉取这些日志,并写入本地的中继日志(relay log),最后由SQL线程重放这些事件实现数据同步。
关键点:建议使用ROW格式的binlog,相比STATEMENT格式能更好处理非确定性函数(如NOW())和存储过程的复制
2.2 详细配置步骤
主库配置(my.cnf):
ini复制[mysqld]
server-id = 1
log_bin = mysql-bin
binlog_format = ROW
sync_binlog = 1
binlog_group_commit_sync_delay = 100
binlog_group_commit_sync_no_delay_count = 10
从库配置:
sql复制CHANGE MASTER TO
MASTER_HOST='master_ip',
MASTER_USER='repl_user',
MASTER_PASSWORD='repl_password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;
START SLAVE;
2.3 复制模式选择
- 异步复制:默认模式,主库不等待从库确认
- 半同步复制:至少一个从库接收后主库才返回
- 组复制:基于Paxos协议的多主同步
生产环境建议:金融类业务使用半同步,一般业务用异步+延迟监控
3. 读写分离实现方案
3.1 客户端分片
在应用层通过代码逻辑区分读写路由:
java复制// Spring配置示例
@Bean
public AbstractRoutingDataSource routingDataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource());
targetDataSources.put("slave", slaveDataSource());
AbstractRoutingDataSource ds = new AbstractRoutingDataSource() {
@Override
protected Object determineCurrentLookupKey() {
return TransactionSynchronizationManager.isCurrentTransactionReadOnly()
? "slave" : "master";
}
};
ds.setTargetDataSources(targetDataSources);
return ds;
}
3.2 中间件方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| MySQL Router | 官方维护,轻量级 | 功能简单 | 简单分片需求 |
| ProxySQL | 灵活配置,支持缓存 | 需要额外维护 | 中大型复杂架构 |
| ShardingSphere | 完整生态,支持分库分表 | 学习成本高 | 分布式系统 |
3.3 负载均衡策略
- 轮询:均匀分配查询压力
- 权重分配:根据服务器配置差异化
- 会话保持:同一会话固定访问同从库
- 延迟感知:自动避开高延迟节点
4. 生产环境优化实践
4.1 主从延迟解决方案
-
并行复制:启用slave_parallel_workers
sql复制STOP SLAVE; SET GLOBAL slave_parallel_workers = 8; START SLAVE; -
GTID复制:避免位点错乱
ini复制[mysqld] gtid_mode = ON enforce_gtid_consistency = ON -
延迟监控:配置Prometheus告警
yaml复制- alert: HighSlaveLag expr: mysql_slave_status_seconds_behind_master > 30 for: 5m
4.2 连接池配置要点
java复制// HikariCP推荐配置
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(50); // 写库建议较小连接数
config.setConnectionTimeout(3000);
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
5. 故障排查手册
5.1 常见错误代码处理
| 错误代码 | 原因 | 解决方案 |
|---|---|---|
| 1236 | binlog位置不匹配 | 重建复制或用MASTER_AUTO_POSITION |
| 1062 | 主键冲突 | 检查双写或设置slave_skip_errors |
| 1593 | 网络中断 | 检查网络并重连 |
5.2 数据一致性校验
使用pt-table-checksum工具:
bash复制pt-table-checksum \
--replicate=test.checksums \
--no-check-binlog-format \
--databases=orders \
h=master_host,u=check_user,p=password
修复不一致数据:
bash复制pt-table-sync --replicate test.checksums \
h=master_host,u=admin,p=password \
--sync-to-master h=slave_host
6. 架构演进建议
当单主架构遇到瓶颈时,可考虑:
- 级联复制:Master → Relay Slave → Leaf Slave
- 多源复制:多个主库同步到汇总库
- MGR集群:MySQL Group Replication实现多主写入
在Kubernetes环境中,可结合Orchestrator实现自动故障转移:
yaml复制apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 3
template:
spec:
containers:
- name: mysql
args:
- --gtid-mode=ON
- --log-slave-updates=ON
- --enforce-gtid-consistency=ON
- --server-id=$(hostname | sed 's/mysql-//')
