续:MySQL的半同步模式
数据库主从复制默认是异步模式。这是MySQL等数据库系统常见的主从复制行为。
异步模式的特点
在异步模式下,主服务器(Master)上的I/O线程将二进制日志(binlog)写入到binlog文件中后,就立即返回客户端结果,而不会等待这些二进制日志是否完整传输到从服务器(Slave)以及是否完整存放到从服务器上的中继日志(relay log)中。这种模式的优点是主服务器能够快速地响应客户端请求,但在主服务器发生故障时,可能会存在数据丢失的风险,因为此时主服务器上已经提交的事务可能还没有被传输到从服务器上。
异步模式的配置步骤
异步模式的配置通常包括以下几个步骤:
- 规划server-id:确保主从服务器的server-id唯一。
- 安装数据库:根据实际需要选择合适的安装方式安装MySQL数据库。
- 修改配置文件:在主从服务器的MySQL配置文件中(通常是my.cnf或my.ini),设置相应的复制参数,如开启binlog、设置server-id等。
- 创建复制账号:在主服务器上创建一个用于复制的用户账号,并授权给从服务器。
- 备份并还原数据:在主服务器上备份需要复制的数据库,并将备份文件还原到从服务器上。
- 配置从服务器:在从服务器上配置主服务器的连接信息,包括主服务器的IP地址、端口号、用户名、密码、binlog文件名和位置等。
- 启动复制:在从服务器上启动复制进程,并检查复制状态,确保主从复制正常运行。
半同步模式原理
在异步复制基础上增加了一定程度的同步性,提高数据安全性,减少数据丢失的风险。MySQL半同步模式通过引入等待从服务器确认的机制,有效提高了数据安全性,降低了数据丢失风险,同时保持了相对较低的延迟成本。适用于需要高数据完整性的应用场景。
基本流程
- 主服务器(Master)事务处理与binlog记录:
- 客户端向主服务器发起写操作(如INSERT、UPDATE、DELETE等)。
- 主服务器执行这些操作,并将它们封装在一个或多个事务中。
- 事务完成后,主服务器将事务的所有更改记录到其本地的二进制日志(Binary Log, binlog)。binlog按顺序记录所有数据修改事件,每个事件包含操作类型、涉及的表名、行数据变化等信息。
- binlog事件发送与确认:
- 主服务器上运行一个名为binlog dump线程的后台进程,负责监听从服务器的复制请求。
- 当从服务器连接到主服务器并请求复制时,binlog dump线程开始读取binlog中的事件,并通过网络将其发送到从服务器。
- 与异步复制不同之处在于,主服务器在此时会等待至少一个从服务器的确认,即从服务器必须将接收到的binlog事件写入到其本地的中继日志(Relay Log)并反馈给主服务器。
- 从服务器处理:
- 从服务器启动一个I/O线程,该线程连接到主服务器并请求从某个特定的binlog位置(如最后一次同步的位置)开始复制。
- I/O线程接收到主服务器发来的binlog事件后,将其写入到从服务器本地的中继日志。
- 当I/O线程将binlog事件写入中继日志后,会向主服务器发送一个确认消息(ACK),表明已成功接收并持久化该事件。
- 事务完成:
- 当主服务器收到至少一个从服务器的ACK后,它会向客户端确认事务完成,并继续处理后续的事务。
关键改进与优点
- 数据安全性增强:半同步复制的关键改进在于主服务器在提交事务后,会等待至少一个从服务器确认已接收并持久化该事务的binlog事件。这显著降低了数据丢失的风险,因为在主服务器发生故障时,至少有一个从服务器已经保存了最新的事务数据。
- 适度延迟:相比异步复制,半同步复制增加了等待从服务器确认的步骤,因此写操作的响应时间会有所增加。但与完全同步复制相比,半同步复制仅需一个从服务器确认即可,延迟相对较小。
- 回退机制:在网络问题或从服务器延迟过高导致无法及时确认时,为了避免阻塞主服务器,半同步复制可以自动回退到异步模式。一旦条件恢复,可以重新启用半同步复制。
半同步模式示例:
#半同步模式必须设置gtid
#在上一个实验的基础上做半同步模式的MySQL
#在master端配置启用半同步模式
[root@mysql1 ~]# vim /etc/my.cnf
[root@mysql1 ~]# cat /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
log-bin=mysql-bin
server-id=1
slow_query_log=on
gtid_mode=on
enforce-gtid-consistency=on
rpl_semi_sync_master_enabled=1#master安装/启用一个插件()
[root@mysql1 ~]# mysql -uroot -predhat
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.02 sec)
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema | #在这里面
| folian |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)mysql> SHOW TABLES FROM information_schema;
+---------------------------------------+
| Tables_in_information_schema |
+---------------------------------------+
......略
| PLUGINS | ##我们找的.....略
mysql> SELECT * FROM information_schema.PLUGINS\G;
*************************** 1. row ***************************
PLUGIN_NAME: binlog
PLUGIN_VERSION: 1.0……
*************************** 39. row ***************************
PLUGIN_NAME: PERFORMANCE_SCHEMA
PLUGIN_VERSION: 0.1
PLUGIN_STATUS: ACTIVE
PLUGIN_TYPE: STORAGE ENGINE
……略mysql> SELECT * FROM information_schema.PLUGINS where PLUGIN_NAME LIKE '%SEMI%'\G;
*************************** 1. row ***************************
PLUGIN_NAME: rpl_semi_sync_master #我们刚刚安装的已经安装好了
PLUGIN_VERSION: 1.0
PLUGIN_STATUS: ACTIVE
.......略mysql> SELECT * FROM information_schema.PLUGINS where PLUGIN_NAME LIKE '%SEMI%'\G;
*************************** 1. row ***************************
PLUGIN_NAME: rpl_semi_sync_master
PLUGIN_VERSION: 1.0
PLUGIN_STATUS: ACTIVE
PLUGIN_TYPE: REPLICATION
PLUGIN_TYPE_VERSION: 4.0
PLUGIN_LIBRARY: semisync_master.so
PLUGIN_LIBRARY_VERSION: 1.7
PLUGIN_AUTHOR: He Zhenxing
PLUGIN_DESCRIPTION: Semi-synchronous replication master
PLUGIN_LICENSE: GPL
LOAD_OPTION: ON
1 row in set (0.01 sec)ERROR:
No query specified
#查看mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 10000 |
| 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)
mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| 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.00 sec)
##严格来讲我们只在主配置文本里写了,但没重启,还需要重启才能打开,或者直接在打开后的MySQL中写SET GLOBAL rpl_semi_sync_master_enabled = 1; 以此来打开半同步功能。
#
#
#在slave端开启半同步功能 slave1 slave2[root@mysql2 ~]# vim /etc/my.cnf
[root@mysql2 ~]# cat /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=2
gtid_mode=on
enforce-gtid-consistency=on
rpl_semi_sync_slave_enabled=1
[root@mysql2 ~]# /etc/init.d/mysqld start
Starting MySQL.... SUCCESS![root@mysql2 ~]# mysql -uroot -predhat
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.03 sec)mysql> SET GLOBAL rpl_semi_sync_slave_enabled =1;
Query OK, 0 rows affected (0.00 sec)mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)mysql> START SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
2 rows in set (0.01 sec)mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.01 sec)
slave2(mysql3同上)
#测试
在 master 端写入数据mysql> insert into folian.userlist values ('user2','123');
Query OK, 1 row affected (0.03 sec)mysql> show status like 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 2 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 2 |
| 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 | 1464 |
| Rpl_semi_sync_master_tx_wait_time | 1464 |
| Rpl_semi_sync_master_tx_waits | 1 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 1 |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
故障模拟:在两个slave端mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
#又在master端插入数据mysql> insert into folian.userlist values ('user3','555');
Query OK, 1 row affected (10.01 sec)mysql> show status like 'Rpl_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 | 2 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 1 |
| Rpl_semi_sync_master_status | OFF |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 1464 |
| Rpl_semi_sync_master_tx_wait_time | 1464 |
| Rpl_semi_sync_master_tx_waits | 1 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 1 |
+--------------------------------------------+-------+
14 rows in set (0.01 sec)