MySQL主从复制与读写分离实战指南

深入理解MySQL主从复制原理、配置步骤以及读写分离的实现方案,附完整配置示例

一、背景

在面对高并发读写场景时,单一数据库实例往往成为系统瓶颈。主从复制 + 读写分离是解决这一问题的经典方案,也是后端开发者进阶必须掌握的核心技能。

二、主从复制原理

2.1 核心概念

MySQL主从复制基于binlog日志实现,主要包含三个线程:

线程 作用 所在节点
Binlog Dump 读取binlog并发送给从库 主库
IO Thread 接收主库发送的binlog 从库
SQL Thread 重放relay log中的SQL 从库

2.2 复制流程

复制代码
主库: INSERT → binlog → Binlog Dump →──────→ IO Thread → relay log → SQL Thread → 从库
  1. 主库执行SQL,生成binlog
  2. Binlog Dump线程读取binlog,发送给从库
  3. 从库IO线程接收,写入relay log
  4. 从库SQL线程重放relay log中的SQL

2.3 复制模式

模式 特点 异步/同步
异步复制 主库不等待从库确认 异步
半同步复制 主库等待至少一个从库确认 半同步
全同步复制 主库等待所有从库确认 同步

三、实战配置

3.1 环境说明

复制代码
192.168.1.10  - 主库 (Master)
192.168.1.20  - 从库 (Slave)

3.2 主库配置

bash 复制代码
# /etc/mysql/my.cnf
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin
binlog_format = ROW
sync_binlog = 1

3.3 创建复制账号

sql 复制代码
-- 主库执行
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

3.4 从库配置

bash 复制代码
# /etc/mysql/my.cnf
[mysqld]
server-id = 2
relay_log = /var/log/mysql/mysql-relay-bin
read_only = 1

3.5 启动复制

sql 复制代码
-- 从库执行
CHANGE MASTER TO
    MASTER_HOST='192.168.1.10',
    MASTER_USER='repl',
    MASTER_PASSWORD='repl_password',
    MASTER_LOG_FILE='mysql-bin.000001',
    MASTER_LOG_POS=154;

START SLAVE;
SHOW SLAVE STATUS\G;

关键检查点:

  • Slave_IO_Running: Yes
  • Slave_SQL_Running: Yes
  • Seconds_Behind_Master: 0

四、读写分离实现

4.1 方案对比

方案 优点 缺点 适用场景
应用层代理 无单点、性能好 需要修改代码 中大型项目
中间件代理 透明接入 有性能损耗 快速接入
数据库中间件 支持分库分表 配置复杂 超大规模

4.2 Spring Boot实现

java 复制代码
@Configuration
public class DataSourceConfig {
    
    @Autowired
    private DataSourceProperties properties;
    
    @Bean
    public DataSource dataSource() {
        AbstractRoutingDataSource routingDataSource = 
            new AbstractRoutingDataSource() {
                @Override
                protected Object determineCurrentLookupKey() {
                    return RoutingContext.isWrite() ? "master" : "slave";
                }
            };
        
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", createDataSource(properties.getMaster()));
        targetDataSources.put("slave", createDataSource(properties.getSlave()));
        
        routingDataSource.setTargetDataSources(targetDataSources);
        return routingDataSource;
    }
}

4.3 路由切粒

java 复制代码
public class RoutingContext {
    private static final ThreadLocal<Boolean> isWrite = new ThreadLocal<>();
    
    public static void setWrite(boolean write) {
        isWrite.set(write);
    }
    
    public static boolean isWrite() {
        return Boolean.TRUE.equals(isWrite.get());
    }
    
    public static void clear() {
        isWrite.remove();
    }
}

Service层使用:

java 复制代码
@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Transactional
    public void saveUser(User user) {
        RoutingContext.setWrite(true);
        userMapper.insert(user);
    }
    
    public User getUserById(Long id) {
        RoutingContext.setWrite(false);
        return userMapper.selectById(id);
    }
}

五、常见问题与解决方案

5.1 主从延迟

症状: 从库延迟超过100ms

排查:

sql 复制代码
SHOW SLAVE STATUS\G;
-- 查看 Seconds_Behind_Master

解决方案:

  • 开启并行复制:slave_parallel_workers > 0
  • 优化主库大事务:分批提交
  • 确认网络延迟

5.2 数据不一致

原因:

  • 主从切换未同步
  • 复制中断未处理
  • 双写导致

修复方案:

bash 复制代码
# 重新同步
mysqldump --master-data=2 -h master -u root -p > backup.sql
mysql -h slave -u root -p < backup.sql

5.3 relay log损坏

恢复步骤:

sql 复制代码
STOP SLAVE;
RESET SLAVE;
CHANGE MASTER TO ...;
START SLAVE;

六、总结

核心要点:

  1. 主从复制基于binlog实现,有异步、半同步、同步三种模式
  2. 配置时注意server-id唯一,row格式binlog更安全
  3. 读写分离通过数据源路由实现,需处理事务边界
  4. 监控主从延迟,设置告警阈值

进阶方向:

  • MGR(MySQL Group Replication)
  • Binlog Server架构
  • 分库分表中间件(ShardingSphere、MyCAT)
相关推荐
qing222222224 小时前
Linux中修改mysql数据表
linux·运维·mysql
J2虾虾4 小时前
MySQL的基本操作
数据库·mysql
2601_949815335 小时前
MySQL输入密码后闪退?
数据库·mysql·adb
_下雨天.6 小时前
MySQL高可用
数据库·mysql
霖霖总总7 小时前
[小技巧52]从 SQL 到结果:MySQL 8.0 查询执行全流程深度剖析
sql·mysql
gjc5927 小时前
零基础OceanBase数据库入门(5):MySQL模式用户创建与权限管理
数据库·mysql·oceanbase
AC赳赳老秦7 小时前
OpenClaw二次开发入门:自定义技能,适配自身工作需求
服务器·数据库·python·mysql·django·deepseek·openclaw
我真会写代码7 小时前
MySQL8聚簇索引与非聚簇索引深度解析:从原理到实战,避开90%的索引踩坑点
mysql·uuid
学编程就要猛8 小时前
MySQL:CRUD(上)
数据库·mysql
Dxy12393102168 小时前
Python正则表达式判断姓名:详细解析
python·mysql·正则表达式