您好,登錄后才能下訂單哦!
沃趣科技 彭許生
前段時間支持客戶處理問題的時候,發現一個semi-sync復制主從切換原master加入集群時,復制同步阻塞,無法繼續同步數據的問題,非常有參考意義,整理一下,供大家參考。
客戶在一個一主兩從的半同步復制環境下做了手工切換,然后嘗試把原主庫加入集群中,結果發現新集群中的數據一直無法同步到slave(原主庫)中來,查看slave(原主庫)同步狀態,IO線程和SQL線程都是YES狀態,但是Seconds_Behind_Master大于0.
- mysql> show slave status\G
- *************************** 1. row ***************************
- Slave_IO_State: Waiting for master to send event
- ..............................................
- 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: Waiting for semi-sync ACK from slave
- 1 row in set (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 | Waiting for master to send event | NULL |
- | 4 | root | localhost | test | Query | 0 | starting | show processlist |
- +----+-------------+-----------+------+---------+------+--------------------------------------+------------------+
- 3 rows in set (0.00 sec)
從SQL線程等待的的半同步問題出發,先查看semi-sync狀態和設置
- mysql> show global 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 rows in set (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> show global 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 rows in set (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> set global rpl_semi_sync_master_enabled=ON;
在slave端安裝semisync_slave.so庫并配置my.cnf
- mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
- mysql> set global rpl_semi_sync_slave_enabled=ON;
- mysql> show global status like 'rpl_semi_sync_master_status';
- +-----------------------------+-------+
- | Variable_name | Value |
- +-----------------------------+-------+
- | Rpl_semi_sync_master_status | ON |
- +-----------------------------+-------+
- mysql> show global 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。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。