更新时间: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

MariaDB:MySQL Replication Master | MariaDB Knowledge Base

主从复制使数据能够从一个 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:每个 replicasI/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

参考-2:Setting The Binary Log Format

二进制日志(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 支持两种不同的复制方法

GTID

GTID 简介

GTID (Global Transaction Identifiers),是对于一个已提交事务的全局编号,也是事务的唯一编号。GTID 和事务会记录到 binlog 中,用来标识事务。 GTID 是用来替代以前传统复制方法(binlog + position),可以避免同一个事务在同一个节点中出现多次的情况。MySQL 5.6.2 开始支持 GTID

GTID 的优势

  • 根据 GTID 可以快速的确定事务最初是在哪个实例上提交的
  • 简单的实现 failover,不用以前那样在需要找事务位于哪个 binlogposition
  • 更简单的搭建主从复制,确保每个事务只会被执行一次
  • 比传统的复制更加安全。GTID 的引入使运维更省事

GTID 使用注意事项

参考:Restrictions on Replication with GTIDs

  • 因为基于 GTID 的复制依赖于事务,所以在使用 GTID 时,有些 MySQL 特性是不支持的
  • 主从库的表存储引擎必须一致
  • 不支持非事务引擎(从库报错)
  • 不支持 create table … select 语句复制(主库直接报错)
  • 不允许在一个 SQL 同时更新一个事务引擎和非事务引擎的表
  • 在一个复制组中,必须要求统一开启 GTID 或是关闭 GTID
  • 开启 GTID 后,就不能再使用原来的传统的复制方式
  • 对于 create temporary tabledrop temporary table 语句不支持
  • 不支持 sql_slave_skip_countersql_replica_skip_counter
  • 不推荐在 GTID 模式的实例上进行 mysql_upgrade,因为 mysql_upgrade 的过程要创建或修改系统表(非事务引擎),所以不建议在开启 GTID 的模式的实例上使用带 有 --write-binlog 选项的 mysql_upgrade

传统方式配置主从

参考:Setting Up Binary Log File Position Based Replication

准备

拓扑

01-topo

主机列表

主机名IP安装服务角色server_id
db-mysql-1192.168.111.191mysql 8.0.32source(主)191
db-mysql-2192.168.111.192mysql 8.0.32replicas(从)192
db-mysql-3192.168.111.193mysql 8.0.32replicas(从)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_addressserver_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 的公钥

参考:Caching SHA-2 Pluggable Authentication

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 **

连接命令参考:SQL Statements for Controlling Replica Servers

使用有复制权限的用户账号连接至主服务器,并启动复制线程

$ 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 配置主从(推荐)

参考:

准备

拓扑

01-topo

主机列表

主机名IP安装服务角色server_id
db-mysql-1192.168.111.191mysql 8.0.32source(主)191
db-mysql-2192.168.111.192mysql 8.0.32replicas(从)192
db-mysql-3192.168.111.193mysql 8.0.32replicas(从)193

此处省略 MySQL 安装过程,可以参考:01-Alma 9 上安装 MySQL 8 - Nemo 的小站 (skynemo.cn)

各主机均完成下面配置

  • 配置时间同步

  • 关闭防火墙

  • 配置国内的 YUM 源(APT 源)

  • 修改主机名称(证书绑定了主机名的时候必须配置)

配置

配置流程

主节点(source

  • 启用二进制日志
  • 为当前节点设置一个全局唯一的 server_id
  • 创建有复制权限(REPLIACTION SLAVEREPLIATION 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_addressserver_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 的公钥

参考:Caching SHA-2 Pluggable Authentication

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 **

连接命令参考:SQL Statements for Controlling Replica Servers

使用有复制权限的用户账号连接至主服务器,并启动复制线程

$ 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)

附录 - 主从复制相关连接

主从复制问题处理

Troubleshooting Replication

连接压缩与 binlog 压缩

Binary Log Transaction Compression

处理 replicas 的意外停止

Handling an Unexpected Halt of a Replica

附录 - my.cnf 常用变量

注:my.cnf 中的变量设置,可以用下划线、也可以用中划线;详见:Using System Variables

系统变量

参考:Server 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 在客户端连接时先解析主机名再校验权限
  • ONmysqld 不解析主机名,只使用 IP 地址;在这种情况下,授权表中的 Host 的值都必须是 IP 地址

transaction_isolation

设置事务的隔离级别,各个级别的影响可以参考:InnoDB and the ACID Model

  • READ-UNCOMMITTED
  • READ-COMMITTED
  • REPEATABLE-READ(默认)
  • SERIALIZABLE

read_onlysuper_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 开始,插件名称和相关的变量名称也有所改变(masterslave 替换成 sourcereplica

插件库文件的文件名后缀因平台而异(例如: 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-* 前缀

参考-1:Program Option Modifiers

参考-2:INSTALL PLUGIN Statement

参考-3:Troubleshooting the InnoDB memcached Plugin

loose-* 前缀作用有两个

  • 在 MySQL 程序启动指定选项时使用。如果一个选项的前缀是 loose-*,那么当 mysql 识别不了该选项时,不会发出错误并退出,而是只发出警告

  • my.cnf 配置安装插件时使用。loose 前缀允许在 my.cnf 文件中添加插件选项,即使在安装插件之前。这样做的好处是,即使插件尚未加载,也可以为其配置选项。当插件被安装时(启动 MySQL 服务或者使用 INSTALL PLUGIN 命令),它会自动读取这些选项。这种方法提供了灵活性,因为您以在不重新启动整个服务器的情况下,更新插件的选项(修改 my.cnf 插件选项,然后卸载插件再加载插件)

source(主)

参考:Replication Source Options and Variables

注:

  • 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_offsetauto_increment_increment

用于主主(source to source)复制。auto_increment_offset 设置自增列的起始值,auto_increment_increment 设置步长

rpl_semi_sync_master_enabledrpl_semi_sync_source_enabled

控制是否在主服务器(source)上启用半同步复制。取值为 ONOFF(或 10)。默认为 OFF

rpl_semi_sync_master_timeoutrpl_semi_sync_source_timeout

控制 source 在提交事务时,等待 replicas 确认的时间。如果超时,就会恢复到异步复制。单位时毫秒,默认为 10000 毫秒(10秒)

rpl_semi_sync_master_trace_levelrpl_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_timeoutrpl_semi_sync_source_timeout)之前确认收到事务,source 才会继续进行半同步复制。如果在超时期间确认收到事务的副本小于 2,则 source 将恢复到异步复制

rpl_semi_sync_master_wait_no_slaverpl_semi_sync_source_wait_no_replica

取值为 ONOFF(或 10)。默认为 ON

  • 当取值为 ON 时,在超时时间(由上述的 rpl_semi_sync_master_timeoutrpl_semi_sync_source_timeout决定)内,即使 source 发现 replicas 数量(状态变量 Rpl_semi_sync_master_clientsRpl_semi_sync_source_clients)小于需要返回确认消息的数量(由rpl_semi_sync_master_wait_for_slave_count rpl_semi_sync_source_wait_for_replica_count 决定),依旧保持半同步复制(Rpl_semi_sync_master_statusRpl_semi_sync_source_statusON)。直到超时,才会转为异步模式(Rpl_semi_sync_master_statusRpl_semi_sync_source_statusOFF
  • 当取值为 OFF 时,在超时时间(由上述的 rpl_semi_sync_master_timeoutrpl_semi_sync_source_timeout决定)内,只要 source 发现 replicas 数量(状态变量 Rpl_semi_sync_master_clientsRpl_semi_sync_source_clients)小于需要返回确认消息的数量(由rpl_semi_sync_master_wait_for_slave_count rpl_semi_sync_source_wait_for_replica_count 决定),就会转为异步模式(Rpl_semi_sync_master_statusRpl_semi_sync_source_statusOFF

注:无论是 ONOFF,当 replicas 数量恢复到需要返回确认消息的 replcas 数量时,异步模式就会恢复到半同步模式

rpl_semi_sync_master_wait_pointrpl_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_COMMITsource 将每个事务写入其 binlog(buffer),再发送到 replicas,然后将 binlog(buffer)同步到磁盘 binlog file,并将事务提交到存储引擎。source 在提交存储引擎之后等待事务接收的 replicas 返回确认信息。在接收到确认后,source 向客户端返回一个结果,然后客户端继续下一步操作

    使用 AFTER_COMMIT 时,在提交存储引擎之后到 replicas 返回确认信息之前,其他客户端可以在提交客户端之前看到提交的事务。如果出现问题,导致 replicas 无法处理事务,那么在 source 意外退出并故障转移到 replicas 的情况下,这些客户端可能会看到与在源上看到的数据相关的数据丢失

replicas (从)

参考:Replica Server Options and Variables

注: 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 线程的执行状态信息(包括状态和连接信息)的存储方式

可取两个值:

  • FILEreplicas 的连接元数据存储库写入默认名称为 master.info 的文件
  • TABLE(默认):replicas将有关 source 的元数据,记录到系统数据库中名为 InnoDB 的表中

replica_compressed_protocolslave_compressed_protocol

开启主从之间连接数据的压缩,可选值为 ONOFF,默认值为OFF

即使已经开启 binlog_transaction_compression,依然可以对非 binlog 的数据进行压缩

replica_load_tmpdirslave_load_tmpdir

指定 replcas 创建临时文件的目录名称

replicas 的 SQL 线程在加载数据时,会从中继日志中提取要加载的文件到临时文件中,然后再将这些文件加载到表中。如果 source 上加载的文件很大,则replicas上的临时文件也很大,中继日志也会很大

replica_max_allowed_packetslave_max_allowed_packet

设置 replicas 的 SQL 线程和 I/O 线程可以处理的最大数据包大小,以字节为单位,默认为 1G,最大值也是 1G

设置此变量会立即对所有复制通道生效,包括正在运行的通道。

replica_net_timeoutslave_net_timeout

replicas 认为连接断开的超时时间。以秒为单位,默认 60 秒

在超时后,replicas 会重新尝试连接。重试之间的间隔由语句的 SOURCE_CONNECT_RETRY选项控制,重新连接尝试的次数受SOURCE_RETRY_COUNT选项限制,这两个选项均在运行 CHANGE REPLICATION SOURCE TO 时设置

replica_parallel_typeslave_parallel_type

对于启用多线程的 replcasreplica_parallel_workersslave_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_workersslave_parallel_workers

replicas 上启用多线程并设置用于并行执行复制事务的 SQL 线程数

  • 当该值为 0 或 1 时,均不会启用多线程
  • 当该值为大于 1 的数字时,副本是一个多线程副本,具有指定数量的应用程序线程,加上一个协调器线程来管理它们。如果有多个复制通道(多个 source),则每个通道都对应有此数量的线程

在 MySQL 8.0.27 之前,这个变量默认为 0,所以 replicas 默认是单线程的。从 MySQL 8.0.27 开始,默认值为 4,因此默认为多线程

replica_preserve_commit_orderslave_preserve_commit_order

对于多线程 replicasreplica_parallel_workersslave_parallel_workers 的值大于 1),可以取值 ONOFF

  • ON (≥ 8.0.27 版本默认,推荐):可以确保事务在 replicas 上执行和提交的顺序,与它们在 replcias 的中继日志中出现的顺序相同。这可以防止从中继日志执行的事务序列中出现间隙,并在副本上保留与源上相同的事务历史记录
  • OFF(< 8.0.27 版本默认) :多线程副本并行应用的事务可能会乱序提交

replica_transaction_retriesslave_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_enabledrpl_semi_sync_slave_enabled

控制是否在副本服务器上启用半同步复制。此变量仅在安装了半同步复制插件时可用

rpl_semi_sync_replica_trace_levelrpl_semi_sync_slave_trace_level

控制半同步复制调试跟踪级别,可以参考 rpl_semi_sync_master_trace_level

sync_source_infosync_master_info

指定 replicas 在多少个二进制日志事件之后,更新连接 source 的元数据存储库( 源数据存储库由变量 master_info_repository 指定是文件还是数据表)。默认为 1000,若设置为 0,则表示永不更新

binlog 相关

参考:Binary Logging Options and Variables

两个过滤选项

  • --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,表示没有延迟。设置延迟可以使更多事务同时同步到磁盘,从而减少提交一组事务的总时间。还可以减少任何具有二进制日志的服务器(sourcereplica)上对二进制日志的调用次数,即减少 fsync()

当设置 sync_binlog=0sync_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_delaybinlog_group_commit_sync_no_delay_count 这两个参数是用于故意拉长 binlogwritefsync 的时间,以此减少 binlog 的写盘次数

binlog_group_commit_sync_delaybinlog_group_commit_sync_no_delay_count 是两个 MySQL 服务器系统变量,用于优化二进制日志文件(binary log)的写入性能。正确配置这两个变量可以提高数据库的写入性能,减少同步延迟,但也增加了主从延迟时间,并且可能在崩溃时导致主从不一致的风险

  1. binlog_group_commit_sync_delay:根据数据库负载和延迟要求进行调整,通常建议从较低的值(例如 500 微秒)开始,逐步增加并观察性能
  2. 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_delaybinlog_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 相同), BLOBTEXT 数据类型除外

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_trackingWRITESET WRITESET_SESSION, 则 transaction_write_set_extraction必须设置为 OFF 以外的值;默认值 ( XXHASH64) 即可

transaction_write_set_extraction(已弃用)

从 MySQL 8.0.26 开始弃用,

指定用于散列事务期间提取的写入的算法。默认值为 XXHASH64。设置为 OFF 意味着不收集写集

log_bin

是否开启二进制日志记录,取值为 ONOFF

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

指定 replicassource 接收的更新是否应记录到自己的二进制日志中,默认为 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 相关

参考:Replica Server Options and Variables

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

设置是否在服务启动时自动进行中继日志恢复。取值为 ONOFF,默认为 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 相关

参考:Global Transaction ID System Variables

gtid_mode

控制是否启用基于 GTID 的日志记录以及日志可以包含的事务类型

记录的事务可以是匿名的(匿名事务依赖于 binlog fileposition 来识别特定的事务),也可以使用 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 文件。取值为 ONOFF(或 10),默认为 ON,可以加快恢复 binlog。若设置为 ON,需保证 binlog 都是由 MySQL 5.7.8+ 版本产生,否则将导致 binlog 损坏,再也无法恢复

enforce_gtid_consistency

是否强制执行 GTID 一致性,有三个取值:

  • OFF0(默认):允许所有事务违反 GTID 一致性
  • ON1: 不允许任何事务违反 GTID 一致性
  • WARN2:允许所有事务违反 GTID 一致性,但在这种情况下会生成警告

建议设置为 ON,保证强制一致性

gtid_next

该变量用于指定是否以及如何获取下一个 GTID,该变量只能够使用命令行设置(应用范围是 session,可以用于跳过一些事务),有两个取值:

  • AUTOMATIC(默认):使用下一个自动生成的全局事务 ID
  • ANONYMOUS:事务没有全局标识符,仅由二进制文件和位置标识

注:若 gtid_mode 设置为 OFF,则设置此变量无效