十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
沃趣科技 彭许生
创新互联是一家专业提供甘南企业网站建设,专注与成都网站设计、网站建设、外贸网站建设、H5页面制作、小程序制作等业务。10年已为甘南众多企业、政府机构等服务。创新互联专业的建站公司优惠进行中。
前段时间支持客户处理问题的时候,发现一个semi-sync复制主从切换原master加入集群时,复制同步阻塞,无法继续同步数据的问题,非常有参考意义,整理一下,供大家参考。
客户在一个一主两从的半同步复制环境下做了手工切换,然后尝试把原主库加入集群中,结果发现新集群中的数据一直无法同步到slave(原主库)中来,查看slave(原主库)同步状态,IO线程和SQL线程都是YES状态,但是Seconds_Behind_Master大于0.
- MySQL> show slave status\G
- ***************************1. row***************************
- Slave_IO_State:Waitingfor master to sendevent
- ..............................................
- Master_Log_File: mysql-bin.000007
- Read_Master_Log_Pos:540
- Relay_Log_File: mysql-relay-bin.000006
- Relay_Log_Pos:367
- Relay_Master_Log_File: mysql-bin.000007
- ..............................................
- Slave_SQL_Running_State:Waitingfor semi-sync ACKfrom slave
- 1 rowinset(0.00 sec)
查看show processlist状态, 发现SQL线程一直处于Waiting for semi-sync ACK from slave状态,可是这个slave(原主库)下已经没有从库了。为什么还需要等待slave返回的ACK呢?
- mysql> show processlist;
- +----+-------------+-----------+------+---------+------+--------------------------------------+------------------+
- |Id|User|Host| db|Command|Time|State|Info|
- +----+-------------+-----------+------+---------+------+--------------------------------------+------------------+
- |1| system user|| NULL|Connect|540|| NULL|
- |2| system user|| NULL|Connect|2191|Waitingfor master to sendevent| NULL|
- |4| root| localhost| test|Query|0| starting| show processlist|
- +----+-------------+-----------+------+---------+------+--------------------------------------+------------------+
- 3 rowsinset(0.00 sec)
从SQL线程等待的的半同步问题出发,先查看semi-sync状态和设置
- mysql> showglobal 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_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|
- |
- +--------------------------------------------+-------+
- 15 rowsinset(0.00 sec)
通过上面semi-sync的状态变量,可以发现semi-sync运行状态Rpl_semi_sync_master_status=ON、Rpl_semi_sync_slave_status=ON。这里最奇怪的是Rpl_semi_sync_master_status=ON。
根据半同步复制原理:主库发生数据变更写binlog,然后等待从库接收并返回ACK,最后在存储引擎层提交数据。这也就是为什么在从库(原主库)一直查不到新主库变更后的数据原因。在默认情况下,半同步复制只有在等待ACK超出 rpl_semi_sync_master_timeout设置的时间才会自动降为异步复制。
这里slave(原主库)被认为是半同步的master,但是没有从库连接他,所以一直在等待从库返回的ACK。等待的时间我们查看rpl_semi_sync_master_timeout变量取值
- mysql> showglobal variables like'rpl_semi_sync%';
- +-------------------------------------------+------------+
- |Variable_name|Value|
- +-------------------------------------------+------------+
- |
- |
- | 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|
- | | rpl_semi_sync_slave_trace_level|32|
- +-------------------------------------------+------------+
- 8 rowsinset(0.00 sec)
查看semi-sync参数发现从库同时开启了rpl_semi_sync_master_enabled=ON、rpl_semi_sync_slave_enabled=ON和rpl_semi_sync_master_timeout=10000000(1万秒,默认10秒)。
客户竟然把rpl_semi_sync_master_timeout设置为10万秒,也就是说,原主库要等待10万秒才能自动变为异步并加入集群中同步数据,slave(原主库)无法从集群中继续同步数据的根本原因就在这里。
跟客户沟通后,客户之所以将rpl_semi_sync_master_timeout设置这么大的值,是强调数据强一致性,不希望在任何情况下半同步复制结构降为异步复制,最大限度保证数据一致性。
前面涉及到几个sc 复制参数,可能有些同学不太了解,下面给大家简单讲解一下MySQL semi-sync 复制安装配置和原理。
在MySQL 5.7版本里如果要开启半同步复制,需要在master端安装semisync_master.so库并配置my.cnf
- mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME'semisync_master.so';
- mysql>setglobal rpl_semi_sync_master_enabled=ON;
在slave端安装semisync_slave.so库并配置my.cnf
- mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME'semisync_slave.so';
- mysql>setglobal rpl_semi_sync_slave_enabled=ON;
- mysql> showglobal status like'rpl_semi_sync_master_status';
- +-----------------------------+-------+
- |Variable_name|Value|
- +-----------------------------+-------+
- |Rpl_semi_sync_master_status| ON|
- +-----------------------------+-------+
- mysql> showglobal status like'rpl_semi_sync_slave_status';
- +-----------------------------+-------+
- |Variable_name|Value|
- +-----------------------------+-------+
- |Rpl_semi_sync_slave_status| ON|
- +-----------------------------+-------+
进入半同步复制,客户端在master每提交一个事务,master MySQL将对应事务写入binlog,然后等待slave返回的ACK,之后在存储引擎层提交,最后返回给客户端写入成功的消息。
如果slave没有返回,master将等待指定超时时间;超过超时时间后,会自动降为异步复制模式。
上述master等待行为都发生在rpl_semi_sync_master_wait_no_slave=ON(默认值)情况下。如果rpl_semi_sync_master_wait_no_slave设置为OFF时,连接master的slave的数量少于rpl_semi_sync_master_wait_for_slave_count设置的值,master不会等待超时,立刻自动降为异步复制模式。
如果把rpl_semi_sync_master_timeout设置非常大,在主从切换时导致原主库加入集群时同步阻塞,建议把rpl_semi_sync_master_wait_no_slave=OFF。