MySQL半同步使用注意事項

賀子_DBA時代發表於2022-07-07
最近遇到了一個關於半同步的問題,剛搭建的半同步資料庫例項,執行第一個sql的時候,從庫延遲太長,原因是從庫開啟了引數
rpl_semi_sync_master_enabled=on,同時設定的rpl_semi_sync_master_timeout為30分鐘,接下來說下半同步使用注意事項以及該問題的具體原因,

一、開啟半同步:必須主從庫都得設定對應的引數!具體如下所示:
主庫:
set global rpl_semi_sync_master_enabled = 1;
從庫
set global rpl_semi_sync_slave_enabled = 1;
注意如果從庫沒設定這個rpl_semi_sync_slave_enabled引數,那麼主庫就不識別這個從庫,但是主庫還是增強半同步的方式,此時主庫就會由於沒有slave返回ack而夯住了,可以透過在master檢視下面這個狀態變數來了解此時有多少從庫可以反饋ack!
如下所示的主庫狀態變數表示當前有多少個從庫是處於半同步複製的方式來連線主庫的,或者說當前有多少slave可以給主庫反饋ack;
mysql> show  status  like   'Rpl_semi_sync_master_clients';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| Rpl_semi_sync_master_clients | 0     |
+------------------------------+-------+
1 row in set (0.00 sec)
二、從庫建議不開啟master角色的增強半同步引數,但是需要開啟slave角色的半同步引數;如果非要開啟rpl_semi_sync_master_enabled需要在slave修改引數rpl_semi_sync_master_wait_no_slave=off;
rpl_semi_sync_slave_enabled=on-----從庫需要開啟,否則該slave不能作為半同步反饋給master的ack;
rpl_semi_sync_master_enabled=off ----如果考慮到主從切換,可以開啟,但是slave第一次啟動的時候,會因為沒有slave反饋ack而處於夯住狀態,所以建議修改引數
rpl_semi_sync_master_wait_no_slave=off 這樣當發現她沒有足夠的slave的時候,立即退化為非同步複製!
三、介紹相關引數,併合理設定相關引數;建議在配置檔案中設定開頭帶loose開頭的引數,這樣如果你沒有安裝半同步外掛,它依舊能啟動資料庫!
#loose_rpl_semi_sync_master_enabled = 1
#loose_rpl_semi_sync_slave_enabled = 1
#loose_rpl_semi_sync_master_timeout = 1800000
rpl_semi_sync_master_enabled:主庫是否開啟半同步。 可以動態調整!立即生效;
rpl_semi_sync_master_wait_point:同步時間點after_commit,after_sync。可以動態調整!對於新事務有效!

rpl_semi_sync_master_wait_for_slave_count:主庫事務提交後需要從庫的確認數量。--可以動態調整!立即生效!

rpl_semi_sync_master_timeout:主庫等待從庫的確認超時時間(ms),預設10000ms(也就是10秒),等待超過則半同步降級為非同步模式。---可以動態調整!但是對於已經處於等待ack的事務無效!對修改後新的事務有效,並且當超時退化成半同步後,只要條件再次滿足半同步了,就自動切換回半同步了(例如某一刻你沒有了從庫,然後主庫由於超時退化成非同步複製,等你再次有了從庫後,自動切換回半同步)

rpl_semi_sync_master_wait_no_slave:----可以動態調整!立即生效!
為OFF時,只要主庫發現(Rpl_semi_sync_master_clients)小於(rpl_semi_sync_master_wait_for_slave_count),則半同步立即轉為非同步模式;

為ON時,在無事務提交的空閒時間裡,即使主庫發現(Rpl_semi_sync_master_clients)小於(rpl_semi_sync_master_wait_for_slave_count),也不會做任何調整;

只要保證在事務超時之前,主庫收到大於等於(rpl_semi_sync_master_wait_for_slave_count)值的ACK應答數量,主庫就一直保持在半同步模式,如果在事務提交階段(主庫等待ACK)超時,半同步才會轉為非同步模式;

無論(rpl_semi_sync_master_wait_no_slave)為ON還是OFF,當slave上線到(rpl_semi_sync_master_wait_for_slave_count)值時,master都會自動由非同步模式轉為半同步模式。
四、注意一個情景:重啟主庫但是不想讓他發生切換的時候需要注意,由於master停止,slave的IO執行緒都會斷開,然後預設過60秒去重新連線master;在這60秒內(引數master-connect-retry控制),如果master接收了事務,那麼此時master由於沒有從庫,就會導致master等待從庫ACK,此時master就會夯住,一直到有slave連線上了master,或者等待時間超過rpl_semi_sync_master_timeout時間!
如果你不想讓他等60秒自動恢復,解決辦法:
方法1、主庫執行關閉半同步的開關-----推薦該方法
mysql> set  global  rpl_semi_sync_master_enabled=off;
Query OK, 0 rows affected (0.00 sec)
方法2、主庫設定rpl_semi_sync_master_wait_no_slave=off;---這樣當master發現沒有足夠的從庫的時候,就自動退化成非同步複製---推薦使用
方法3、在從庫手動重啟slave的IO執行緒,手動讓slave重連主庫,而不是等60秒,這樣主庫就不會因為沒有從庫而夯住;
mysql> stop slave    io_thread;
mysql> start slave io_thread;
方法4、 停止業務,保證slave重連master的這段時間內主庫沒有接受任何操作;---不建議
五、主庫狀態變數Rpl_semi_sync_master_clients的意義;
1、首先需要源端開啟半同步,這個引數才會有;
This variable is available only if the source-side semisynchronous replication plugin is installed.
2、這個參數列示當前連線著的從庫的個數;但是這個狀態變數在增加slave的時候是實時更新的,但是減少了slave的個數的時候不是實時更新的;
3、這個引數給slave的引數rpl_semi_sync_slave_enabled有關(或者說是和slave的狀態變數Rpl_semi_sync_slave_status有關係),當slave的狀態變數Rpl_semi_sync_slave_status=on的時候主庫的Rpl_semi_sync_master_clients狀態變數才會加1;當Rpl_semi_sync_slave_status=off的從庫連線上主庫後,主庫的Rpl_semi_sync_master_clients狀態變數不會加1,
4、動態調整引數slave引數rpl_semi_sync_slave_enabled後,需要restart  slave io  thread才能讓slave的Rpl_semi_sync_slave_status動態變化,進而讓主庫Rpl_semi_sync_master_clients動態增減!
mysql> show  status   like   '%Rpl_semi_sync_slave_status%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

mysql> show  variables  like   '%Rpl%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 1800000    |
| 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_enabled               | OFF        |
| rpl_semi_sync_slave_trace_level           | 32         |
| rpl_stop_slave_timeout                    | 31536000   |
+-------------------------------------------+------------+
9 rows in set (0.00 sec)
案例1:證明該狀態變數的值給當前主庫連線的slave個數有關;
主庫檢視當前是2個從庫處於半同步複製中;
mysql> show status like '%Rpl_semi_sync_master_clients%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| Rpl_semi_sync_master_clients | 2     |
+------------------------------+-------+
從庫上執行stop  slave的操作;
然後再次去檢視主庫show status like '%Rpl_semi_sync_master_clients%';發現還是2;
等過了大概一分鐘後,變成了1;再次檢視發現變成了1;
mysql> show status like '%Rpl_semi_sync_master_clients%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| Rpl_semi_sync_master_clients | 1     |
+------------------------------+-------+
1 row in set (0.00 sec)
案例2;當時當你再次start slave後,會發現這個引數瞬間就變成了2;
案例3:證明該狀態變數的數值和他的從庫的Rpl_semi_sync_slave_status引數有關係;
當你把其中一個從庫Rpl_semi_sync_slave_status變為off後,再次去檢視主庫的Rpl_semi_sync_master_clients狀態變數,會發現此時主庫該狀態變數就減少了1;
mysql> show status like '%Rpl_semi_sync_slave_status%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | OFF   |
+----------------------------+-------+
1 row in set (0.00 sec)
再次檢視該狀態變數發現變成了1
mysql> show status like '%Rpl_semi_sync_master_clients%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| Rpl_semi_sync_master_clients | 1     |
+------------------------------+-------+
1 row in set (0.00 sec)
六、從庫狀態變數Rpl_semi_sync_slave_status和rpl_semi_sync_slave_enabled引數的關係!
1)當前以rpl_semi_sync_slave_enabled=on的方式啟動資料庫後,Rpl_semi_sync_slave_status狀態變數是on,然後動態調整rpl_semi_sync_slave_enabled=off,發現狀態變數依舊是Rpl_semi_sync_slave_status=on!
2)同樣rpl_semi_sync_slave_enabled=off的方式啟動資料庫後,Rpl_semi_sync_slave_status狀態變數是off,然後動態調整rpl_semi_sync_slave_enabled=on,發現狀態變數依舊是Rpl_semi_sync_slave_status=off!
3)除非你stop slave,然後start slave;然後狀態變數才會隨著rpl_semi_sync_slave_enabled引數動態調整而變化!準確的說是stop  slave  io_thread即可!注意單獨stop slave  sql_thread是不可以的!
最開始狀態:
mysql> show  variables  like   'rpl_semi_sync_master_enabled';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| rpl_semi_sync_master_enabled | ON    |
+------------------------------+-------+
1 row in set (0.00 sec)
mysql> show  status   like   '%Rpl_semi_sync_slave_status%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)
嘗試調整引數rpl_semi_sync_master_enabled
mysql> set global  rpl_semi_sync_slave_enabled=0;
Query OK, 0 rows affected (0.00 sec)
再次檢視發現狀態變數還是on,等了一個晚上也檢視也是on!
mysql> show  variables  like   'rpl_semi_sync_slave_enabled';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| rpl_semi_sync_slave_enabled | OFF   |
+-----------------------------+-------+
1 row in set (0.00 sec)
mysql> show  status   like   '%Rpl_semi_sync_slave_status%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)
執行stop slave,然後啟動slave,發現狀態變數變化了!
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show  status   like   '%Rpl_semi_sync_slave_status%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | OFF    |
+----------------------------+-------+
1 row in set (0.00 sec)
結論:Rpl_semi_sync_slave_status狀態變數只會在資料庫啟動的時候和rpl_semi_sync_slave_enabled引數保證一致!當你啟動資料庫後,動態調整引數rpl_semi_sync_slave_enabled後,需要restart slave io thread,Rpl_semi_sync_slave_status狀態變數才會變化!
六、主庫Rpl_semi_sync_master_status狀態變數和引數rpl_semi_sync_master_enabled的關係,Rpl_semi_sync_master_status隨著 rpl_semi_sync_master_enabled變化實時變化!區別於slave角色的引數rpl_semi_sync_slave_enabled和Rpl_semi_sync_slave_status狀態變數的關係!
mysql> show  status   like   '%Rpl_semi_sync_master_status%';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON   |
+-----------------------------+-------+
1 row in set (0.00 sec)
mysql> set  global  rpl_semi_sync_master_enabled=off;
Query OK, 0 rows affected (0.11 sec)
mysql> show  status   like   '%Rpl_semi_sync_master_status%';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | OFF   |
+-----------------------------+-------+
1 row in set (0.00 sec)
mysql> show  status   like   '%Rpl_semi_sync_master_status%';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | OFF   |
+-----------------------------+-------+
1 row in set (0.00 sec)
mysql> set  global  rpl_semi_sync_master_enabled=on;
Query OK, 0 rows affected (0.00 sec)
mysql> show  status   like   '%Rpl_semi_sync_master_status%';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON    |
+-----------------------------+-------+
1 row in set (0.01 sec)
五、特殊講解下引數:rpl_semi_sync_master_wait_no_slave

官方文件記錄:
rpl_semi_sync_master_wait_no_slave

Command-Line Format
--rpl-semi-sync-master-wait-no-slave[={OFF|ON}]
System Variable
Scope
Global
Dynamic
Yes
Type
Boolean
Default Value
ON

Controls whether the source waits for the timeout period configured by rpl_semi_sync_master_timeout to expire, even if the replica count drops to less than the number of replicas configured by rpl_semi_sync_master_wait_for_slave_count during the timeout period.

When the value of rpl_semi_sync_master_wait_no_slave is ON (the default), it is permissible for the replica count to drop to less than rpl_semi_sync_master_wait_for_slave_count during the timeout period. As long as enough replicas acknowledge the transaction before the timeout period expires, semisynchronous replication continues.

When the value of rpl_semi_sync_master_wait_no_slave is OFF, if the replica count drops to less than the number configured in rpl_semi_sync_master_wait_for_slave_count at any time during the timeout period configured by rpl_semi_sync_master_timeout, the source reverts to normal replication.

This variable is available only if the source-side semisynchronous replication plugin is installed.

當rpl_semi_sync_master_wait_no_slave=on的時候,如果master探測到沒有足夠的slave(rpl_semi_sync_master_wait_for_slave_count引數決定)可以反饋ack後,就自動退化成非同步複製,當再次有足夠個數的slave可以反饋ack後,master就自動又切換成了半同步!
當rpl_semi_sync_master_wait_no_slave=off的時候,如果沒有足夠的slave可以反饋ack, 進而master夯住一直等待rpl_semi_sync_master_timeout引數設定的時間後,退化成非同步複製;等再次有足夠的slave可以反饋ack了,master就不會自動切換成半同步!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29654823/viewspace-2904616/,如需轉載,請註明出處,否則將追究法律責任。

相關文章