MYSQL 主从复制配置指南

MYSQL 主从复制配置指南

MYSQL 主从复制配置指南

适用于 ARM64 架构 Debian 13 (trixie) 环境 MySQL 8.0.41 Community Server (通用二进制安装)


一、部署环境

1.1 服务器信息

角色 IP 主机名 系统 架构 MySQL版本
服务器A 10.211.55.5 Debian (trixie) Debian 13 aarch64 8.0.41
服务器B 10.211.55.9 Debian (trixie) Debian 13 aarch64 8.0.41

1.2 MySQL 安装过程回顾

由于 Oracle 官方从未为 ARM64 架构发布过 MySQL APT/RPM 包(所有 MySQL 版本的 APT 仓库仅支持 amd64i386),本环境采用 通用二进制包(Generic Linux Tarball) 方式安装。

安装步骤摘要:

# 1. 下载 MySQL 8.0.41 ARM64 通用二进制包
wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.41-linux-glibc2.28-aarch64.tar.xz

# 2. 解压到 /usr/local
tar xf mysql-8.0.41-linux-glibc2.28-aarch64.tar.xz -C /usr/local/
ln -sf /usr/local/mysql-8.0.41-linux-glibc2.28-aarch64 /usr/local/mysql

# 3. 安装系统依赖(ARM64 下 MySQL 8.0 仅缺 libnuma)
apt-get install -y libnuma1 libncurses6 libaio1t64
ln -sf /usr/lib/aarch64-linux-gnu/libaio.so.1t64 /usr/lib/aarch64-linux-gnu/libaio.so.1

# 4. 创建 mysql 用户和目录
groupadd -r mysql && useradd -r -g mysql -s /bin/false mysql
mkdir -p /var/lib/mysql /var/log/mysql /var/run/mysqld
chown -R mysql:mysql /var/lib/mysql /var/log/mysql /var/run/mysqld

# 5. 初始化 MySQL(--initialize-insecure 生成空 root 密码)
/usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysql

# 6. 配置 systemd 服务
cat > /etc/systemd/system/mysql.service << 'EOF'
[Unit]
Description=MySQL Server
After=network.target

[Service]
Type=notify
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --datadir=/var/lib/mysql \
   --socket=/var/run/mysqld/mysqld.sock --port=3306
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload && systemctl enable mysql && systemctl start mysql

# 7. 配置 PATH
echo 'export PATH=/usr/local/mysql/bin:$PATH' > /etc/profile.d/mysql.sh

当前配置基线(两台服务器相同):

# /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
port=3306
user=mysql
log-error=/var/log/mysql/error.log
pid-file=/var/run/mysqld/mysqld.pid

[client]
socket=/var/run/mysqld/mysqld.sock

两台服务器的 MySQL 目前是 独立运行 的,server_id 均为默认值 1,彼此无复制关系。本文档将在此基础上配置各种复制拓扑。


二、MYSQL 复制核心概念

2.1 什么是 MySQL 复制

MySQL 复制(Replication)是指将一台 MySQL 服务器(主库 / Master)上的数据变更,通过二进制日志(Binary Log)同步到另一台或多台服务器(从库 / Slave)上的过程。

2.2 复制原理(三步走)

主库 (Master)                      从库 (Slave)
───────────                       ───────────
① 数据变更写入 binlog ──推送──→   ② I/O 线程拉取 binlog 写入 relay log
                                ③ SQL 线程回放 relay log 中的事件
  • Binary Log (binlog):主库记录所有数据修改事件的日志文件

  • I/O 线程:从库上运行的线程,负责从主库拉取 binlog 并写入 relay log

  • Relay Log:从库上暂存主库 binlog 事件的中转日志

  • SQL 线程:从库上运行的线程,负责读取 relay log 并在从库上执行

2.3 复制模式

模式 binlog_format 特点
基于语句 (SBR) STATEMENT 记录 SQL 语句本身,日志小但某些函数可能导致不一致
基于行 (RBR) ROW 记录每行数据的实际变更,一致性强但日志大(当前默认)
混合模式 (MBR) MIXED 默认用 STATEMENT,必要时自动切换为 ROW

2.4 复制方式

方式 原理 优点 缺点
基于 binlog 位置 记录 binlog 文件名 + 偏移量 简单直接 切换主库时需手动计算位置
基于 GTID 每个事务分配全局唯一 ID 自动定位,故障切换简单 需要 GTID 模式开启

本文档两种方式都会介绍。


三、一主一从(MASTER-SLAVE)

┌──────────┐          binlog          ┌──────────┐
│ Master │ ───────────────────────→ │ Slave   │
│ .55.5   │     (只读副本)           │ .55.9   │
│ 读写     │                         │ 只读     │
└──────────┘                         └──────────┘

概念: 最经典的复制拓扑。主库处理所有写操作,从库作为只读副本,用于数据备份、报表查询或读写分离中的”读”负载。MySQL 默认的异步复制就是这种模式。

3.1 基于 binlog 位置的配置方式

3.1.1 主库配置(10.211.55.5)

编辑 /etc/my.cnf,在 [mysqld] 段添加:

[mysqld]
# === 基础配置(已有) ===
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
port=3306
user=mysql

# === 复制相关配置(新增) ===
server-id = 1                     # 服务器唯一 ID,主从必须不同
log_bin = /var/lib/mysql/binlog   # 开启二进制日志(前缀,实际文件 binlog.000001)
binlog_format = ROW               # 基于行的复制(推荐)
expire_logs_days = 7               # binlog 保留天数
max_binlog_size = 500M             # 单个 binlog 文件最大大小
sync_binlog = 1                   # 每次事务都同步 binlog 到磁盘(安全但略慢)

重启 MySQL:

systemctl restart mysql

创建复制专用账号:

-- 在主库上执行
CREATE USER 'repl'@'10.211.55.%' IDENTIFIED BY 'Repl@123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.211.55.%';
FLUSH PRIVILEGES;

-- 查看主库当前 binlog 位置(记下来,从库配置要用)
SHOW MASTER STATUS;
-- +---------------+----------+
-- | File         | Position |
-- +---------------+----------+
-- | binlog.000001 |     857 |
-- +---------------+----------+

3.1.2 从库配置(10.211.55.9)

编辑 /etc/my.cnf,在 [mysqld] 段添加:

[mysqld]
# === 基础配置(已有) ===
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
port=3306
user=mysql

# === 复制相关配置(新增) ===
server-id = 2                     # 必须与主库不同
relay_log = /var/lib/mysql/relay   # 中继日志前缀
log_bin = /var/lib/mysql/binlog   # 从库也开 binlog(便于以后提升为主库)
read_only = ON                     # 从库只读(root 和复制线程不受限)

重启 MySQL:

systemctl restart mysql

在从库上配置复制关系:

-- 在从库上执行
CHANGE MASTER TO
  MASTER_HOST = '10.211.55.5',
  MASTER_USER = 'repl',
  MASTER_PASSWORD = 'Repl@123456',
  MASTER_LOG_FILE = 'binlog.000001',   -- 来自主库 SHOW MASTER STATUS 的 File
  MASTER_LOG_POS = 857;                -- 来自主库 SHOW MASTER STATUS 的 Position

-- 启动复制
START SLAVE;

-- 检查复制状态
SHOW SLAVE STATUS\G

关键指标:

Slave_IO_Running: Yes        ← I/O 线程正常运行
Slave_SQL_Running: Yes       ← SQL 线程正常运行
Seconds_Behind_Master: 0     ← 复制延迟(0 表示实时同步)

3.2 基于 GTID 的配置方式(推荐)

GTID (Global Transaction Identifier) 让每个事务有全局唯一编号,从库不需要手动指定 binlog 位置。

3.2.1 主库配置(10.211.55.5)

[mysqld]
server-id = 1
log_bin = /var/lib/mysql/binlog
binlog_format = ROW

# === GTID 配置 ===
gtid_mode = ON
enforce_gtid_consistency = ON

重启:

systemctl restart mysql

创建复制账号(同上):

CREATE USER 'repl'@'10.211.55.%' IDENTIFIED BY 'Repl@123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.211.55.%';

3.2.2 从库配置(10.211.55.9)

[mysqld]
server-id = 2
relay_log = /var/lib/mysql/relay
log_bin = /var/lib/mysql/binlog
read_only = ON

# === GTID 配置 ===
gtid_mode = ON
enforce_gtid_consistency = ON

重启后在从库执行:

-- GTID 方式不需要指定 binlog 文件和位置
CHANGE MASTER TO
  MASTER_HOST = '10.211.55.5',
  MASTER_USER = 'repl',
  MASTER_PASSWORD = 'Repl@123456',
  MASTER_AUTO_POSITION = 1;    -- 自动定位,替代 MASTER_LOG_FILE + MASTER_LOG_POS

START SLAVE;
SHOW SLAVE STATUS\G

GTID 的优势: 切换主库时,只需 CHANGE MASTER TO MASTER_AUTO_POSITION=1,不用手动计算 binlog 偏移量。

3.3 验证复制

-- 在主库创建一个测试数据库
CREATE DATABASE test_repl;
USE test_repl;
CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO t1 VALUES (1, 'hello replication');

-- 在从库查询
USE test_repl;
SELECT * FROM t1;
-- +----+-------------------+
-- | id | name             |
-- +----+-------------------+
-- | 1 | hello replication |
-- +----+-------------------+

四、主主复制(MASTER-MASTER)

         ┌──────────┐              ┌──────────┐
        │ Master A │ ←────────→ │ Master B │
        │ .55.5   │ 双向同步     │ .55.9   │
        │ 读写     │             │ 读写     │
        └──────────┘             └──────────┘

概念: 两台服务器互为主从,任意一台的写入都会同步到另一台。适合高可用场景(配合 Keepalived/ProxySQL 等),但需要处理 自增 ID 冲突循环复制 问题。

4.1 配置步骤

两台服务器都需要同时作为主库和从库。

4.1.1 服务器 A(10.211.55.5)

[mysqld]
server-id = 1
log_bin = /var/lib/mysql/binlog
binlog_format = ROW
relay_log = /var/lib/mysql/relay

gtid_mode = ON
enforce_gtid_consistency = ON

# === 主主复制关键配置 ===
auto_increment_increment = 2       # 自增步长(服务器数量)
auto_increment_offset = 1         # 自增起始偏移(本机:1, 3, 5, 7...)

# 防止循环复制:本机的更新不再回写到本机
log_slave_updates = ON

4.1.2 服务器 B(10.211.55.9)

[mysqld]
server-id = 2
log_bin = /var/lib/mysql/binlog
binlog_format = ROW
relay_log = /var/lib/mysql/relay

gtid_mode = ON
enforce_gtid_consistency = ON

auto_increment_increment = 2
auto_increment_offset = 2

log_slave_updates = ON

4.1.3 创建复制账号(两台都要)

-- 在 10.211.55.5 上创建
CREATE USER 'repl'@'10.211.55.%' IDENTIFIED BY 'Repl@123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.211.55.%';

ALTER USER 'repl'@'10.211.55.%' IDENTIFIED WITH mysql_native_password BY 'Repl@123456';

-- 在 10.211.55.9 上同样创建(如果之前一主一从已创建则跳过)
CREATE USER 'repl'@'10.211.55.%' IDENTIFIED BY 'Repl@123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.211.55.%';

ALTER USER 'repl'@'10.211.55.%' IDENTIFIED WITH mysql_native_password BY 'Repl@123456';

4.1.4 建立双向复制

-- 在服务器 A (.55.5) 上执行:把 B 设为 A 的主库
CHANGE MASTER TO
  MASTER_HOST = '10.211.55.9',
  MASTER_USER = 'repl',
  MASTER_PASSWORD = 'Repl@123456',
  MASTER_AUTO_POSITION = 1;
START SLAVE;

-- 在服务器 B (.55.9) 上执行:把 A 设为 B 的主库
CHANGE MASTER TO
  MASTER_HOST = '10.211.55.5',
  MASTER_USER = 'repl',
  MASTER_PASSWORD = 'Repl@123456',
  MASTER_AUTO_POSITION = 1;
START SLAVE;

-- 两边都检查
SHOW SLAVE STATUS\G
# 10.211.55.9
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
              Slave_IO_State: Waiting for source to send event
                Master_Host: 10.211.55.9
                Master_User: repl
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: binlog.000002
        Read_Master_Log_Pos: 758
              Relay_Log_File: relay.000002
              Relay_Log_Pos: 708
      Relay_Master_Log_File: binlog.000002
            Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
            Replicate_Do_DB:
        Replicate_Ignore_DB:
          Replicate_Do_Table:
      Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                  Last_Errno: 0
                  Last_Error:
                Skip_Counter: 0
        Exec_Master_Log_Pos: 758
            Relay_Log_Space: 908
            Until_Condition: None
              Until_Log_File:
              Until_Log_Pos: 0
          Master_SSL_Allowed: No
          Master_SSL_CA_File:
          Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
              Master_SSL_Key:
      Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
              Last_IO_Errno: 0
              Last_IO_Error:
              Last_SQL_Errno: 0
              Last_SQL_Error:
Replicate_Ignore_Server_Ids:
            Master_Server_Id: 2
                Master_UUID: 23786b26-57da-11f1-9fcf-001c420f4775
            Master_Info_File: mysql.slave_master_info
                  SQL_Delay: 0
        SQL_Remaining_Delay: NULL
    Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
          Master_Retry_Count: 86400
                Master_Bind:
    Last_IO_Error_Timestamp:
    Last_SQL_Error_Timestamp:
              Master_SSL_Crl:
          Master_SSL_Crlpath:
          Retrieved_Gtid_Set: 23786b26-57da-11f1-9fcf-001c420f4775:1
          Executed_Gtid_Set: 01e7fb08-57da-11f1-ba69-001c429cec7c:1,
23786b26-57da-11f1-9fcf-001c420f4775:1
              Auto_Position: 1
        Replicate_Rewrite_DB:
                Channel_Name:
          Master_TLS_Version:
      Master_public_key_path:
      Get_master_public_key: 0
          Network_Namespace:
1 row in set, 1 warning (0.01 sec)
# 10.211.55.5
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
              Slave_IO_State: Waiting for source to send event
                Master_Host: 10.211.55.5
                Master_User: repl
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: binlog.000002
        Read_Master_Log_Pos: 758
              Relay_Log_File: relay.000002
              Relay_Log_Pos: 708
      Relay_Master_Log_File: binlog.000002
            Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
            Replicate_Do_DB:
        Replicate_Ignore_DB:
          Replicate_Do_Table:
      Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                  Last_Errno: 0
                  Last_Error:
                Skip_Counter: 0
        Exec_Master_Log_Pos: 758
            Relay_Log_Space: 908
            Until_Condition: None
              Until_Log_File:
              Until_Log_Pos: 0
          Master_SSL_Allowed: No
          Master_SSL_CA_File:
          Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
              Master_SSL_Key:
      Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
              Last_IO_Errno: 0
              Last_IO_Error:
              Last_SQL_Errno: 0
              Last_SQL_Error:
Replicate_Ignore_Server_Ids:
            Master_Server_Id: 1
                Master_UUID: 01e7fb08-57da-11f1-ba69-001c429cec7c
            Master_Info_File: mysql.slave_master_info
                  SQL_Delay: 0
        SQL_Remaining_Delay: NULL
    Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
          Master_Retry_Count: 86400
                Master_Bind:
    Last_IO_Error_Timestamp:
    Last_SQL_Error_Timestamp:
              Master_SSL_Crl:
          Master_SSL_Crlpath:
          Retrieved_Gtid_Set: 01e7fb08-57da-11f1-ba69-001c429cec7c:1
          Executed_Gtid_Set: 01e7fb08-57da-11f1-ba69-001c429cec7c:1,
23786b26-57da-11f1-9fcf-001c420f4775:1
              Auto_Position: 1
        Replicate_Rewrite_DB:
                Channel_Name:
          Master_TLS_Version:
      Master_public_key_path:
      Get_master_public_key: 0
          Network_Namespace:
1 row in set, 1 warning (0.00 sec)

 

4.2 auto_increment 冲突解决原理

服务器 offset 生成的自增 ID
A (.55.5) 1 1, 3, 5, 7, 9, 11…
B (.55.9) 2 2, 4, 6, 8, 10, 12…

两台同时插入数据时,自增 ID 永远不会冲突。

4.3 主主复制的黄金法则

  1. 始终使用 GTID —— 避免 binlog 位置混乱

  2. 不同表操作 —— 尽量让不同服务器操作不同表,减少冲突

  3. 避免同时更新同一行 —— 会导致复制中断

  4. 配合高可用中间件 —— ProxySQL、MySQL Router 等做读写分离和故障切换


五、常见问题与排查

5.1 复制中断

-- 查看错误信息
SHOW SLAVE STATUS\G
-- 关注这些字段:
-- Last_IO_Error: I/O 线程错误
-- Last_SQL_Error: SQL 线程错误

-- 常见中断原因及处理
-- 1. 主键冲突(最常见)
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;  -- 跳过当前出错的事务
START SLAVE;

-- 2. GTID 模式下跳过事务
STOP SLAVE;
SET GTID_NEXT = 'aaa-bbb-ccc:5';  -- 要跳过的事务 GTID
BEGIN; COMMIT;
SET GTID_NEXT = AUTOMATIC;
START SLAVE;

-- 3. 使用 pt-slave-restart(Percona Toolkit)
pt-slave-restart --user=root --error-numbers=1062

5.2 延迟过大

-- 查看延迟
SHOW SLAVE STATUS\G
-- Seconds_Behind_Master: N   ← 延迟 N 秒

-- 加速手段
-- 1. 开启并行复制
SET GLOBAL slave_parallel_workers = 8;
SET GLOBAL slave_parallel_type = LOGICAL_CLOCK;

-- 2. 临时跳过 binlog 写入(仅中间从库做级联时)
SET GLOBAL sync_binlog = 0;

-- 3. 检查是否有大事务或锁等待
SHOW PROCESSLIST;
SELECT * FROM information_schema.innodb_trx WHERE trx_state = 'RUNNING'\G

5.3 数据一致性检查

# 使用 Percona Toolkit 的 pt-table-checksum 检查主从数据是否一致
pt-table-checksum h=10.211.55.5,u=root --databases mydb

# 发现不一致时用 pt-table-sync 修复
pt-table-sync --sync-to-master h=10.211.55.9,u=root --databases mydb --print

5.4 常用监控命令

-- 查看所有从库状态
SHOW SLAVE STATUS\G

-- 查看复制过滤规则
SHOW SLAVE STATUS\G | grep -i replicate

-- 查看 binlog 事件
SHOW BINLOG EVENTS IN 'binlog.000001' LIMIT 10;

-- 查看 relay log 事件
SHOW RELAYLOG EVENTS IN 'relay.000001' LIMIT 10;

-- 查看当前所有连接
SHOW PROCESSLIST;

-- 查看复制线程状态
SELECT * FROM performance_schema.replication_applier_status_by_worker;

六、拓扑总结与选型建议

拓扑 复杂度 适用场景 关键配置
一主一从 备份、简单读写分离 server-id, log_bin
主主复制 ⭐⭐⭐ 高可用、双向同步 auto_increment_offset/increment, GTID

选型路线图

                    你的业务是?
                      │
        ┌────────────┼────────────┐
        ↓           ↓           ↓
    只有两台机器   3台以上       多个独立业务库
        │           │           │
        ↓           ↓           ↓
    需要高可用?   读瓶颈大?   需要数据汇聚?
        │
    ┌────┴────┐
    ↓         ↓
  Yes       No
    │         │
    ↓         ↓
主主复制   一主一从

广告:

© 版权声明
THE END
喜欢就支持一下吧
点赞6打赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容