主从复制

当单台 MySQL 服务器无法满足业务需求(如读请求量过大、担心单点故障导致数据丢失)时,主从复制 是最基础的解决方案。其核心逻辑是:主库(Master)写入数据,从库(Slave)实时同步主库数据,实现 “数据备份”“读写分离”(主库写、从库读)“故障转移”(主库挂了,从库可切换为主库)。

1.核心概念

角色定义:

  • 主库(Master):唯一的写入节点,所有数据变更(DML/DDL)均在主库执行,同时将变更记录到 二进制日志
  • 从库(Slave):1 个或多个读取节点,通过 “IO 线程” 从主库拉取二进制日志,通过 “SQL 线程” 执行日志中的变更,实现与主库数据一致。

核心目标:

  1. 数据备份:从库相当于主库的实时备份,主库故障时可从从库恢复数据。
  2. 读写分离:主库负责写操作(INSERT/UPDATE/DELETE),从库负责读操作(SELECT),分摊主库压力,提升并发能力。
  3. 故障转移:主库宕机后,可将其中一个从库升级为主库,保证业务连续性。

2.原理

主从复制的本质是 “从库模拟主库的操作”,整个过程通过 3 个线程(主库 1 个、从库 2 个)协同完成,步骤如下:

  1. 主库记录二进制日志(binlog)

    当主库执行数据变更操作(如 INSERT)时,会先将操作记录到 二进制日志(binlog)中,同时给每条记录分配一个 “偏移量(Position)”,标记日志的位置。

  2. 从库 IO 线程拉取二进制日志

    从库启动后,会启动一个 IO 线程,该线程会连接主库的 “二进制日志 dump 线程”(主库自动创建),并请求主库发送 “从指定偏移量开始的二进制日志”。

    主库的 dump 线程收到请求后,会读取二进制日志内容,发送给从库的 IO 线程;从库 IO 线程将收到的日志内容写入本地的 中继日志(Relay Log)(中继日志是临时日志,避免直接操作主库日志导致冲突)。

  3. 从库 SQL 线程执行中继日志

    从库同时启动一个 SQL 线程,该线程会实时读取中继日志中的内容,解析出具体的 SQL 语句,并在从库上执行这些语句,最终实现从库数据与主库一致。

关键结论:主从复制存在 微小延迟(IO 线程拉取日志、SQL 线程执行日志的时间差),通常在毫秒到秒级,大部分业务可接受;若需 “无延迟同步”,需使用 MySQL 8.0 后的 “GTID 复制” 或 “半同步复制”(进阶内容)。

3.常见问题

(1)主从延迟过大

主库执行数据变更后,从库需要较长时间(如几秒、几分钟)才能查询到变更结果。

常见原因

  1. 从库压力过大(大量读请求占用 CPU/IO,导致 SQL 线程执行缓慢)。
  2. 主库写入量过高(短时间内大量 DML 操作,二进制日志生成速度超过从库同步速度)。
  3. 大事务(主库执行耗时较长的大事务,如批量插入 10 万条数据,从库需等待整个事务执行完成才能同步)。

解决方案

优化从库:给从库配置更高性能的硬件(CPU、SSD),或增加从库数量(通过 “一主多从” 分摊读压力)。

拆分大事务:将主库的大事务拆分为多个小事务,减少单次同步耗时。

启用并行复制(MySQL 5.7+):通过 slave_parallel_workers = 4(配置 4 个并行 SQL 线程),让从库可并行执行多个事务,提升同步效率(需配合 binlog_format=ROW)。

(2)主从数据不一致

主库有某条数据,从库没有;或主从数据字段值不同,导致 Slave_SQL_Running: No

常见原因

  1. 从库开启了写操作(未设置 read_only=ON,误在从库插入 / 修改数据)。
  2. 主库执行了从库不支持的 SQL(如主库使用自定义函数,从库未创建该函数)。
  3. 主从复制中断后未正确恢复(如主库日志文件被删除,从库无法找到同步起点)。

解决方案

  1. 紧急恢复,通过主库全量备份初始化从库(推荐使用 mysqldump 工具)

    主库执行备份:mysqldump -u root -p --all-databases --lock-all-tables > master_backup.sql--lock-all-tables 确保备份期间数据不变化)。

    复制备份文件到从库:scp master_backup.sql root@192.168.1.101:/tmp/

    从库恢复备份:mysql -u root -p < /tmp/master_backup.sql,之后重新执行 CHANGE MASTER TO 关联主库最新的日志位置。

  2. 长期预防

    从库严格设置 read_only=ON,并限制超级权限用户的使用(避免通过 root 账号在从库写数据)。

    定期使用工具检查数据一致性(如 pt-table-checksum,自动对比主从表数据,发现不一致时生成修复语句)。

(3)主库二进制日志丢失

主库二进制日志文件被误删除(或因磁盘故障损坏),导致从库 IO 线程无法拉取日志,同步中断。

解决方案

若主库有全量备份:先通过备份恢复主库数据,然后重新配置主从复制(从备份对应的日志位置开始同步)。

若主库无备份:需先确保主从数据一致(手动对比主从关键表数据),然后在主库执行 reset master;(重置二进制日志,生成新的 mysql-bin.000001),再在从库重新执行 CHANGE MASTER TO 关联新的日志文件和位置(注意:reset master; 会清空主库所有二进制日志,仅在无备份且数据一致时使用)。

4.进阶优化

基础主从复制仅能满足 “数据同步” 需求,生产环境需结合以下优化提升稳定性和可用性:

(1)启用 GTID 复制(MySQL 5.6+)

问题背景:传统复制依赖 “日志文件 + 偏移量” 定位同步位置,若主库日志文件丢失或切换,从库需重新手动查找同步起点,操作复杂且易出错。

GTID 原理:GTID(Global Transaction ID)是全局唯一的事务 ID,每个事务在主库执行时会被分配一个 GTID,从库通过 GTID 定位同步位置,无需关注具体的日志文件和偏移量。

配置方法:在主库和从库的 my.cnf 中添加以下配置,重启服务后按基础步骤配置复制即可:

[mysqld]
gtid_mode=ON
enforce_gtid_consistency=ON  # 强制 GTID 一致性,避免非 GTID 事务
(2)启用半同步复制(MySQL 5.5+,需安装插件)

问题背景:传统复制是 “异步复制”—— 主库执行事务后立即返回结果给客户端,不等待从库同步,若主库宕机时从库未同步完事务,会导致数据丢失。

半同步复制原理:主库执行事务后,会等待至少一个从库将事务日志写入中继日志(并返回确认),再返回结果给客户端,确保 “主库宕机时,至少有一个从库拥有完整数据”,降低数据丢失风险。

配置方法:

  1. 主库安装并启用半同步插件:

    INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
    SET GLOBAL rpl_semi_sync_master_enabled = 1;
    SET GLOBAL rpl_semi_sync_master_timeout = 1000;  # 超时时间(1秒),若超过1秒未收到从库确认,自动降级为异步复制
  2. 从库安装并启用半同步插件:

    INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
    SET GLOBAL rpl_semi_sync_slave_enabled = 1;
    STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;  # 重启 IO 线程使插件生效
分类: Java-Backend 标签: MySQL

评论

暂无评论数据

暂无评论数据

目录