MySQL 数据库复制的默认方式是异步复制,但是异步复制的不足之处就在于,当主库把 event 写入二进制日志之后,并不知道从库是否已经接收并应用了。在异步模式的复制,如果主库崩溃,很有可能在主库中已经提交的事务,并没有传到到任何一台从库机器上。在高可用集群架构下做主备切换,就会造成新的主库丢失数据的现象。
MySQL 5.5 版本之后引入了半同步复制功能,主从服务器必须同时安装半同步复制插件,才能开启该复制功能。在该功能下,确保从库接收完主库传递过来的 binlog 内容已经写入到自己的 relay log 里,才会通知主库上的等待线程,该操作完毕。如果等待超时,超过 repl_semi_sync_master_timeout
参数设置的时间,则关闭半同步复制,并自动转换为异步复制模式,直到至少有一台从库通知主库已经接收到 binlog 信息为止。
半同步复制提升了主从之间数据的一致性,让复制更加安全可靠。在 MySQL 5.7.2 版本中增加了rpl_semi_sync_master_wait_point
参数,用来控制半同步模式下主库返回给 session 事务成功之前的事务提交方式。
该参数有两个值:
- AFTER_COMMIT(MySQL 5.6 默认值)
主库将每个事务写入 binlog,并传递给从库,刷新到中继日志中,同时主库提交事务,之后主库开始等待从库的反馈,只有收到从库的回复之后,master 才将commit OK
的结果反馈给客户端。 - AFTER_SYNC(MySQL 5.7 默认值)
主库将每个事务写入 binlog,并传递给从库,刷新到中继日志中,主库开始等待从库的反馈,接收到从库的回复之后,再提交事务并且返回commit OK
结果给客户端。
可以通过
repl_semi_sync_master_wait_for_slave_count
参数来控制主库接收多少个从库写事务成功反馈,才返回成功给客户端。生产环境中使用半同步复制方式,当从库出现故障,等待超时的时间又很长,导致主库无法接收从库信息而无法正常写入时,可通过该参数剔除故障从库。
在 AFTER_SYNC
模式下,即使主库宕机,所有在主库上已经提交的事务都能保证已经同步到从库的中继日志中,不会丢失任何数据。
安装插件
开始下面操作前请先参考『MySQL 的主从、主主复制』准备好主从的环境。
半同步复制插件在 MySQL 安装包中默认就自带了,这里我是使用二进制包格式安装的 MySQL,该插件位置在 MySQL 安装目录(basedir
)下的 lib/plugin/
目录中,如下:
$ ls lib/plugin/semi* | xargs -n1
lib/plugin/semisync_master.so # 主节点插件
lib/plugin/semisync_slave.so # 从节点插件
具体操作继续往下看咯。
在 master 节点中做如下操作:
-- 安装
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.01 sec)
-- 检查是否安装成功,也可通过 show plugins 查看
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE |
+----------------------+---------------+
1 row in set (0.00 sec)
在 slave 节点中做如下操作:
-- 安装
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.01 sec)
-- 检查是否安装成功,也可通过 show plugins 查看
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%';
+---------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+---------------------+---------------+
| rpl_semi_sync_slave | ACTIVE |
+---------------------+---------------+
1 row in set (0.00 sec)
配置
安装了半同步复制插件后,默认情况下会禁用它。必须在 master 和 slave 上都启用插件才能启用半同步复制。如果仅启用一侧,则复制将是异步的。
要控制是否启用已安装的插件,请设置相应的系统变量。可以在运行时使用 SET GLOBAL
或直接修改 /etc/my.cnf
配置文件 来设置这些变量。
master 可用的系统变量:
-- 0:禁用 1:启用,默认为 0
SET GLOBAL rpl_semi_sync_master_enabled = {0|1};
-- 等待 salve 同步信息的超时时间,单位为毫秒,默认为 10000 即 10 秒,如果超过这个时间将恢复异步模式
SET GLOBAL rpl_semi_sync_master_timeout = N;
slave 可用的系统变量:
-- 0:禁用 1:启用,默认为 0
SET GLOBAL rpl_semi_sync_slave_enabled = {0|1};
下面来操作一波。
在 master 节点下做如下操作:
# 启用插件
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
# 设置超时时间为 60 秒
mysql> SET GLOBAL rpl_semi_sync_master_timeout = 60000;
在 slave 节点下做如下操作:
# 启用插件
mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
# 重启 IO 线程
mysql> STOP SLAVE IO_THREAD;START SLAVE IO_THREAD;
此时半同步复制就已经配置完成了~~
相关变量
半同步复制功能的插件公开了几个系统和状态变量,可以检查这些变量以确定其配置和运行状态。
系统变量
系统变量反映了如何配置半同步复制。要检查其值,请使用SHOW VARIABLES
:
master 节点中的系统变量如下:
mysql> show variables like '%semi%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 60000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.01 sec)
slave 节点中的系统变量如下:
mysql> show variables like '%semi%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
2 rows in set (0.02 sec)
这几个变量在上面基本上都有了介绍,就不多说了。
状态变量
状态变量可以监视半同步复制的操作。要检查其值,请使用 SHOW STATUS
:
master 节点中的状态变量如下:
mysql> show status like '%semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 1 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
slave 节点中的状态变量如下:
mysql> show status like '%semi%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.00 sec)
其中各个变量含义入如下:
在 master 端:
Rpl_semi_sync_master_status
:此状态变量用来确定主服务器当前是使用异步还是半同步复制;Rpl_semi_sync_master_clients
:查看连接了多少个半同步 slave;Rpl_semi_sync_master_no_tx
:代表没有成功接收 slave 事务提交回复的次数;Rpl_semi_sync_master_yes_tx
:代表成功接收 slave 事务提交回复的次数;Rpl_semi_sync_master_net_avg_wait_time
:主机等待 slave 回复的平均时间(以微秒为单位)。此变量已弃用,始终为 0,将在以后的版本中删除;Rpl_semi_sync_master_net_wait_time
:主机等待 slave 回复的总时间(以微秒为单位)。此变量已弃用,始终为 0,将在以后的版本中删除;Rpl_semi_sync_master_net_waits
:master 等待 slave 回复的总次数;Rpl_semi_sync_master_no_times
:主服务器关闭半同步复制的次数;Rpl_semi_sync_master_timefunc_failures
:调用gettimeofday()
等时间函数时主服务器失败的次数;Rpl_semi_sync_master_tx_avg_wait_time
:master 等待每个事务的平均时间(以微秒为单位);Rpl_semi_sync_master_tx_wait_time
:master 等待事务的总时间(以微秒为单位);Rpl_semi_sync_master_tx_waits
:主服务器等待事务的总次数;Rpl_semi_sync_master_wait_pos_backtraverse
:master 等待二进制坐标低于先前等待事件的事件的总次数。当事务开始等待回复的顺序与其二进制日志事件的写入顺序不同时,就会发生这种情况;Rpl_semi_sync_master_wait_sessions
:当前正在等待 slave 回复的会话数;
在 slave 端:
Rpl_semi_sync_slave_status
:指示半同步复制当前是否可操作;
模式切换
半同步复制的原理是从库的 I/O thread 接收完主库的 binlog,并把它写入 relay 中后,会给主库一个回馈。但如果主库等待从库的回馈时间超过 repl_semi_sync_master_timeout
参数设置的时间,会自动切换为异步复制方式。
下面就利用 rpl_semi_sync_master_timeout
超时设置,测试半同步复制与异步复制的切换。
1、 查看主库 rpl_semi_sync_master_timeout
设置时间:
mysql> show variables like '%rpl_semi_sync_master_tim%';
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| rpl_semi_sync_master_timeout | 60000 |
+------------------------------+-------+
1 row in set (0.01 sec)
2、从库关闭 I/O 线程:
mysql> stop slave io_thread;
Query OK, 0 rows affected (0.00 sec)
3、 确认从库的半同步功能已关闭:
mysql> show global status like '%semi%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | OFF |
+----------------------------+-------+
1 row in set (0.00 sec)
4、查看主库的半同步复制状态:
mysql> show global status like '%semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
+--------------------------------------------+-------+
14 rows in set (0.01 sec)
5、测试在主库做写操作:
-- 由于 slave 节点没有相应,所以第一次建库耗时 60 秒
mysql> create database testdb1;
Query OK, 1 row affected (1 min 0.00 sec)
-- 由于此时已经切换到了异步模式,所以瞬间就完成了建库操作
mysql> create database testdb2;
Query OK, 1 row affected (0.01 sec)
6、验证一下是否切换回了异步模式,即半同步模式是否已关闭:
mysql> show global status like '%semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 3 |
| Rpl_semi_sync_master_status | OFF |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
参考:
评论区