1. 程式人生 > >MySQL半同步複製

MySQL半同步複製

MySQL資料庫複製的預設方式是非同步複製,但是非同步複製的不足之處就在於,當主庫把event寫入二進位制日誌之後,並不知道從庫是否已經接收並應用了。在非同步模式的複製,如果主庫崩潰,很有可能在主庫中已經提交的事務,並沒有傳到到任何一臺從庫機器上。在高可用叢集架構下做主備切換,就會造成新的主庫丟失資料的現象。

MySQL5.5版本之後引入了半同步複製功能,主從伺服器必須同時安裝半同步複製外掛,才能開啟該複製功能。在該功能下,確保從庫接收完主庫傳遞過來的binlog內容已經寫入到自己的relay log裡,才會通知主庫上的等待執行緒,該操作完畢。如果等待超時,超過repl_semi_sync_master_timeout引數設定的時間,則關閉半同步複製,並自動轉換為非同步複製

模式,直到至少有一臺從庫通知主庫已經接收到binlog資訊為止。

半同步複製提升了主從之間資料的一致性,讓複製更加安全可靠。在MySQL5.7.2版本中增加了rpl_semi_sync_master_wait_point引數,用來控制半同步模式下主庫返回給session事務成功之前的事務提交方式。

該引數有兩個值:

  • AFTER_COMMIT(MySQL5.6預設值) 主庫將每個事務寫入binlog,並傳遞給從庫,重新整理到中繼日誌中,同時主庫提交事務,之後主庫開始等待從庫的反饋,只有收到從庫的回覆之後,master才將commit OK的結果反饋給客戶端。

  • AFTER_SYNC(MySQL5.7預設值)

    主庫將每個事務寫入binlog,並傳遞給從庫,重新整理到中繼日誌中,主庫開始等待從庫的反饋,接收到從庫的回覆之後,再提交事務並且返回commit OK結果給客戶端。

可以通過repl_semi_sync_master_wait_for_slave_count引數來控制主庫接收多少個從庫寫事務成功反饋,才返回成功給客戶端。生產環境中使用半同步複製方式,當從庫出現故障,等待超時的時間又很長,導致主庫無法接收從庫資訊而無法正常寫入時,可通過該引數剔除故障從庫。

在AFTER_SYNC模式下,即使主庫宕機,所有在主庫上已經提交的事務都能保證已經同步到從庫的中繼日誌中,不會丟失任何資料。

1. 半同步複製安裝與配置

半同步複製的安裝非常簡單,它基於非同步複製的基礎上,安裝半同步複製外掛。

1.1 安裝半同步複製外掛

在master上:


mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME          | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE        |
+----------------------+---------------+
       

在slave上


mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME LIKE '%semi%';
+---------------------+---------------+
| PLUGIN_NAME         | PLUGIN_STATUS |
+---------------------+---------------+
| rpl_semi_sync_slave | ACTIVE        |
+---------------------+---------------+

1.2 配置半同步複製

安裝了半同步複製外掛後,預設情況下會禁用它。必須在master和slave上都啟用外掛才能啟用半同步複製。如果僅啟用一側,則複製將是非同步的。

要控制是否已啟用已安裝的外掛,請設定相應的系統變數。可以在執行時使用SET GLOBAL或`在命令列選項(my.cnf)檔案中的伺服器啟動時設定這些變數。

在複製執行時,master可用的系統變數


SET GLOBAL rpl_semi_sync_master_enabled = {0|1};
SET GLOBAL rpl_semi_sync_master_timeout = N;

在複製執行時,slave可用的系統變數


SET GLOBAL rpl_semi_sync_slave_enabled = {0|1};

對於 rpl_semi_sync_master_enabledrpl_semi_sync_slave_enabled,該值應為1以啟用半同步複製,或者為0以禁用它。預設情況下,這些變數設定為0。

對於 rpl_semi_sync_master_timeout,值N以毫秒為單位。預設值為10000(10秒)。

啟用半同步複製,需要重啟從庫的I/O執行緒


STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

操作如下:

#master上
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
mysql> SET GLOBAL rpl_semi_sync_master_timeout = 60000;#該引數預設值是10s,應儘量調整大點,減小向非同步複製切換以保證資料複製的安全性。
 #要在伺服器啟動時,啟動半同步複製,可以在my.cnf檔案新增如下
[mysqld]
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=60000 # 60 second

#slave上
mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
mysql> STOP SLAVE IO_THREAD;
mysql> START SLAVE IO_THREAD;
 #要在伺服器啟動時,啟動半同步複製,可以在my.cnf檔案新增如下
[mysqld]
rpl_semi_sync_slave_enabled=1

2. 監控半同步

半同步複製功能的外掛公開了幾個系統和狀態變數,可以檢查這些變數以確定其配置和執行狀態。

系統變數反映瞭如何配置半同步複製。要檢查其值,請使用SHOW VARIABLES

#master 
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 60000      |
| 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 |
+-------------------------------------------+------------+
6 rows in set (0.00 sec)

#slave
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | ON    |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
2 rows in set (0.00 sec)

狀態變數可以監視半同步複製的操作。要檢查其值,請使用SHOW STATUS

#master
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)

#slave
mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

在master端:

Rpl_semi_sync_master_status:此狀態變數用來確定主伺服器當前是使用非同步還是半同步複製

Rpl_semi_sync_master_clients:檢視連線了多少個半同步slave

Rpl_semi_sync_master_no_tx:代表沒有成功接收slave事務提交回復的次數

Rpl_semi_sync_master_yes_tx:代表成功接收slave事務提交回復的次數

Rpl_semi_sync_master_net_avg_wait_time:主機等待slave回覆的平均時間(以微秒為單位)。此變數已棄用,始終為0,將在以後的版本中刪除。 Rpl_semi_sync_master_net_wait_time:主機等待slave回覆的總時間(以微秒為單位)。此變數已棄用,始終為0,將在以後的版本中刪除。 Rpl_semi_sync_master_net_waits:master等待slave回覆的總次數。 Rpl_semi_sync_master_no_times:主伺服器關閉半同步複製的次數。 Rpl_semi_sync_master_timefunc_failures:呼叫gettimeofday()等時間函式時主伺服器失敗的次數。 Rpl_semi_sync_master_tx_avg_wait_time:master等待每個事務的平均時間(以微秒為單位)。 Rpl_semi_sync_master_tx_wait_time:master等待事務的總時間(以微秒為單位)。 Rpl_semi_sync_master_tx_waits:主伺服器等待事務的總次數。 Rpl_semi_sync_master_wait_pos_backtraverse:master等待二進位制座標低於先前等待事件的事件的總次數。當事務開始等待回覆的順序與其二進位制日誌事件的寫入順序不同時,就會發生這種情況。 Rpl_semi_sync_master_wait_sessions:當前正在等待slave回覆的會話數。

在slave端:

Rpl_semi_sync_slave_status:指示半同步複製當前是否可操作。

3. 半同步複製和非同步複製模式的切換

半同步複製的原理是從庫的I/O thread接收完主庫的binlog,並把它寫入relay中後,會給主庫一個回饋。但如果主庫等待從庫的回饋時間超過repl_semi_sync_master_timeout引數設定的時間,會自動切換為非同步複製方式。

下面就利用rpl_semi_sync_master_timeout超時設定,測試半同步複製與非同步複製的切換。

#1. 檢視主庫rpl_semi_sync_master_timeout設定時間

root@localhost [(none)] 15:45:06> show variables like '%rpl_semi_sync_master_tim%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| rpl_semi_sync_master_timeout | 60000 |
+------------------------------+-------+
1 row in set (0.00 sec)

#2. 從庫關掉I/O thread執行緒
root@localhost [(none)] 15:02:14>stop slave io_thread;

#3.  檢視從庫的半同步狀態,為OFF
root@localhost [(none)] 15:46:49>show global status like '%semi%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | OFF   |
+----------------------------+-------+
1 row in set (0.00 sec)

#4. 檢視主庫的半同步複製狀態
root@localhost [(none)] 15:58:03> show global status like '%semi%';
+--------------------------------------------+-------+
| 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)

#主庫第一次插入耗時60s
root@localhost [test] 15:59:05> insert into z1 values(4,'python');
Query OK, 1 row affected (1 min 0.01 sec)

#主庫第二次插入耗時0.01s
root@localhost [test] 16:00:25> insert into z1 values(5,'php');
Query OK, 1 row affected (0.01 sec)

# 主庫檢視半同步狀態
root@localhost [test] 16:07:04> show global status like '%semi%';
+--------------------------------------------+-------+
| 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             | 2     |
| Rpl_semi_sync_master_no_times              | 2     |
| Rpl_semi_sync_master_no_tx                 | 3     |
| Rpl_semi_sync_master_status                | OFF   |
| 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)


【說明】
第一次插入時,主庫一直在等待從庫的回覆(60s),直到超過60s,主庫再進行提交,且轉換為非同步複製。
第二次插入時,主從庫已為非同步複製,所以插入無需等待從庫的反饋。