更新时间:2023 年 5 月
简介
官方文档参考
MySQL 8.0:MySQL :: MySQL 8.0 Reference Manual :: 17.1 Configuring Replication
MySQL 5.7:MySQL :: MySQL 5.7 Reference Manual :: 16.1 Configuring Replication
主从复制使数据能够从一个 MySQL 数据库服务器(源数据库,称为 source
,旧称 master
)复制到一个或多个 MySQL 数据库服务器(副本数据库,称为 replicas
,旧称 slave
)。默认情况下,复制是异步的,复制副本不需要永久连接即可从源接收更新。根据配置,可以复制数据库中的所有数据库、选定的部分数据库,甚至选定的表
复制的作用
- 横向扩展:在多个
replicas
(副本)之间分散负载以提高性能;所有的数据写入和更新在source
上进行,数据读取则在replicas
上进行。可以提高写入性能(因为source
专用于更新),同时可以增加的replicas
数量以显著提高读取速度 - 数据安全:由于
replicas
可以暂停复制过程,因此可以在不损坏相应source
数据的情况下在replicas
运行备份服务 - 数据分析:可以在
source
上创建实时数据,而对信息的分析可以在replicas
上进行,而不会影响source
的性能 - 远程数据分发:以使用复制创建数据的本地副本供远程站点使用,而无需直接访问源
- 延迟复制:复制的
replicas
故意落后于source
至少指定的时间,可以作为数据备份
更多相关解决方案可以参考:Replication Solutions
复制的限制
当前复制是基于 binlog
进行,如果 source
已经运行一段时间,binlog
已经有部分删除(超过生存周期删除或其他原因),此时需要增加 replicas
,必须先备份 source
上的数据在 replicas
上恢复。若直接配置主从,会导致主从数据不一致
复制原理

复制步骤
- 主节点(
source
) 开启二进制日志(binary log
,或叫binlog
),并将数据库的改变记录到二进制日志中 (这些记录叫做二进制日志事件,binary log events
) - 从节点(
replicas
) 开启一个 I/O 线程(I/O thread
),请求主节点的二进制日志文件中的事件 source
启动一个 dump 线程(Dump thread
),检查自己binlog
中的事件,跟对方请求的位置进行对比,并将事件发送给replicas
的 I/O 线程replicas
的 I/O 线程将source
的二进制日志事件解析到它的中继日志(relay log
)。若使用半同步复制,保存到磁盘后,会向source
返回确认信息replicas
的 SQL 线程将中继日志事件还原并生成数据
复制中各个线程的作用
从节点:
I/O Thread
:从source
节点请求binlog
事件,并保存于中继日志中SQL Thread
:从relay log
中读取日志事件并在本地完成重放
主节点:
Dump Thread
:每个replicas
的I/O Thread
都会启动一个Dump thread
,用于向从节点发送binlog
事件
同步类型
-
异步复制(asynchronous replication)
默认使用的同步类型。从 MySQL 诞生之初,就产生了这种架构,性能极好。 但是有丢失数据库的风险
-
完全同步复制(synchronous replication)
保证数据安全,不丢数据,损失性能;目前只有 MySQL NDB Cluster 支持,一般用不到
-
半同步复制(Semisynchronous Replication)
通常情况下应该选用半同步复制。由半同步复制插件
rpl_semi_sync_*
提供功能对于半同步复制,
source
上的事务在提交到存储引擎时需要等待,直到它至少收到一台replicas
返回的确认信息(确认已接收并写入)。因此,半同步复制可以保证source
发生故障事,提交的所有事务已经传到至少一台replicas
注:在 MySQL 5.5 就开始支持半同步复制,后续 MySQL 5.7 优化了接收确认消息时间点、MySQL 8.0 优化并行复制策略等
binlog
格式
参考-1:Replication Formats
二进制日志(binlog
)记录格式在配置文件中由 binlog_format
指定,例:binlog_format = ROW
;目前支持三种格式
-
STATEMENT
:基于 SQL 语句的复制(statement-based replication, SBR)每一条会修改数据的 SQL 语句会记录到
binlog
中**优点:**并不需要记录每一条 SQL 语句和每一行的数据变化,减少了
binlog
日志量,减少 IO,提高性能**缺点:**在某些情况下会导致主从数据不一致
-
ROW
:基于行的复制(row-based replication, RBR),推荐使用日志中会记录成每一行数据被修改的形式
**优点:**不会出现某些特定情况下的存储过程、function 或 trigger 的调用和触发无法被正确复制的问题
**缺点:**可能会产生大量的
binlog
日志 -
MIXED
:混合模式复制(mixed-based replication, MBR),推荐使用以上两种模式的混合使用,一般的复制使用
STATEMENT
模式保存binlog
,对于STATEMENT
模式无法复制的操作使用ROW
模式保存 binlog
MySQL 5.7.7 之前版本,默认使用
STATEMENT
格式, 在 MySQL 5.7.7 以及之后版本,默认使用ROW
格式
复制方法
MySQL 支持两种不同的复制方法
- 传统方式:要求在
source
和replicas
之间同步二进制日志文件(binlog file
)及其位置(position
)。详情参考:Configuring Replication - 基于全局事务标识(GTID):不需要处理二进制日志文件或这些文件中的位置。详情参考:Replication with Global Transaction Identifiers
GTID
GTID 简介
GTID (Global Transaction Identifiers),是对于一个已提交事务的全局编号,也是事务的唯一编号。GTID 和事务会记录到 binlog
中,用来标识事务。 GTID 是用来替代以前传统复制方法(binlog
+ position
),可以避免同一个事务在同一个节点中出现多次的情况。MySQL 5.6.2 开始支持 GTID
GTID 的优势
- 根据 GTID 可以快速的确定事务最初是在哪个实例上提交的
- 简单的实现 failover,不用以前那样在需要找事务位于哪个
binlog
和position
- 更简单的搭建主从复制,确保每个事务只会被执行一次
- 比传统的复制更加安全。GTID 的引入使运维更省事
GTID 使用注意事项
- 因为基于 GTID 的复制依赖于事务,所以在使用 GTID 时,有些 MySQL 特性是不支持的
- 主从库的表存储引擎必须一致
- 不支持非事务引擎(从库报错)
- 不支持
create table … select
语句复制(主库直接报错) - 不允许在一个 SQL 同时更新一个事务引擎和非事务引擎的表
- 在一个复制组中,必须要求统一开启 GTID 或是关闭 GTID
- 开启 GTID 后,就不能再使用原来的传统的复制方式
- 对于
create temporary table
和drop temporary table
语句不支持 - 不支持
sql_slave_skip_counter
(sql_replica_skip_counter
) - 不推荐在 GTID 模式的实例上进行
mysql_upgrade
,因为 mysql_upgrade 的过程要创建或修改系统表(非事务引擎),所以不建议在开启 GTID 的模式的实例上使用带 有--write-binlog
选项的 mysql_upgrade
传统方式配置主从
准备
拓扑

主机列表
主机名 | IP | 安装服务 | 角色 | server_id |
---|---|---|---|---|
db-mysql-1 | 192.168.111.191 | mysql 8.0.32 | source(主) | 191 |
db-mysql-2 | 192.168.111.192 | mysql 8.0.32 | replicas(从) | 192 |
db-mysql-3 | 192.168.111.193 | mysql 8.0.32 | replicas(从) | 193 |
此处省略 MySQL 安装过程,可以参考:01-Alma 9 上安装 MySQL 8 - Nemo 的小站 (skynemo.cn)
各主机均完成以下配置
-
配置时间同步
-
关闭防火墙
-
配置国内的 YUM 源(APT 源)
-
修改主机名称(证书绑定了主机名的时候必须配置)
配置
配置流程
主节点(source
)
- 启用二进制日志
- 为当前节点设置一个全局唯一的
server_id
- 创建有复制权限(
REPLIACTION SLAVE
)的用户账号 - 记录开始复制的二进制日志的位置
从节点(replica
)
- 启用中继日志
- 为当前节点设置一个全局唯一的
server_id
- 使用有复制权限的用户账号连接至主节点,设置二进制日志开始复制的位置,并启动复制线程
主节点配置
准备 binlog
目录
$ BINLOG_PATH="/var/lib/mysql/binlog"
$ mkdir -p ${BINLOG_PATH}
$ chown -R mysql:mysql ${BINLOG_PATH}
修改主节点参数配置
备份原有的配置
$ mv /etc/my.cnf /etc/my.cnf-`date +"%F--%H-%M"`
配置
$ vim /etc/my.cnf
[mysqld]
########## 基础配置 #########
# 为当前节点设置一个全局唯一的 ID
server_id=191
# 绑定 IP
bind_address = 192.168.111.191
# 跳过域名解析
skip_name_resolve = ON
# 设置事务级别
transaction_isolation = READ-COMMITTED
# 设置数据目录
datadir=/var/lib/mysql
# 设置 socket 目录
socket=/var/lib/mysql/mysql.sock
# 设置错误日志
log_error=/var/log/mysqld.log
# 设置 PID 存储路径
pid_file=/var/run/mysqld/mysqld.pid
# 设置 SQL 模式,去掉了 MySQL 8 默认的 ONLY_FULL_GROUP_BY
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
########## binlog 相关配置 #########
# 启用 binlog
log_bin = ON
# 配置 binlog 路径和名称
log_bin = /var/lib/mysql/binlog/mysql-binlog
log_bin_index = /var/lib/mysql/binlog/mysql-binlog.index
# binlog 格式
binlog_format = ROW
# 忽略哪些库的数据同步,根据生产环境实际情况设置
# binlog-ignore-db = mysql
# binlog-ignore-db = sys
# 设置 binlog 过期时间
binlog_expire_logs_seconds = 2592000
# 设置 binlog 过期自动删除
binlog_expire_logs_auto_purge = ON
# binlog 文件的大小限制,此处设置最大值 1 G,超出时轮换。可以适当调整
max_binlog_size = 1073741824
# 关闭 binlog 顺序,提升一点性能
binlog_order_commits = OFF
# 设置 binlog 同步到磁盘前延迟时间
binlog_group_commit_sync_delay = 500
# 在 binlog 同步到磁盘前延迟时间内,如果有 5 个事务,则立即提交
binlog_group_commit_sync_no_delay_count = 5
# 使用写集来区分可以并行的事务
binlog_transaction_dependency_tracking = WRITESET
# binlog 单个事件大小软限制
binlog_row_event_max_size = 8192
# 仅记录要修改的列,减小 binlog 文件大小
binlog_row_image = minimal
# 配置压缩 binlog
binlog_transaction_compression = ON
# 配置压缩级别
binlog_transaction_compression_level_zstd = 3
# 配置缓存,单位 byte,根据生产环境实际情况适当调整
binlog_cache_size = 1048576
binlog_stmt_cache_size = 1048576
max_binlog_cache_size = 4294967295
max_binlog_stmt_cache_size = 4294967295
# 控制从 binlog 和 relay log 读取数据的最小值,IO 频繁时可以适当增加该值
rpl_read_size = 8192
# binlog 刷盘频率,每个事务均同步磁盘
sync_binlog = 1
########## innodb redo-log 相关配置 #########
# 事务提交时将事务日志立即写入磁盘
innodb_flush_log_at_trx_commit = 1
########## source 半同步复制相关配置 #########
#------ 安装半同步模块插件 ---------
plugin_dir = "/usr/lib64/mysql/plugin/"
plugin_load = "rpl_semi_sync_source=semisync_source.so"
#------ 配置半同步相关参数 ---------
# 开启半同步复制
loose-rpl_semi_sync_source_enabled = ON
# 超时时间设置,单位毫秒
loose-rpl_semi_sync_source_timeout = 10000
# 设置等待 replicas 确认的时间点,AFTER_SYNC 可以保证 RPO=0
loose-rpl_semi_sync_source_wait_point = AFTER_SYNC
# 等待多少个 replicas 的回复后才向客户端返回,根据生产环境实际情况设置
loose-rpl_semi_sync_source_wait_for_replica_count = 2
# 在 timeout 时间内,即使 replicas 数量小于需要回复的客户端数量,依旧保存半同步复制
loose-rpl_semi_sync_source_wait_no_replica = ON
重启服务,使配置生效
$ systemctl restart mysqld
查看二进制日志位置
$ mysql -uroot -p
Enter password:
# 查看当前 binlog 日志
mysql> SHOW MASTER STATUS;
+---------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------------+----------+--------------+------------------+-------------------+
| mysql-binlog.000001 | 891 | | | |
+---------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
创建复制用户
# 创建用户
mysql> CREATE USER repluser@'192.168.111.%' identified by 'Replpass123..';
Query OK, 0 rows affected (0.02 sec)
# 授权
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'192.168.111.%';
Query OK, 0 rows affected (0.01 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
从节点配置
注:两台从节点的配置,除了
bind_address
和server_id
外,其余配置均相同
准备 binlog
目录
注:
replicas
可以不设置binlog
,但如果需要级联复制,则必须配置
$ BINLOG_PATH="/var/lib/mysql/binlog"
$ mkdir -p ${BINLOG_PATH}
$ chown -R mysql:mysql ${BINLOG_PATH}
准备 relay log 日志目录
# 准备从机的 relaylog 目录
$ RELAYLOG_PATH="/var/lib/mysql/relay-log"
$ mkdir -p ${RELAYLOG_PATH}
$ chown -R mysql:mysql ${RELAYLOG_PATH}
修改从库配置
备份原有的配置
$ mv /etc/my.cnf /etc/my.cnf-`date +"%F--%H-%M"`
配置
$ vim /etc/my.cnf
[mysqld]
########## 基础配置 #########
# 为当前节点设置一个全局唯一的 ID
server_id=192
# 绑定 IP
bind_address = 192.168.111.192
# 跳过域名解析
skip_name_resolve = ON
# 设置事务级别
transaction_isolation = READ-COMMITTED
# 设置数据目录
datadir=/var/lib/mysql
# 设置 socket 目录
socket=/var/lib/mysql/mysql.sock
# 设置错误日志
log_error=/var/log/mysqld.log
# 设置 PID 存储路径
pid_file=/var/run/mysqld/mysqld.pid
# 设置 SQL 模式,去掉了 MySQL 8 默认的 ONLY_FULL_GROUP_BY
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
# 设置只读,防止数据不一致
read_only=ON
########## binlog 相关配置 #########
# 启用 binlog
log_bin = ON
# 配置 binlog 路径和名称
log_bin = /var/lib/mysql/binlog/mysql-binlog
# 配置 binlog 索引路径和名称
log_bin_index = /var/lib/mysql/binlog/mysql-binlog.index
# binlog 格式
binlog_format = ROW
# 忽略哪些库的数据同步,根据生产环境实际情况设置
# binlog-ignore-db = mysql
# binlog-ignore-db = sys
# 设置 binlog 过期时间
binlog_expire_logs_seconds = 2592000
# 设置 binlog 过期自动删除
binlog_expire_logs_auto_purge = ON
# binlog 文件的大小限制,此处设置最大值 1 G,超出时轮换。可以适当调整
max_binlog_size = 1073741824
# 关闭 binlog 顺序,提升一点性能
binlog_order_commits = OFF
# 设置 binlog 同步到磁盘前延迟时间
binlog_group_commit_sync_delay = 500
# 在 binlog 同步到磁盘前延迟时间内,如果有 5 个事务,则立即提交
binlog_group_commit_sync_no_delay_count = 5
# 使用写集来区分可以并行的事务
binlog_transaction_dependency_tracking = WRITESET
# binlog 单个事件大小软限制
binlog_row_event_max_size = 8192
# 仅记录要修改的列,减小 binlog 文件大小
binlog_row_image = minimal
# 配置压缩 binlog
binlog_transaction_compression = ON
# 配置压缩级别
binlog_transaction_compression_level_zstd = 3
# 配置缓存,单位 byte,根据生产环境实际情况适当调整
binlog_cache_size = 1048576
binlog_stmt_cache_size = 1048576
max_binlog_cache_size = 4294967295
max_binlog_stmt_cache_size = 4294967295
# 控制从 binlog 和 relay log 读取数据的最小值,IO 频繁时可以适当增加该值
rpl_read_size = 8192
# binlog 刷盘频率,每个事务均同步磁盘
sync_binlog = 1
########## innodb redo-log 相关配置 #########
# 事务提交时将事务日志立即写入磁盘
innodb_flush_log_at_trx_commit = 1
########## relay log 相关配置 #########
# 设置 relay log 完整路径和基础名称
relay_log = /var/lib/mysql/relay-log/mysql-relay-bin
# 配置 relay log 过期自动删除 索引路径和名称
relay_log_index = /var/lib/mysql/relay-log/mysql-relay-bin.index
# 配置 SQL 线程执行状态信息存储方式
relay_log_info_repository = TABLE
# 配置自动删除无用的 relay log
relay_log_purge = ON
# 设置所有 relaylog 的最大空间使用量
relay_log_space_limit = 4294967295
# relaylog 文件的大小限制,此处设置最大值 1 G,超出时轮换。可以适当调整
max_relay_log_size = 1073741824
# 设置在服务启动时自动进行中继日志恢复
relay_log_recovery = ON
# 设置每个 relay log 事件都触发同步到磁盘
sync_relay_log = 1
########## replicas 半同步复制相关配置 #########
#------ 安装半同步模块插件 ---------
plugin_dir = "/usr/lib64/mysql/plugin/"
plugin_load = "rpl_semi_sync_replica=semisync_replica.so"
#------ 配置半同步相关参数 ---------
# 启用插件
loose-rpl_semi_sync_replica_enabled = 1
# 指定事务在 replcias 上的并行执行策略
replica_parallel_type = LOGICAL_CLOCK
# 启用多线程,并设置用于并行执行复制事务的 SQL 线程数
replica_parallel_workers = 4
# 确保多线程事务提交顺序
replica_preserve_commit_order = ON
# 设置失败事务的最大重试次数
replica_transaction_retries = 10
# 设置 IO 线程执行状态信息的存储方式
master_info_repository = TABLE
# 开启主从之间连接数据的压缩
replica_compressed_protocol = ON
# 设置 SQL 线程在加载数据时临时数据存储目录
replica_load_tmpdir = "/tmp"
# 设置 replicas 的 SQL 线程和 I/O 线程可以处理的最大数据包大小
replica_max_allowed_packet = 1073741824
# 设置 replicas 认为连接断开的超时时间。以秒为单位
replica_net_timeout = 30
# 使用共享锁,提高半同步复制性能
replication_optimize_for_static_plugin_config = ON
# 限制回调,提高半同步复制性能
replication_sender_observe_commit_only = ON
重启服务,使配置生效
$ systemctl restart mysqld
配置 source
的公钥
MySQL 8.0 版本默认开启了加密连接(插件
caching_sha2_password
),所以需要在replcas
配置source
的公钥
在 replcas
上使用复制用户连接 source
,需要请求公钥或者指定公钥,初次连接完成后,后续连接(包括复制线程)都会使用该公钥(老版本缓存在文件,新版本缓存在 source
的内存中)
-
方式一:
--get-server-public-key
注:此选项适用于使用
caching_sha2_password
身份验证插件进行身份验证的客户端带上
--get-server-public-key
选项请求公钥,公钥会自动保存在这种情况下,服务器将 RSA 公钥发送给客户端,客户端使用它来加密密码并将结果返回给服务器。插件使用服务器端的 RSA 私钥解密密码,并根据密码是否正确来接受或拒绝连接
$ mysql -u'repluser' -p'Replpass123..' -h 192.168.111.191 -P3306 --get-server-public-key
-
方式二:
--server-public-key-path
复制
source
的公钥$ scp 192.168.111.191:/var/lib/mysql/public_key.pem /var/lib/mysql/source_public_key.pem
指定
source
公钥$ mysql -u'repluser' -p'replpass' -h 192.168.111.196 -P3306 --server-public-key-path /var/lib/mysql/source_public_key.pem
-
(推荐)方式三:在命令行指定
在
CHANGE REPLICATION SOURCE TO
语句中使用GET_SOURCE_PUBLIC_KEY = {0|1}
或指定配置source
的证书示例
mysql> CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.111.191', SOURCE_USER='repluser', SOURCE_PASSWORD='Replpass123..', SOURCE_PORT=3306, SOURCE_LOG_FILE='mysql-binlog.000001', SOURCE_LOG_POS=891, GET_SOURCE_PUBLIC_KEY=1;
**连接至 source
**
使用有复制权限的用户账号连接至主服务器,并启动复制线程
$ mysql -uroot -p
Enter password:
# 清除配置
mysql> STOP REPLICA;
mysql> RESET MASTER;
mysql> RESET REPLICA;
# 连接至 source ,设置二进制日志开始复制的位置
mysql> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.111.191',
SOURCE_USER='repluser',
SOURCE_PASSWORD='Replpass123..',
SOURCE_PORT=3306,
SOURCE_LOG_FILE='mysql-binlog.000001',
SOURCE_LOG_POS=891,
GET_SOURCE_PUBLIC_KEY=1;
# 启动 REPLICA
mysql> START REPLICA;
# 查看状态
mysql> SHOW SLAVE STATUS\G;
# IO 线程与 SQL 线程均运行,则配置成功
......
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
......
检查
查看主节点状态
mysql> SHOW MASTER STATUS;
从节点查看复制状态
mysql> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.1.196
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-binlog.000001
Read_Master_Log_Pos: 883
Relay_Log_File: mysql-relay.000002
Relay_Log_Pos: 1054
......
测试
主库操作数据
$ mysql -uroot -p
Enter password:
mysql> CREATE DATABASE testdb DEFAULT CHARSET utf8mb4;
mysql> CREATE USER 'testuser'@'%' IDENTIFIED BY 'Qwert123--';
mysql> GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'%';
mysql> FLUSH PRIVILEGES;
mysql> USE testdb;
mysql> CREATE TABLE t_user01(
id int auto_increment primary key,
name varchar(40)
) ENGINE = InnoDB;
BEGIN;
INSERT INTO t_user01 VALUES (1,'user01');
INSERT INTO t_user01 VALUES (2,'user02');
INSERT INTO t_user01 VALUES (3,'user03');
INSERT INTO t_user01 VALUES (4,'user04');
INSERT INTO t_user01 VALUES (5,'user05');
COMMIT;
备库查询
$ mysql -utestuser -p
Enter password:
# 查看数据库,可以看到 testdb 同步过来了
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| testdb |
+--------------------+
2 rows in set (0.01 sec)
# 数据也同步过来了
mysql> select * from testdb.t_user01;
+----+--------+
| id | name |
+----+--------+
| 1 | user01 |
| 2 | user02 |
| 3 | user03 |
| 4 | user04 |
| 5 | user05 |
+----+--------+
5 rows in set (0.00 sec)
GTID 配置主从(推荐)
参考:
准备
拓扑

主机列表
主机名 | IP | 安装服务 | 角色 | server_id |
---|---|---|---|---|
db-mysql-1 | 192.168.111.191 | mysql 8.0.32 | source(主) | 191 |
db-mysql-2 | 192.168.111.192 | mysql 8.0.32 | replicas(从) | 192 |
db-mysql-3 | 192.168.111.193 | mysql 8.0.32 | replicas(从) | 193 |
此处省略 MySQL 安装过程,可以参考:01-Alma 9 上安装 MySQL 8 - Nemo 的小站 (skynemo.cn)
各主机均完成下面配置
-
配置时间同步
-
关闭防火墙
-
配置国内的 YUM 源(APT 源)
-
修改主机名称(证书绑定了主机名的时候必须配置)
配置
配置流程
主节点(source
)
- 启用二进制日志
- 为当前节点设置一个全局唯一的
server_id
- 创建有复制权限(
REPLIACTION SLAVE
,REPLIATION CLIENT
)的用户账号
从节点(replica
)
- 启动中继日志
- 为当前节点设置一个全局唯一的
server_id
- 使用有复制权限的用户账号连接至主节点,并启动复制线程
主节点配置
准备 binlog
目录
$ BINLOG_PATH="/var/lib/mysql/binlog"
$ mkdir -p ${BINLOG_PATH}
$ chown -R mysql:mysql ${BINLOG_PATH}
修改主节点参数配置
备份原有的配置
$ mv /etc/my.cnf /etc/my.cnf-`date +"%F--%H-%M"`
配置
$ vim /etc/my.cnf
[mysqld]
########## 基础配置 #########
# 为当前节点设置一个全局唯一的 ID
server_id=191
# 绑定 IP
bind_address = 192.168.111.191
# 跳过域名解析
skip_name_resolve = ON
# 设置事务级别
transaction_isolation = READ-COMMITTED
# 设置数据目录
datadir=/var/lib/mysql
# 设置 socket 目录
socket=/var/lib/mysql/mysql.sock
# 设置错误日志
log_error=/var/log/mysqld.log
# 设置 PID 存储路径
pid_file=/var/run/mysqld/mysqld.pid
# 设置 SQL 模式,去掉了 MySQL 8 默认的 ONLY_FULL_GROUP_BY
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
########## binlog 相关配置 #########
# 启用 binlog
log_bin = ON
# 配置 binlog 路径和名称
log_bin = /var/lib/mysql/binlog/mysql-binlog
log_bin_index = /var/lib/mysql/binlog/mysql-binlog.index
# binlog 格式
binlog_format = ROW
# 忽略哪些库的数据同步,根据生产环境实际情况设置
# binlog-ignore-db = mysql
# binlog-ignore-db = sys
# 设置 binlog 过期时间
binlog_expire_logs_seconds = 2592000
# 设置 binlog 过期自动删除
binlog_expire_logs_auto_purge = ON
# binlog 文件的大小限制,此处设置最大值 1 G,超出时轮换。可以适当调整
max_binlog_size = 1073741824
# 关闭 binlog 顺序,提升一点性能
binlog_order_commits = OFF
# 设置 binlog 同步到磁盘前延迟时间
binlog_group_commit_sync_delay = 500
# 在 binlog 同步到磁盘前延迟时间内,如果有 5 个事务,则立即提交
binlog_group_commit_sync_no_delay_count = 5
# 使用写集来区分可以并行的事务
binlog_transaction_dependency_tracking = WRITESET
# binlog 单个事件大小软限制
binlog_row_event_max_size = 8192
# 仅记录要修改的列,减小 binlog 文件大小
binlog_row_image = minimal
# 配置压缩 binlog
binlog_transaction_compression = ON
# 配置压缩级别
binlog_transaction_compression_level_zstd = 3
# 配置缓存,单位 byte,根据生产环境实际情况适当调整
binlog_cache_size = 1048576
binlog_stmt_cache_size = 1048576
max_binlog_cache_size = 4294967295
max_binlog_stmt_cache_size = 4294967295
# 控制从 binlog 和 relay log 读取数据的最小值,IO 频繁时可以适当增加该值
rpl_read_size = 8192
# binlog 刷盘频率,每个事务均同步磁盘
sync_binlog = 1
########## innodb redo-log 相关配置 #########
# 事务提交时将事务日志立即写入磁盘
innodb_flush_log_at_trx_commit = 1
########## GTID 相关配置 #########
# 启用 GTID 事务
gtid_mode = ON
# 设置重启时快速恢复 binlog
binlog_gtid_simple_recovery = ON
# 强制 GTID 一致性
enforce_gtid_consistency = ON
########## source 半同步复制相关配置 #########
#------ 安装半同步模块插件 ---------
plugin_dir = "/usr/lib64/mysql/plugin/"
plugin_load = "rpl_semi_sync_source=semisync_source.so"
#------ 配置半同步相关参数 ---------
# 开启半同步复制
loose-rpl_semi_sync_source_enabled = ON
# 超时时间设置,单位毫秒
loose-rpl_semi_sync_source_timeout = 10000
# 设置等待 replicas 确认的时间点,AFTER_SYNC 可以保证 RPO=0
loose-rpl_semi_sync_source_wait_point = AFTER_SYNC
# 等待多少个 replicas 的回复后才向客户端返回,根据生产环境实际情况设置
loose-rpl_semi_sync_source_wait_for_replica_count = 2
# 在 timeout 时间内,即使 replicas 数量小于需要回复的客户端数量,依旧保存半同步复制
loose-rpl_semi_sync_source_wait_no_replica = ON
重启 mysql 使配置生效
$ systemctl restart mysqld
创建复制用户并授权
$ mysql -uroot -p
Enter password:
# 创建用户
mysql> CREATE USER repluser@'192.168.111.%' identified by 'Replpass123..';
Query OK, 0 rows affected (0.02 sec)
# 授权
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'192.168.111.%';
Query OK, 0 rows affected (0.01 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
从节点配置
注:两台从节点的配置,除了
bind_address
和server_id
外,其余配置均相同
准备 binlog
目录
注:
replicas
可以不设置binlog
,但如果需要级联复制,则必须配置
$ BINLOG_PATH="/var/lib/mysql/binlog"
$ mkdir -p ${BINLOG_PATH}
$ chown -R mysql:mysql ${BINLOG_PATH}
准备 relay log 日志目录
# 准备从机的 relaylog 目录
$ RELAYLOG_PATH="/var/lib/mysql/relay-log"
$ mkdir -p ${RELAYLOG_PATH}
$ chown -R mysql:mysql ${RELAYLOG_PATH}
修改从库配置
备份原有的配置
$ mv /etc/my.cnf /etc/my.cnf-`date +"%F--%H-%M"`
配置
$ vim /etc/my.cnf
[mysqld]
########## 基础配置 #########
# 为当前节点设置一个全局唯一的 ID
server_id=192
# 绑定 IP
bind_address = 192.168.111.192
# 跳过域名解析
skip_name_resolve = ON
# 设置事务级别
transaction_isolation = READ-COMMITTED
# 设置数据目录
datadir=/var/lib/mysql
# 设置 socket 目录
socket=/var/lib/mysql/mysql.sock
# 设置错误日志
log_error=/var/log/mysqld.log
# 设置 PID 存储路径
pid_file=/var/run/mysqld/mysqld.pid
# 设置 SQL 模式,去掉了 MySQL 8 默认的 ONLY_FULL_GROUP_BY
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
# 设置只读,防止数据不一致
read_only=ON
########## binlog 相关配置 #########
# 启用 binlog
log_bin = ON
# 配置 binlog 路径和名称
log_bin = /var/lib/mysql/binlog/mysql-binlog
# 配置 binlog 索引路径和名称
log_bin_index = /var/lib/mysql/binlog/mysql-binlog.index
# binlog 格式
binlog_format = ROW
# 忽略哪些库的数据同步,根据生产环境实际情况设置
# binlog-ignore-db = mysql
# binlog-ignore-db = sys
# 设置 binlog 过期时间
binlog_expire_logs_seconds = 2592000
# 设置 binlog 过期自动删除
binlog_expire_logs_auto_purge = ON
# binlog 文件的大小限制,此处设置最大值 1 G,超出时轮换。可以适当调整
max_binlog_size = 1073741824
# 关闭 binlog 顺序,提升一点性能
binlog_order_commits = OFF
# 设置 binlog 同步到磁盘前延迟时间
binlog_group_commit_sync_delay = 500
# 在 binlog 同步到磁盘前延迟时间内,如果有 5 个事务,则立即提交
binlog_group_commit_sync_no_delay_count = 5
# 使用写集来区分可以并行的事务
binlog_transaction_dependency_tracking = WRITESET
# binlog 单个事件大小软限制
binlog_row_event_max_size = 8192
# 仅记录要修改的列,减小 binlog 文件大小
binlog_row_image = minimal
# 配置压缩 binlog
binlog_transaction_compression = ON
# 配置压缩级别
binlog_transaction_compression_level_zstd = 3
# 配置缓存,单位 byte,根据生产环境实际情况适当调整
binlog_cache_size = 1048576
binlog_stmt_cache_size = 1048576
max_binlog_cache_size = 4294967295
max_binlog_stmt_cache_size = 4294967295
# 控制从 binlog 和 relay log 读取数据的最小值,IO 频繁时可以适当增加该值
rpl_read_size = 8192
# binlog 刷盘频率,每个事务均同步磁盘
sync_binlog = 1
########## innodb redo-log 相关配置 #########
# 事务提交时将事务日志立即写入磁盘
innodb_flush_log_at_trx_commit = 1
########## GTID 相关配置 #########
# 启用 GTID 事务
gtid_mode = ON
# 设置重启时快速恢复 binlog
binlog_gtid_simple_recovery = ON
# 强制 GTID 一致性
enforce_gtid_consistency = ON
########## relay log 相关配置 #########
# 设置 relay log 完整路径和基础名称
relay_log = /var/lib/mysql/relay-log/mysql-relay-bin
# 配置 relay log 过期自动删除 索引路径和名称
relay_log_index = /var/lib/mysql/relay-log/mysql-relay-bin.index
# 配置 SQL 线程执行状态信息存储方式
relay_log_info_repository = TABLE
# 配置自动删除无用的 relay log
relay_log_purge = ON
# 设置所有 relaylog 的最大空间使用量
relay_log_space_limit = 4294967295
# relaylog 文件的大小限制,此处设置最大值 1 G,超出时轮换。可以适当调整
max_relay_log_size = 1073741824
# 设置在服务启动时自动进行中继日志恢复
relay_log_recovery = ON
# 设置每个 relay log 事件都触发同步到磁盘
sync_relay_log = 1
########## replicas 半同步复制相关配置 #########
#------ 安装半同步模块插件 ---------
plugin_dir = "/usr/lib64/mysql/plugin/"
plugin_load = "rpl_semi_sync_replica=semisync_replica.so"
#------ 配置半同步相关参数 ---------
# 启用插件
loose-rpl_semi_sync_replica_enabled = 1
# 指定事务在 replcias 上的并行执行策略
replica_parallel_type = LOGICAL_CLOCK
# 启用多线程,并设置用于并行执行复制事务的 SQL 线程数
replica_parallel_workers = 4
# 确保多线程事务提交顺序
replica_preserve_commit_order = ON
# 设置失败事务的最大重试次数
replica_transaction_retries = 10
# 设置 IO 线程执行状态信息的存储方式
master_info_repository = TABLE
# 开启主从之间连接数据的压缩
replica_compressed_protocol = ON
# 设置 SQL 线程在加载数据时临时数据存储目录
replica_load_tmpdir = "/tmp"
# 设置 replicas 的 SQL 线程和 I/O 线程可以处理的最大数据包大小
replica_max_allowed_packet = 1073741824
# 设置 replicas 认为连接断开的超时时间。以秒为单位
replica_net_timeout = 30
# 使用共享锁,提高半同步复制性能
replication_optimize_for_static_plugin_config = ON
# 限制回调,提高半同步复制性能
replication_sender_observe_commit_only = ON
重启服务,使配置生效
$ systemctl restart mysqld
配置 source
的公钥
MySQL 8.0 版本默认开启了加密连接(插件
caching_sha2_password
),所以需要在replcas
配置source
的公钥
在 replcas
上使用复制用户连接 source
,需要请求公钥或者指定公钥,初次连接完成后,后续连接(包括复制线程)都会使用该公钥(老版本缓存在文件,新版本缓存在 source
的内存中)
-
方式一:
--get-server-public-key
注:此选项适用于使用
caching_sha2_password
身份验证插件进行身份验证的客户端带上
--get-server-public-key
选项请求公钥,公钥会自动保存在这种情况下,服务器将 RSA 公钥发送给客户端,客户端使用它来加密密码并将结果返回给服务器。插件使用服务器端的 RSA 私钥解密密码,并根据密码是否正确来接受或拒绝连接
$ mysql -u'repluser' -p'Replpass123..' -h 192.168.111.191 -P3306 --get-server-public-key
-
方式二:
--server-public-key-path
复制
source
的公钥$ scp 192.168.111.191:/var/lib/mysql/public_key.pem /var/lib/mysql/source_public_key.pem
指定
source
公钥$ mysql -u'repluser' -p'replpass' -h 192.168.111.196 -P3306 --server-public-key-path /var/lib/mysql/source_public_key.pem
-
(推荐)方式三:在命令行指定
在
CHANGE REPLICATION SOURCE TO
语句中使用GET_SOURCE_PUBLIC_KEY = {0|1}
或指定配置source
的证书示例
mysql> CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.111.191', SOURCE_USER='repluser', SOURCE_PASSWORD='Replpass123..', SOURCE_PORT=3306, SOURCE_AUTO_POSITION=1, GET_SOURCE_PUBLIC_KEY=1;
**连接至 source
**
使用有复制权限的用户账号连接至主服务器,并启动复制线程
$ mysql -uroot -p
Enter password:
# 清除配置
mysql> STOP REPLICA;
mysql> RESET MASTER;
mysql> RESET REPLICA;
# 连接至 source ,设置二进制日志开始复制的位置
mysql> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.111.191',
SOURCE_USER='repluser',
SOURCE_PASSWORD='Replpass123..',
SOURCE_PORT=3306,
SOURCE_AUTO_POSITION=1,
GET_SOURCE_PUBLIC_KEY=1;
# 启动 REPLICA
mysql> START REPLICA;
# 查看状态
mysql> SHOW SLAVE STATUS\G;
# IO 线程与 SQL 线程均运行,则配置成功
......
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
......
检查
主节点检查
检查主节点状态
mysql> SHOW MASTER STATUS\G;
*************************** 1. row ***************************
File: mysql-binlog.000002
Position: 890
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: a3f97197-fb97-11ed-9f34-000c29808bde:1-3
1 row in set (0.00 sec)
ERROR:
No query specified
检查主节点半同步插件相关参数
SHOW VARIABLES LIKE '%semi%';
+---------------------------------------------+------------+
| Variable_name | Value |
+---------------------------------------------+------------+
| rpl_semi_sync_source_enabled | ON |
| rpl_semi_sync_source_timeout | 10000 |
| rpl_semi_sync_source_trace_level | 32 |
| rpl_semi_sync_source_wait_for_replica_count | 2 |
| rpl_semi_sync_source_wait_no_replica | ON |
| rpl_semi_sync_source_wait_point | AFTER_SYNC |
+---------------------------------------------+------------+
6 rows in set (0.02 sec)
检查插件运行状态
主要查看半同步状态(Rpl_semi_sync_source_status
)
其他状态变量含义可以参考:Server Status Variables
mysql> SHOW STATUS LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_source_clients | 2 |
| Rpl_semi_sync_source_net_avg_wait_time | 0 | # 网络等待的平均时间
| Rpl_semi_sync_source_net_wait_time | 0 |
| Rpl_semi_sync_source_net_waits | 8 |
| Rpl_semi_sync_source_no_times | 1 |
| Rpl_semi_sync_source_no_tx | 9 | # 异步同步的消息个数
| Rpl_semi_sync_source_status | ON | # 半同步状态,为 ON 即可
| Rpl_semi_sync_source_timefunc_failures | 0 |
| Rpl_semi_sync_source_tx_avg_wait_time | 0 |
| Rpl_semi_sync_source_tx_wait_time | 0 |
| Rpl_semi_sync_source_tx_waits | 0 |
| Rpl_semi_sync_source_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_source_wait_sessions | 0 |
| Rpl_semi_sync_source_yes_tx | 9 | # 半同步的消息个数
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
从节点检查
检查复制状态
# 主要查看 IO 线程以及 SQL 线程运行情况
mysql> SHOW REPLICA STATUS\G;
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
检查插件运行状态
mysql> SHOW STATUS LIKE '%semi%';
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| Rpl_semi_sync_replica_status | ON |
+------------------------------+-------+
验证
主库操作数据
mysql> CREATE DATABASE testdb DEFAULT CHARSET utf8mb4;
mysql> CREATE USER 'testuser'@'%' IDENTIFIED BY 'Qwert123..';
mysql> GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'%';
mysql> FLUSH PRIVILEGES;
mysql> USE testdb;
mysql> CREATE TABLE t_user01(
id int auto_increment primary key,
name varchar(40)
) ENGINE = InnoDB;
BEGIN;
INSERT INTO t_user01 VALUES (1,'user01');
INSERT INTO t_user01 VALUES (2,'user02');
INSERT INTO t_user01 VALUES (3,'user03');
INSERT INTO t_user01 VALUES (4,'user04');
INSERT INTO t_user01 VALUES (5,'user05');
commit;
备库查询
$ mysql -utestuser -p
Enter password:
# 查看数据库,可以看到testdb同步过来了
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| testdb |
+--------------------+
2 rows in set (0.01 sec)
# 数据也同步过来了
mysql> select * from testdb.t_user01;
+----+--------+
| id | name |
+----+--------+
| 1 | user01 |
| 2 | user02 |
| 3 | user03 |
| 4 | user04 |
| 5 | user05 |
+----+--------+
5 rows in set (0.00 sec)
附录 - 主从复制相关连接
主从复制问题处理
连接压缩与 binlog 压缩
Binary Log Transaction Compression
处理 replicas 的意外停止
Handling an Unexpected Halt of a Replica
附录 - my.cnf
常用变量
注:
my.cnf
中的变量设置,可以用下划线、也可以用中划线;详见:Using System Variables
系统变量
bind_address
设置 MySQL 服务的监听地址,多个地址用逗号隔开,默认值为 *
,表示所有本机地址
示例:bind_address=198.51.100.20,2001:db8:0:f101::1
server_id
标识 MySQL 服务的唯一 ID,将记录到 binlog
中。在复制架构中,必须为每个服务指定一个唯一的 ID
取值范围 0~4294967295,默认值为 1;不建议设置为 0(如设置为 0,则会进行二进制日志记录,但 ID 为 0 的 source
会拒绝来自 replicas
的任何连接)
skip_name_resolve
客户端连接时是否解析其主机名
OFF
(默认):mysqld
在客户端连接时先解析主机名再校验权限ON
:mysqld
不解析主机名,只使用 IP 地址;在这种情况下,授权表中的Host
的值都必须是 IP 地址
transaction_isolation
设置事务的隔离级别,各个级别的影响可以参考:InnoDB and the ACID Model
READ-UNCOMMITTED
READ-COMMITTED
REPEATABLE-READ
(默认)SERIALIZABLE
read_only
与 super_read_only
禁止客户端进行更新数据,只能进行读取操作
read_only
:具有CONNECTION_ADMIN
权限(或已弃用的SUPER
权限)的用户可以更新super_read_only
:即使是具有CONNECTION_ADMIN
权限(或已弃用的SUPER
权限)的用户也不能更新
半同步复制插件
注:半同步复制配置参考:Semisynchronous Replication
本文选择在
my.cnf
配置加载插件;插件加载的不同方法请参考:Installing and Uninstalling Plugins
插件加载
命令加载
插件可以在 mysql 服务运行后,使用命令加载,如下
INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';
INSTALL PLUGIN rpl_semi_sync_replica SONAME 'semisync_replica.so';
配置文件配置加载
plugin_dir
:设置插件的路径,DNF 或 YUM 安装的默认插件路径为:/usr/lib64/mysql/plugin/
plugin_load
:加载插件,多个插件用分号隔开
示例
plugin_dir = "/usr/lib64/mysql/plugin/"
plugin_load = "rpl_semi_sync_source=semisync_source.so;rpl_semi_sync_replica=semisync_replica.so"
检查插件加载情况
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_source | ACTIVE |
+----------------------+---------------+
半同步复制插件版本差异
半同步复制插件分为两个,一个用于 source
,一个用于 replicas
。从 MySQL 8.0.26 开始,插件名称和相关的变量名称也有所改变(master
和 slave
替换成 source
和 replica
)
插件库文件的文件名后缀因平台而异(例如: Unix 和类 Unix 系统为 .so
,Windows 为 .dll
)。插件和库文件名如下:
source
,旧:rpl_semi_sync_master
插件(semisync_master.so
或semisync_master.dll
库)source
,新(MySQL 8.0.26+):rpl_semi_sync_source
插件(semisync_source.so
或semisync_source.dll
库)replicas
,旧:rpl_semi_sync_slave
插件(semisync_slave.so
或semisync_slave.dll
库)replicas
,新(MySQL 8.0.26+):rpl_semi_sync_replica
插件(semisync_replica.so
或semisync_replica.dll
库)
loose-*
前缀
loose-*
前缀作用有两个
-
在 MySQL 程序启动指定选项时使用。如果一个选项的前缀是
loose-*
,那么当 mysql 识别不了该选项时,不会发出错误并退出,而是只发出警告 -
在
my.cnf
配置安装插件时使用。loose
前缀允许在my.cnf
文件中添加插件选项,即使在安装插件之前。这样做的好处是,即使插件尚未加载,也可以为其配置选项。当插件被安装时(启动 MySQL 服务或者使用INSTALL PLUGIN
命令),它会自动读取这些选项。这种方法提供了灵活性,因为您以在不重新启动整个服务器的情况下,更新插件的选项(修改my.cnf
插件选项,然后卸载插件再加载插件)
source
(主)
注:
rpl_semi_sync_master_*
选项或参数适用于rpl_semi_sync_master
插件 (semisync_master.so
库)rpl_semi_sync_source_*
(MySQL 8.0.26+)选项或参数适用于rpl_semi_sync_source
插件(semisync_source.so
库)
auto_increment_offset
与 auto_increment_increment
用于主主(source to source
)复制。auto_increment_offset
设置自增列的起始值,auto_increment_increment
设置步长
rpl_semi_sync_master_enabled
与 rpl_semi_sync_source_enabled
控制是否在主服务器(source
)上启用半同步复制。取值为 ON
或 OFF
(或 1
与 0
)。默认为 OFF
rpl_semi_sync_master_timeout
与 rpl_semi_sync_source_timeout
控制 source
在提交事务时,等待 replicas
确认的时间。如果超时,就会恢复到异步复制。单位时毫秒,默认为 10000 毫秒(10秒)
rpl_semi_sync_master_trace_level
与 rpl_semi_sync_source_trace_level
指定 source
上的半同步复制调试跟踪级别,可以设置以下几个值。默认为 1
-
1
:一般级别(例如,时间功能故障) -
16
:详细级别(更详细的信息) -
32
:网络等待级别(有关网络等待的更多信息) -
64
:函数级别(关于函数进入和退出的信息)
rpl_semi_sync_master_wait_for_slave_count
与 rpl_semi_sync_source_wait_for_replica_count
指定 source
事务提交存储引擎之前,每个事务必须接收的 replicas
回复的确认(ack)数。默认值为:1
,这意味着半同步复制在接收到 1
个副本确认后就进行下一步操作。此变量值较小时性能更好,较大时可以保证更强的可靠性
假设值为 2
;则必须有 2 个副本在配置的超时时间(rpl_semi_sync_master_timeout
与 rpl_semi_sync_source_timeout
)之前确认收到事务,source
才会继续进行半同步复制。如果在超时期间确认收到事务的副本小于 2,则 source
将恢复到异步复制
rpl_semi_sync_master_wait_no_slave
与 rpl_semi_sync_source_wait_no_replica
取值为 ON
或 OFF
(或 1
与 0
)。默认为 ON
- 当取值为
ON
时,在超时时间(由上述的rpl_semi_sync_master_timeout
与rpl_semi_sync_source_timeout
决定)内,即使source
发现replicas
数量(状态变量Rpl_semi_sync_master_clients
与Rpl_semi_sync_source_clients
)小于需要返回确认消息的数量(由rpl_semi_sync_master_wait_for_slave_count
与rpl_semi_sync_source_wait_for_replica_count
决定),依旧保持半同步复制(Rpl_semi_sync_master_status
与Rpl_semi_sync_source_status
为ON
)。直到超时,才会转为异步模式(Rpl_semi_sync_master_status
与Rpl_semi_sync_source_status
为OFF
) - 当取值为
OFF
时,在超时时间(由上述的rpl_semi_sync_master_timeout
与rpl_semi_sync_source_timeout
决定)内,只要source
发现replicas
数量(状态变量Rpl_semi_sync_master_clients
与Rpl_semi_sync_source_clients
)小于需要返回确认消息的数量(由rpl_semi_sync_master_wait_for_slave_count
与rpl_semi_sync_source_wait_for_replica_count
决定),就会转为异步模式(Rpl_semi_sync_master_status
与Rpl_semi_sync_source_status
为OFF
)
注:无论是
ON
或OFF
,当replicas
数量恢复到需要返回确认消息的replcas
数量时,异步模式就会恢复到半同步模式
rpl_semi_sync_master_wait_point
与 rpl_semi_sync_source_wait_point
此变量控制半同步复制 source
在向提交事务的客户端返回状态之前,等待事务接收的 replicas
确认的时间点。有两个值:
注:假设已经设置了
sync_binlog=1
,否则binlog
刷盘时间将由操作系统决定
-
AFTER_SYNC
(默认值,推荐使用):source
将每个事务写入其binlog
(buffer),再发送到replicas
,然后将binlog
(buffer)同步到磁盘binlog file
。同步之后,source
将等待事务接收的replicas
返回确认信息。在收到确认后,source
将事务提交给存储引擎,并将结果返回给客户端,然后客户端继续下一步操作 -
AFTER_COMMIT
:source
将每个事务写入其binlog
(buffer),再发送到replicas
,然后将binlog
(buffer)同步到磁盘binlog file
,并将事务提交到存储引擎。source
在提交存储引擎之后等待事务接收的replicas
返回确认信息。在接收到确认后,source
向客户端返回一个结果,然后客户端继续下一步操作使用
AFTER_COMMIT
时,在提交存储引擎之后到replicas
返回确认信息之前,其他客户端可以在提交客户端之前看到提交的事务。如果出现问题,导致replicas
无法处理事务,那么在source
意外退出并故障转移到replicas
的情况下,这些客户端可能会看到与在源上看到的数据相关的数据丢失
replicas
(从)
注: replica_*
变量或参数适用于 MySQL 8.0.26+ 版本,slave_*
变量或参数适用于 MySQL 8.0.26 之前版本
两个过滤选项
-
--replicate-do-db={DB_NAME}
只有指定的数据库会进行复制
此选项影响复制的方式与
--binlog-do-db
影响二进制日志记录的方式相同 -
--replicate-ignore-db={DB_NAME}
指定的数据库不会进行复制
master_info_repository
注:现在不推荐使用此系统变量
设置 I/O 线程的执行状态信息(包括状态和连接信息)的存储方式
可取两个值:
FILE
:replicas
的连接元数据存储库写入默认名称为master.info
的文件TABLE
(默认):replicas
将有关source
的元数据,记录到系统数据库中名为InnoDB
的表中
replica_compressed_protocol
与 slave_compressed_protocol
开启主从之间连接数据的压缩,可选值为 ON
或 OFF
,默认值为OFF
即使已经开启 binlog_transaction_compression
,依然可以对非 binlog
的数据进行压缩
replica_load_tmpdir
与 slave_load_tmpdir
指定 replcas
创建临时文件的目录名称
replicas
的 SQL 线程在加载数据时,会从中继日志中提取要加载的文件到临时文件中,然后再将这些文件加载到表中。如果 source
上加载的文件很大,则replicas
上的临时文件也很大,中继日志也会很大
replica_max_allowed_packet
与 slave_max_allowed_packet
设置 replicas
的 SQL 线程和 I/O 线程可以处理的最大数据包大小,以字节为单位,默认为 1G,最大值也是 1G
设置此变量会立即对所有复制通道生效,包括正在运行的通道。
replica_net_timeout
与 slave_net_timeout
replicas
认为连接断开的超时时间。以秒为单位,默认 60 秒
在超时后,replicas
会重新尝试连接。重试之间的间隔由语句的 SOURCE_CONNECT_RETRY
选项控制,重新连接尝试的次数受SOURCE_RETRY_COUNT
选项限制,这两个选项均在运行 CHANGE REPLICATION SOURCE TO
时设置
replica_parallel_type
与 slave_parallel_type
对于启用多线程的 replcas
( replica_parallel_workers
或 slave_parallel_workers
的值大于 1),replica_parallel_type
指定事务在 replcas
上并行执行的策略。有两个取值:
LOGICAL_CLOCK
(≥ 8.0.27 版本默认,推荐):基于source
写入二进制日志的时间戳,事务在replicas
上并行应用。事务之间的依赖关系根据它们的时间戳进行跟踪DATABASE
(< 8.0.27 版本默认):更新不同数据库的事务是并行应用的。仅当数据被分区到多个数据库中,并且在source
上独立、同时更新时,此值才适用。必须没有跨数据库约束,因为这样的约束可能会在replicas
上回放可能会导致错误
replica_parallel_type
在后续版本可能会弃用,默认使用并且只能使用 LOGICAL_CLOCK
值
replica_parallel_workers
与 slave_parallel_workers
在 replicas
上启用多线程并设置用于并行执行复制事务的 SQL 线程数
- 当该值为 0 或 1 时,均不会启用多线程
- 当该值为大于 1 的数字时,副本是一个多线程副本,具有指定数量的应用程序线程,加上一个协调器线程来管理它们。如果有多个复制通道(多个
source
),则每个通道都对应有此数量的线程
在 MySQL 8.0.27 之前,这个变量默认为 0,所以 replicas
默认是单线程的。从 MySQL 8.0.27 开始,默认值为 4,因此默认为多线程
replica_preserve_commit_order
与 slave_preserve_commit_order
对于多线程 replicas
( replica_parallel_workers
或 slave_parallel_workers
的值大于 1),可以取值 ON
或 OFF
ON
(≥ 8.0.27 版本默认,推荐):可以确保事务在replicas
上执行和提交的顺序,与它们在replcias
的中继日志中出现的顺序相同。这可以防止从中继日志执行的事务序列中出现间隙,并在副本上保留与源上相同的事务历史记录OFF
(< 8.0.27 版本默认) :多线程副本并行应用的事务可能会乱序提交
replica_transaction_retries
与 slave_transaction_retries
设置单线程或多线程 replicas
上用于复制的 SQL 线程失败事务的最大次数,超过后停止自动重试。默认值为 10
replication_optimize_for_static_plugin_config
使用共享锁,避免不必要的锁获取,以提高半同步复制或组复制(group replication)的性能。在多个 replicas
时才有效果。可以设置 ON
或者 OFF
,默认为 OFF
注:启用此变量后,无法卸载半同步复制插件,必须在卸载之前禁用该变量
replication_sender_observe_commit_only
限制回调以提高半同步复制的性能。在多个 replicas
时才有效果。可以设置 ON
或者 OFF
,默认为 OFF
rpl_read_size
控制从二进制日志文件和中继日志文件读取的最小数据量,以字节为单位,默认为 8192(该值必须是 4096 的整数倍)。如果 IO 频繁,可以适当增加该值
注:
rpl_semi_sync_slave_*
选项或参数适用于rpl_semi_sync_slave
插件 (semisync_slave.so
库)rpl_semi_sync_replica_*
(MySQL 8.0.26+)选项或参数适用于rpl_semi_sync_replica
插件(semisync_replica.so
库)
rpl_semi_sync_replica_enabled
与 rpl_semi_sync_slave_enabled
控制是否在副本服务器上启用半同步复制。此变量仅在安装了半同步复制插件时可用
rpl_semi_sync_replica_trace_level
与 rpl_semi_sync_slave_trace_level
控制半同步复制调试跟踪级别,可以参考 rpl_semi_sync_master_trace_level
sync_source_info
与 sync_master_info
指定 replicas
在多少个二进制日志事件之后,更新连接 source
的元数据存储库( 源数据存储库由变量 master_info_repository
指定是文件还是数据表)。默认为 1000,若设置为 0,则表示永不更新
binlog
相关
两个过滤选项
-
--binlog-do-db={DB_NAME}
只有指定的数据库会写入
binlog
-
--binlog-ignore-db={DB_NAME}
忽略指定的数据库,不写入
binlog
binlog_error_action
当服务器遇到错误时(例如无法写入、刷新或同步二进制日志)的行为,有两个取值
IGNORE_ERROR
:遇到错误时,会继续进行中的事务,忽略错误并继续执行更新。这可能导致源的二进制日志变得不一致ABORT_SERVER
(默认):遇到错误时,停止记录并关闭服务
binlog_expire_logs_seconds
以秒为单位设置二进制日志过期时间。默认值为:2592000,即 30 天
expire_logs_days
(已弃用)
指定自动删除指定天数之前的二进制日志文件
binlog_expire_logs_auto_purge
是否开启二进制日志文件的自动清除,默认为 NO
,即启用删除
binlog_format
详见简介 binlog
格式
binlog_order_commits
当在 source
上启用此变量时(默认设置),向存储引擎发出的事务提交指令在单个线程上被序列化,因此事务总是以与写入二进制日志相同的顺序提交。禁用此变量允许使用多个线程发出事务提交指令,与二进制日志组提交结合使用,可以防止单个事务的提交率成为吞吐量的瓶颈,因此可能会提高性能
如果要确保 source
和多线程的 replica
上的事务历史记录保持相同,则应该设置slave_preserve_commit_order
或 replica_preserve_commit_order
的值为 1
binlog_group_commit_sync_delay
控制在将二进制日志文件同步到磁盘之前延迟的微秒数,默认为 0,表示没有延迟。设置延迟可以使更多事务同时同步到磁盘,从而减少提交一组事务的总时间。还可以减少任何具有二进制日志的服务器(source
或 replica
)上对二进制日志的调用次数,即减少 fsync()
当设置 sync_binlog=0
或 sync_binlog=1
时,指定的延迟 binlog_group_commit_sync_delay
在同步之前应用于每个二进制日志提交组。当 sync_binlog
设置为大于 1的值 n
时,则在每 n
个二进制日志提交组之后应用延迟
建议:设置
binlog_group_commit_sync_delay
会增加服务器上事务的延迟。在并发事务较多的情况下,可以根据实际情况设置一定延迟
binlog_group_commit_sync_no_delay_count
若在二进制日志文件同步到磁盘延迟时间内,事务数达到该变量设置的值,则立刻中止当前延迟之前等待,立即同步磁盘
如果 binlog_group_commit_sync_delay
设置为 0,则此选项无效
注:
binlog_group_commit_sync_delay
和binlog_group_commit_sync_no_delay_count
这两个参数是用于故意拉长binlog
从write
到fsync
的时间,以此减少binlog
的写盘次数
binlog_group_commit_sync_delay
和 binlog_group_commit_sync_no_delay_count
是两个 MySQL 服务器系统变量,用于优化二进制日志文件(binary log)的写入性能。正确配置这两个变量可以提高数据库的写入性能,减少同步延迟,但也增加了主从延迟时间,并且可能在崩溃时导致主从不一致的风险
binlog_group_commit_sync_delay
:根据数据库负载和延迟要求进行调整,通常建议从较低的值(例如 500 微秒)开始,逐步增加并观察性能binlog_group_commit_sync_no_delay_count
:根据您的事务并发量进行调整,通常可以设置为 5 或 10 ,观察性能后再进行调整
合适的设置取决于您的应用程序和数据库的需求。在调整这些值时,请注意以下几点:
- 测试不同的值以找到最佳平衡。增加
binlog_group_commit_sync_delay
可能会提高吞吐量,但会增加延迟。增加binlog_group_commit_sync_no_delay_count
可能会减少延迟,但可能降低吞吐量。 - 监视数据库性能指标,如事务延迟和吞吐量,以确定是否需要调整这些值。
- 在生产环境中进行更改之前,请在测试环境中验证新设置。
总之,要找到合适的 binlog_group_commit_sync_delay
和 binlog_group_commit_sync_no_delay_count
设置,需要根据您的数据库负载、性能要求和可接受的延迟来进行多次测试和调整
binlog_row_event_max_size
当 binlog_format = ROW
时,该设置有效
此设置是对二进制日志事件的大小的软限制(不会报错退出),以字节为单位。默认为 8192。
当超过该限制时,存储在二进制日志中的行会被分组为大小不超过此设置值的事件。如果无法拆分事件,则可能会超过最大限制
binlog_row_image
当 binlog_format = ROW
时,该设置有效
这个变量决定了如何将行的镜像(包括修改前的镜像和修改后的镜像)写入二进制日志。在行更改事件中,通常 MySQL 会记录前后镜像的完整行(包含所有列)。然而,并不是绝对有必要在两个镜像中都包括每一列,可以通过仅记录那些实际需要的列来节省磁盘、内存和网络使用
可以设置以下三个值
full
(默认):记录行的修改前镜像和修改后镜像中的所有列minimal
:仅记录修改前镜像中标识为要修改的行的那些列;仅记录修改后镜像中由 SQL 语句指定值或由自动递增生成的那些列noblob
:记录所有列(与full
相同),BLOB
和TEXT
数据类型除外
binlog_rows_query_log_events
当 binlog_format = ROW
时,该设置有效
该变量常用于调试。设置为 ON
后,可以让服务器将行查询日志事件等信息日志事件写入其二进制日志
binlog_transaction_compression
MySQL 8.0.20+ 支持该变量
对写入的二进制日志文件的事务启用压缩。默认为 OFF
,即不启用压缩。压缩事务会一直保持压缩状态,并以压缩状态写入 replicas
的中继日志。因此,二进制日志事务压缩为事务的发起者和接收者(以及他们的备份)都节省了存储空间,并在服务器实例之间发送事务时节省了网络带宽
二进制日志压缩可以参考:Binary Log Transaction Compression
binlog_transaction_compression_level_zstd
设置二进制日志事务压缩的压缩级别,取值可以为 1~22 中的整数值,默认为 3。数值越大,压缩率越高,但压缩时占用的 CPU 和内存资源也就越多
binlog_transaction_dependency_tracking
在 source
生成一些写入二进制日志的依赖信息,以帮助 replicas
确定哪些事务可以并行执行。有三个取值:
COMMIT_ORDER
(默认):如果第一个事务的提交时间窗口与第二个事务的提交时间窗口重叠,则两个事务被认为是独立的。提交时间窗口在事务的最后一条语句执行后立即开始,并在存储引擎提交结束后立即结束。由于事务持有这两个时间点之间的所有行锁,MySQL 知道它们不能更新相同的行WRITESET
:事务中的每一行通过散列添加到一个写集中,如果两个事务的写入集重叠,则两个事务被认为是冲突的WRITESET_SESSION
:如果以下任一陈述为真,则两个事务被认为是相关的:- 事务依赖于
WRITESET
- 事务是在同一个用户会话中提交的
- 事务依赖于
注:要设置
binlog_transaction_dependency_tracking
为WRITESET
或WRITESET_SESSION
, 则transaction_write_set_extraction
必须设置为OFF
以外的值;默认值 (XXHASH64
) 即可
transaction_write_set_extraction
(已弃用)
从 MySQL 8.0.26 开始弃用,
指定用于散列事务期间提取的写入的算法。默认值为 XXHASH64
。设置为 OFF
意味着不收集写集
log_bin
是否开启二进制日志记录,取值为 ON
或 OFF
log_bin_basename
保存二进制日志文件的基本名称和路径,也可以直接在 log_bin
设置路径和名称。若未设置 log_bin_basename
,则默认的二进制日志文件名称为 binlog
,默认保持位置是数据目录。如果 log-bin
提供的值没有字符串或空字符串,则默认基本名称为 ${HOSTNAME}-bin
log_bin_index
保存二进制日志索引文件的基本名称和路径
log_bin_trust_function_creators
二进制日志是否信任存储过程和函数(即记录事件),默认为 OFF
,即不记录存储过程和函数产生的时间
log_replica_updates
与 log_slave_updates
指定 replicas
从 source
接收的更新是否应记录到自己的二进制日志中,默认为 ON
。常用于级联复制架构
binlog_cache_size
事务执行期间用于保存 binlog
更改的内存缓冲区的大小,单位是 bytes,默认值为 32768(32K)。每个会话连接都会分配该缓存
binlog_stmt_cache_size
二进制日志的内存缓冲区大小,用于保存事务期间发出的非事务性语句。单位为 byte,默认 32768(32k)。每个会话连接都会分配该缓存
max_binlog_cache_size
事务缓存的大小(总缓存上限,语句缓存的上限由 max_binlog_stmt_cache_size
系统变量控制)。单位为 byte,默认值为 16EB,推荐值为 4G(MySQL 当前无法处理大于 4GB 的二进制日志位置)。超出限制时,服务会产生错误 Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage
max_binlog_stmt_cache_size
事务中的非事务语句需要的内存缓冲区的最大限制值,如果超过,则服务会产生错误。单位为 byte,默认值为 4G(32位) 和 16EB(64位)
max_binlog_size
二进制日志文件的大小限制值,如果超出限制,则服务器轮换二进制日志(关闭当前文件并打开下一个文件)
注:如果
max_relay_log_size
为 0,则max_binlog_size
同时适用于中继日志
sync_binlog
控制 MySQL 服务器将二进制日志同步到磁盘的频率,关系到数据持久性和一致性
sync_binlog=0
:禁用 MySQL 服务将二进制日志同步到磁盘。此时,MySQL 服务器只能依靠操作系统不时将二进制日志刷新到磁盘,就像它对任何其他文件所做的那样。此设置提供最佳性能,但在电源故障或操作系统崩溃的情况下,服务器可能已提交尚未同步到二进制日志的事务sync_binlog=1
(默认值):在提交事务之前启用二进制日志到磁盘的同步。这是最安全的设置,但由于磁盘写入次数增加,可能会对磁盘I/O
性能产生负面影响。在电源故障或操作系统崩溃的情况下,二进制日志中丢失的事务仅处于准备状态。这允许自动恢复例程回滚事务,从而保证二进制日志中不会丢失任何事务sync_binlog=N
,其中 N 为大于 1 的整数值。收集 N 个二进制日志提交组再后同步到磁盘 。在电源故障或操作系统崩溃的情况下,服务器可能已提交尚未刷新到二进制日志的事务
InnoDB
存储引擎为了在与事务一起使用的复制设置中获得最大可能的持久性和一致性,请使用以下设置(著名的双一设置):
sync_binlog=1
innodb_flush_log_at_trx_commit=1
relay log
相关
relay_log
设置中继日志文件的完整路径和基本名称
对于默认复制通道,中继日志的默认基本名称是 ${HOSTNAME}-relay-bin
。 对于非默认复制通道,中继日志的默认基本名称是:${HOSTNAME}-relay-bin-${channel}
,其中 ${channel}
是记录在此中继日志中的复制通道的名称
relay_log_basename
保存中继日志文件的完整路径和基本名称。注:该变量由 MySQL 服务自动设置并且是只读的
relay_log_index
保存中继日志索引文件的完整路径和基本名称
relay_log_info_repository
设置 SQL 线程的执行状态和信息的存储方式
可以取值
FILE
:将元数据存储库以文件形式保存TABLE
(默认,推荐):将元数据存储库以数据表形式保存,在配置多个复制通道时必须是TABLE
relay_log_purge
设置是否启用中继日志文件的自动清除。默认值为 1 ( ON
)
relay_log_recovery
设置是否在服务启动时自动进行中继日志恢复。取值为 ON
或 OFF
,默认为 OFF
设置为 ON
,具备更好的安全性,可以参考:Handling an Unexpected Halt of a Replica
relay_log_space_limit
所有中继日志的最大空间使用量,单位为字节,默认为 0,表示不限制
max_relay_log_size
如果 replicas
的中继日志的写入导致当前日志文件大小超过此变量的值,则 replicas
将轮转中继日志(关闭当前文件并打开下一个文件)。如果设置为 0,则使用 max_binlog_size
的配置,默认使用 max_binlog_size
的配置
sync_relay_log
在中继日志有多少事件时进行持久化到磁盘,该设置会中继日志持久化到磁盘的方式
-
如果设置等于 0,服务将不会主动同步中继日志到磁盘。在这种情况下,只能依靠操作系统不时刷新中继日志的内容,就像任何其他文件一样
-
如果设置大于 0,则在对应数量事件写入中继日志后,MySQL服务器会将其中继日志同步到磁盘(使用
fdatasync()
)
默认值为 10000,即 10000 个事件同步磁盘一次
设置 sync_relay_log=1
是最安全的选择,因为在意外停止的情况下,您最多会从中继日志中丢失一个事件。但是也是最慢的选择,因为频繁同步到磁盘可能会导致磁盘 IO 性能瓶颈
sync_relay_log=1
对于多线程复制尤为重要,如果 replicas
意外停止,重启时无法使用中继日志中的信息填充事务序列中的间隙,则恢复过程将失败
设置建议:根据
replcias
的重要程度决定要可靠性还是性能如果
replicas
在异常中断重启后,可以通过其他方式(例如备份)来快速靠近source
的数据,可以适当增大该变量
sync_relay_log_info
(已弃用)
在 MySQL 8.0 中已弃用,MySQL 8.0 的默认设会在每个事务后更新
设置多少个中继日志事件之后,进行更新元数据存储库(SQL 线程执行状态和信息)
GTID 相关
gtid_mode
控制是否启用基于 GTID 的日志记录以及日志可以包含的事务类型
记录的事务可以是匿名的(匿名事务依赖于 binlog file
和 position
来识别特定的事务),也可以使用 GTID。GTID 事务有一个唯一的标识符,用于引用事务
可以有四种取值:
OFF
:新事务(source
)和复制的事务(replicas
)都必须是匿名OFF_PERMISSIVE
: 新事务(source
)是匿名的。复制的事务(replicas
)可以是匿名事务或 GTID 事务ON_PERMISSIVE
:新事务(source
)是 GTID 事务。复制的事务(replicas
)可以是匿名事务或 GTID 事务ON
:新事务(source
)和复制的事务(replicas
)都必须是 GTID 事务
注:
enforce_gtid_consistency
必须设置为ON
才能设置gtid_mode=ON
binlog_gtid_simple_recovery
该变量控制 MySQL 启动或重新启动时,在搜索 GTID 的过程中如何迭代 binlog
文件。取值为 ON
或 OFF
(或 1
与 0
),默认为 ON
,可以加快恢复 binlog
。若设置为 ON
,需保证 binlog
都是由 MySQL 5.7.8+ 版本产生,否则将导致 binlog
损坏,再也无法恢复
enforce_gtid_consistency
是否强制执行 GTID 一致性,有三个取值:
OFF
或0
(默认):允许所有事务违反 GTID 一致性ON
或1
: 不允许任何事务违反 GTID 一致性WARN
或2
:允许所有事务违反 GTID 一致性,但在这种情况下会生成警告
建议设置为 ON
,保证强制一致性
gtid_next
该变量用于指定是否以及如何获取下一个 GTID,该变量只能够使用命令行设置(应用范围是 session
,可以用于跳过一些事务),有两个取值:
AUTOMATIC
(默认):使用下一个自动生成的全局事务 IDANONYMOUS
:事务没有全局标识符,仅由二进制文件和位置标识
注:若
gtid_mode
设置为 OFF,则设置此变量无效