默认情况下,MySQL的复制功能是异步的。master把binlog发送给slave时,这个复制动作就已经完成,master不会验证slave是否接收完毕(类似于Oracle DataGuard Maximum Performance)。异步复制同时意味着在把数据从一个mysqld实例拷贝到另一个mysqld时有一个延时,即master当前提交的事务不会在同一时刻拷贝到slave。这也带来了一定的风险,当master或slave发生故障时,slave有可能会没有接收到master发送过来的binlog,这样就会造成了master/slave的数据不一直,甚至在恢复时也会造成数据的损失。
为了解决这个问题,MySQL 在5.5以后引入了一种半同步模式,slave在接收binlog并写入relay log后会给服务器发送一个反馈,告诉master接收完成,当出现超时情况时,master会暂时切换到异步复制模式,和Oracle DataGuard Maximum Available的处理方式比较相似。半同步复制模式必须在master和slave端同时启用,否则master会使用默认的异步模式。
1. 开启半同步
我的环境是RHEL 6.5 x86_64, Percona-Server-server-56(RPM),已经配置了异步的同步模式。
检查动态加载选项和插件列表。
mysql> select @@have_dynamic_loading ;
+------------------------+
| @@have_dynamic_loading |
+------------------------+
| YES |
+------------------------+
1 row in set (0.00 sec)
mysql> show plugins;
......
默认并没有加载半同步插件,rpm发行版的插件.so文件的位置
/usr/lib64/mysql/plugin/semisync_master.so
/usr/lib64/mysql/plugin/semisync_slave.so
然后在M/S上都加载插件并启用同步。初次加载插件后,MySQL会将该插件记录到系统表mysql.plugin中,下次mysqld启动时会自动加载,无需INSTALL PLUGIN
mysql> INSTALL PLUGIN rpl_semi_sync_master soname 'semisync_master.so' ;
Query OK, 0 rows affected (0.01 sec)
mysql> INSTALL PLUGIN rpl_semi_sync_slave soname 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)
mysql> SET GLOBAL rpl_semi_sync_master_enabled=ON;
mysql> SET GLOBAL rpl_semi_sync_slave_enabled=ON;
要将rpl_semi_sync_master_enabled和rpl_semi_sync_slave_enabled参数写入配置文件my.cnf
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_slave_enabled =1
日志文件会显示:
2014-08-14 14:13:23 5927 [Note] Semi-sync replication initialized for transactions.
2014-08-14 14:13:23 5927 [Note] Semi-sync replication enabled on the master.
2. 半同步的参数说明
在master上有4个相关参数,slave中有2个.
mysql> show global variables like 'rpl_semi%';
+------------------------------------+-------+
| Variable_name | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled | ON | --master上是否开启了半同步复制模式
| rpl_semi_sync_master_timeout | 10000 | --该参数默认为10000毫秒,可动态调整。它用来表示如果主库中某个事务等待时间超过10秒,则降级为异步复制模式。
| rpl_semi_sync_master_trace_level | 32 | --开启半同模式的调试级别
| rpl_semi_sync_master_wait_no_slave | ON | --表示是否允许master每个事物提交后都要等待slave的接收等待确认信号,默认为ON。
| rpl_semi_sync_slave_enabled | ON | --slave是否开启了半同步复制模式
| rpl_semi_sync_slave_trace_level | 32 |
+------------------------------------+-------+
6 rows in set (0.00 sec)
3. 半同步与异步的切换
执行完上面的步骤后,我们在M/S上检查半同步的状态,发现rpl_semi_sync_slave_status都是关闭的。这说明虽然启用了半同步的功能,但slave不会自动从异步模式转换到半同步模式。
mysql> show status like "%semi%";
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 1 | --有多少slave配置成了semi-sync模式
| Rpl_semi_sync_master_net_avg_wait_time | 677 | --等待slave确认的平均等待时间,单位微秒。
| Rpl_semi_sync_master_net_wait_time | 3385 | --master的总等待时间,单位微秒
| Rpl_semi_sync_master_net_waits | 5 | --等待slave确认的的总的等待次数
| Rpl_semi_sync_master_no_times | 0 | --关闭半同步复制的次数
| Rpl_semi_sync_master_no_tx | 0 | --slave确认的不成功提交次数
| Rpl_semi_sync_master_status | ON | --master现在是否是半同步复制状态
| Rpl_semi_sync_master_timefunc_failures | 0 | --半同步所用的时间函数失败的次数
| Rpl_semi_sync_master_tx_avg_wait_time | 776 | --事务等待slave确认的平均等待时间,单位微秒
| Rpl_semi_sync_master_tx_wait_time | 3881 | --事物等待slave确认的总等待时间,单位微秒
| Rpl_semi_sync_master_tx_waits | 5 | --等待slave确认的的总的等待次数
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 | --改变当前等待最小二进制日志的次数
| Rpl_semi_sync_master_wait_sessions | 0 | --当前有多少个session 因为slave 的回复而造成等待
| Rpl_semi_sync_master_yes_tx | 5 | --slave确认的成功提交次数
| Rpl_semi_sync_slave_status | OFF | --该server的slave是否处于半同步状态
+--------------------------------------------+-------+
通过上面的参数也说明了开启半同步会导致一部分额外的开销:
(1). 完成单条事务增加了额外的等待延迟,延迟的大小取决于网络的好坏。
(2). Semi-sync不是分布式事务,主库会在自己完成事务后,等待备库接收事务日志。
接下来重新启动slave。
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
mysql> start slave ;
Query OK, 0 rows affected (0.03 sec)
这是Master和Slave中的日志中会提示:
--- master ---
2014-08-14 14:26:10 5927 [Note] Start semi-sync binlog_dump to slave (server_id: 2), pos(mysql-bin.000009, 1507)
--- slave ---
2014-08-14 14:26:09 5969 [Note] Slave I/O thread: Start semi-sync replication to master 'rep@172.19.17.210:3306' in log 'mysql-bin.000009' at position 1507
再次检查slave的状态:
mysql> show status like "%semi%";
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_status | ON |
......
| Rpl_semi_sync_slave_status | ON |
+--------------------------------------------+-------+
15 rows in set (0.01 sec)
一般情况下,当slave的io线程将binlog接受完毕后,要给master发送一个确认。如果超过rpl_semi_sync_master_timeout=10000(10秒)内未收到该确认信号,那么就自动转换为异步复制模式。这种情况下要排查错误并重启slave来恢复半同步模式。
--转自