centos7下mysql半同步複製原理安裝測試詳解

原理簡介前端

在MySQL5.5以前,MySQL的複製其實都是異步複製(見下圖),主庫和從庫的數據之間存在必定的延遲,這樣存在一個隱患:當在主庫上寫入一個事務並提交成功,而從庫還沒有獲得主庫推送的BinLog日誌時,剛好主庫宕機了,例如主庫可能因磁盤損壞、內存故障等形成主庫上該事務Binlog丟失,此時從庫就可能損失這個事務,從而形成主從不一致。mysql

        

  

爲了解決這個問題,從MySQL5.5開始引入了半同步複製機制(Semi_synchronous Replication)。爲了保證主庫上的每個Binlog事務都可以被可靠的複製到從庫上,主庫在每次事務成功提交時,並不及時反饋給前端用戶,而是等待其中一個從庫也接受到Binlog事務併成功寫入中繼日誌後,主庫才返回Commit操做成功給客戶端。半同步複製保證了事務成功提交後,至少有兩份日誌記錄,一份在主庫的Binlog日誌上,另外一份在至少一個從庫的中繼日誌Relay Log上,從而更進一步保證了數據的完整性。半同步複製的大體流程以下圖:sql

    

半同步複製模式下,假如在上圖步驟①②③中任何一個步驟中主庫宕機,則事務並未提交成功,從庫上也沒收到事務對應的Binlog日誌,因此主從數據是一致的;假如在步驟④傳送Binlog日誌到從庫時,從庫宕機或者網絡故障,致使Binlog並無及時地傳送到從庫上,此時主庫上的事務會等待一段時間(時間長短由參數rpl_semi_sync_master_timeout設置的毫秒數決定),若是Binlog在這段時間內都沒法成功推送到從庫上,則MySQL自動調整複製爲異步複製,事務正常返回提交結果給客戶端。服務器

半同步複製很大程度上取決於主從庫之間的網絡狀況,往返時延RTT(Round-Trip Time)越小決定了從庫的實時性越好。通俗地說,主從庫之間的網絡越快,從庫越實時。網絡

 

測試環境session

 

安裝步驟異步

半同步複製是以插件形式來實現的,安裝比較簡單,在異步複製的環境上(這裏已經安裝好傳統的異步複製),安裝半同步插件便可,也可在新建時寫入my.cnf,參考文章尾部;測試

1. 查看MySQL服務器是否支持動態增長插件spa

mysql> select @@have_dynamic_loading; +------------------------+
| @@have_dynamic_loading |
+------------------------+
| YES                    |  //YES表示支持
+------------------------+
1 row in set (0.00 sec)

2. 確認支持動態插件後,檢查安裝目錄是否存在所需插件,通常在mysql安裝目錄中的一個.../plugin/目錄下,能夠搜索一下:插件

[root@server-10 ~]# find / -name semisync_*.so /usr/lib64/mysql/plugin/debug/semisync_master.so /usr/lib64/mysql/plugin/debug/semisync_slave.so /usr/lib64/mysql/plugin/semisync_master.so /usr/lib64/mysql/plugin/semisync_slave.so

3. 在主庫上安裝插件semisync_master.so

mysql> install plugin rpl_semi_sync_master SONAME 'semisync_master.so'; Query OK, 0 rows affected (0.03 sec)

4. 在從庫上安裝插件semisync_master.so

mysql> install plugin rpl_semi_sync_slave SONAME 'semisync_slave.so'; Query OK, 0 rows affected (0.00 sec)

插件安裝完成後,從plugin表中可以看到剛纔安裝的插件(這裏在主庫上查看一下):

mysql> select * from mysql.plugin; +----------------------+--------------------+
| name                 | dl                 |
+----------------------+--------------------+
| rpl_semi_sync_master | semisync_master.so |
+----------------------+--------------------+
1 row in set (0.00 sec)

也就是說,安裝完成後,MySQL會在系統表plugin中記錄剛纔安裝的插件,下次系統重啓後會自動加載插件。

5. 分別在主庫和從庫上配置參數打開半同步semi-sync,默認半同步設置是不打開的。

在主庫上配置全局參數:

mysql> show variables like 'rpl_semi_sync_master%'; +------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled       | OFF   |
| rpl_semi_sync_master_timeout       | 10000 |
| rpl_semi_sync_master_trace_level   | 32    |
| rpl_semi_sync_master_wait_no_slave | ON    |
+------------------------------------+-------+
4 rows in set (0.00 sec) mysql> set global rpl_semi_sync_master_enabled = 1; Query OK, 0 rows affected (0.00 sec) mysql> set global rpl_semi_sync_master_timeout = 20000; Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'rpl_semi_sync_master%'; +------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled       | ON    |
| rpl_semi_sync_master_timeout       | 20000 |
| rpl_semi_sync_master_trace_level   | 32    |
| rpl_semi_sync_master_wait_no_slave | ON    |
+------------------------------------+-------+
4 rows in set (0.00 sec)

在從庫上配置參數:

mysql> set global rpl_semi_sync_slave_enabled = 1; Query OK, 0 rows affected (0.00 sec)

6. 因爲以前配置的是傳統的異步複製,因此須要重啓一下從庫上的I/O線程(若是是全新配置的半同步複製則不須要,後面會提到全新配置):

mysql> stop slave io_thread; Query OK, 0 rows affected (0.05 sec) mysql> start slave io_thread; Query OK, 0 rows affected (0.00 sec)

到此,半同步複製配置完成,下面能夠來驗證一下。

 

實際測試

1. 先查看當前主庫上半同步複製的一些狀態值:

mysql> show status like 'Rpl_semi_sync%'; +--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |
| 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)

注意環境不同,可能顯示也不同,着重關注如下3個狀態值的變化,而不是上面這些初始值

Rpl_semi_sync_master_status :值爲ON,表示半同步複製目前處於打開狀態。

Rpl_semi_sync_master_yes_tx:值爲0,表示主庫當前還沒有有任何一個事務是經過半同步複製到從庫。

Rpl_semi_sync_master_no_tx:值爲0,表示當前有0個事務不是半同步模式下從庫及時響應的。

在主庫上執行一個事務,而後再檢查一下狀態:

mysql> use mydb; Database changed mysql> show tables; Empty set (0.00 sec) mysql> CREATE TABLE customers -> ( ->   cust_id      int NOT NULL AUTO_INCREMENT, ->   cust_name    char(50) NOT NULL , ->   cust_address char(50) NULL , ->   cust_city    char(50) NULL , ->   cust_state   char(5) NULL , ->   cust_zip     char(10) NULL , ->   cust_country char(50) NULL , ->   cust_contact char(50) NULL , ->   cust_email   char(255) NULL , -> PRIMARY KEY (cust_id) -> ) ENGINE=InnoDB; Query OK, 0 rows affected (0.10 sec) mysql> show tables; +----------------+
| Tables_in_mydb |
+----------------+
| customers      |
+----------------+
1 row in set (0.00 sec) mysql> show status like 'Rpl_semi_sync%'; +--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |
| Rpl_semi_sync_master_net_avg_wait_time     | 316   |
| Rpl_semi_sync_master_net_wait_time         | 316   |
| Rpl_semi_sync_master_net_waits             | 1     |
| 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      | 488   |
| Rpl_semi_sync_master_tx_wait_time          | 488   |
| 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)

此時會發現Rpl_semi_sync_master_yes_tx的值變爲1,即剛纔的CREATE事務經過半同步複製到從庫上了,Rpl_semi_sync_master_yes_tx計數增長1。

到從庫確認一下,新建的customers表確實被複制過去了:

 

2. 接下來模仿網絡異常的場景下,主庫在等待 rpl_semi_sync_master_timeout毫秒超時後,自動轉成異步複製的場景。

在主庫上確認半同步複製會等待20s超時:

mysql> show variables like 'rpl_semi_sync_master_timeout'; +------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| rpl_semi_sync_master_timeout | 20000 |    //單位:ms
+------------------------------+-------+
1 row in set (0.00 sec)

從庫上經過iptables命令模擬從庫宕機或者網絡故障:

[root@server-11 ~]# iptables -A INPUT -s 138.138.82.10 -j DROP

在主庫上執行一個事務並提交(默認提交便可),主庫上的提交操做會被阻塞20秒

mysql> INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) -> VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com'); Query OK, 1 row affected (20.05 sec)   //回車後,會卡主(阻塞)20秒,而後纔會跳出Query OK...這行,並顯示用時20秒

在這個20秒阻塞過程當中,新開一個窗口檢查當前主庫的線程,會發現提交操做在等待從庫上半同步複製操做的響應:

mysql> show processlist\G
......
*************************** 3. row *************************** Id: 12 User: root Host: localhost db: mydb Command: Query Time: 3 State: Waiting for semi-sync ACK from slave    //阻塞,等待從庫確認 Info: INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_countr 3 rows in set (0.00 sec)

阻塞結束後,再次查看半同步複製的一些狀態值:

mysql> show status like 'Rpl_semi_sync%'; +--------------------------------------------+----------+
| Variable_name                              | Value    |
+--------------------------------------------+----------+
| Rpl_semi_sync_master_clients               | 1        |
| Rpl_semi_sync_master_net_avg_wait_time     | 15011119 |
| Rpl_semi_sync_master_net_wait_time         | 30022238 |
| Rpl_semi_sync_master_net_waits             | 2        |
| Rpl_semi_sync_master_no_times              | 1        |
| Rpl_semi_sync_master_no_tx                 | 1        |//該值更新爲1,表示在半同步複製模式下,從庫沒有及時響應的事務增長1個
| Rpl_semi_sync_master_status                | OFF      |//表示主庫上半同步複製已經關閉了
| Rpl_semi_sync_master_timefunc_failures     | 0        |
| Rpl_semi_sync_master_tx_avg_wait_time      | 488      |
| Rpl_semi_sync_master_tx_wait_time          | 488      |
| 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        |//該值仍然爲1,表示剛纔的事務並非經過半同步複製完成的,因此半同步成功事務仍然爲1個
+--------------------------------------------+----------+
14 rows in set (0.00 sec)

繼續測試:若是從庫正常鏈接上主庫以後,主庫是否會自動切換回半同步複製模式呢?

那麼把以前從庫上面的iptables限制條目去除:

[root@server-11 ~]# iptables -F [root@server-11 ~]# iptables -nL   //查看一下確實沒了 Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination 

而後在從庫上查看slave狀態:

mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 138.138.82.10 Master_User: repl_user Master_Port: 3306 Connect_Retry: 60 Master_Log_File: master-bin.000010 Read_Master_Log_Pos: 988 Relay_Log_File: relay-bin.000016 Relay_Log_Pos: 704 Relay_Master_Log_File: master-bin.000010 Slave_IO_Running: Yes    Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 988 Relay_Log_Space: 5483 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 10 Master_UUID: 8086bac0-a428-11e8-8bf9-00505691656b Master_Info_File: /var/lib/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0
1 row in set (0.00 sec) mysql> select * from customers;   //以前在主庫插入時阻塞20.05秒的條目也複製過來了 +---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+
| cust_id | cust_name   | cust_address   | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email      |
+---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+
|   10001 | Coyote Inc. | 200 Maple Lane | Detroit   | MI         | 44444    | USA          | Y Lee        | ylee@coyote.com |
+---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+
1 row in set (0.00 sec)

以上顯示說明在網絡狀態恢復後(去掉iptables),從庫會自動嘗試鏈接主庫,幾秒鐘後I/O線程狀態從Connecting變成了YES,而且主庫和從庫的數據一致了。

再次查看主庫上半同步複製的狀態值

mysql> show status like 'Rpl_semi_sync%'; +--------------------------------------------+----------+
| Variable_name                              | Value    |
+--------------------------------------------+----------+
| Rpl_semi_sync_master_clients               | 1        |
| Rpl_semi_sync_master_net_avg_wait_time     | 10033583 |
| Rpl_semi_sync_master_net_wait_time         | 30100750 |
| Rpl_semi_sync_master_net_waits             | 3        |
| Rpl_semi_sync_master_no_times              | 1        |
| Rpl_semi_sync_master_no_tx                 | 1        |
| Rpl_semi_sync_master_status                | ON       |
| Rpl_semi_sync_master_timefunc_failures     | 0        |
| Rpl_semi_sync_master_tx_avg_wait_time      | 488      |
| Rpl_semi_sync_master_tx_wait_time          | 488      |
| 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)

以上發現Rpl_semi_sync_master_status的值自動從OFF變成ON,說明在檢測到從庫正常以後,主庫到從庫的複製方式會自動切換爲半同步複製模式。

咱們繼續主庫上作一個INSERT事務測試,確認當前的複製模式確實是半同步複製:

mysql> INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact) -> VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse'); Query OK, 1 row affected (0.07 sec) mysql> show status like 'Rpl_semi_sync%'; +--------------------------------------------+----------+
| Variable_name                              | Value    |
+--------------------------------------------+----------+
| Rpl_semi_sync_master_clients               | 1        |
| Rpl_semi_sync_master_net_avg_wait_time     | 7525296  |
| Rpl_semi_sync_master_net_wait_time         | 30101185 |
| Rpl_semi_sync_master_net_waits             | 4        |
| Rpl_semi_sync_master_no_times              | 1        |
| Rpl_semi_sync_master_no_tx                 | 1        |
| Rpl_semi_sync_master_status                | ON       |
| Rpl_semi_sync_master_timefunc_failures     | 0        |
| Rpl_semi_sync_master_tx_avg_wait_time      | 517      |
| Rpl_semi_sync_master_tx_wait_time          | 1034     |
| Rpl_semi_sync_master_tx_waits              | 2        |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0        |
| Rpl_semi_sync_master_wait_sessions         | 0        |
| Rpl_semi_sync_master_yes_tx                | 2        |  //計數增長了1個,變爲2
+--------------------------------------------+----------+
14 rows in set (0.00 sec)

能夠看出,以上的一個INSERT事務提交後,Rpl_semi_sync_master_yes_tx 值從1變成2,確認了剛纔事務的複製事半同步複製。

測試結束;

小結

從半同步複製的流程會發現,半同步複製的「半」就體如今:雖然主庫和從庫的Binlog日誌時同步的,可是主庫並不等待從庫應用這部分日誌就返回提交結果,這部分操做是異步的,從庫的數據並非和主庫實時同步的,因此只能成爲半同步,而不是徹底的實時同步。

 

補充

經過配置文件添加半同步插件和參數,操做以下:

在/etc/my.cnf中添加如下參數

plugin_load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_slave_enabled = 1
rpl_semi_sync_master_timeout = 20000

 

結束.

相關文章
相關標籤/搜索