MySQL主從複製複製預設是非同步的,非同步複製可以提供最佳的性能, 主庫把binlog日誌發送給從庫,然後將結果返回給客戶端,並不會驗證從庫是否接收完畢。這也就意味著有可能出現當主庫或從庫發生故障的時候,從庫沒有接收到主庫發送過來的binlog日誌,導致主庫和從庫的數據不一致,甚至在恢復時造成數據的丟... ...
一 、非同步、同步和半同步複製概念
非同步複製(Asynchronous replication),MySQL預設的複製是非同步的,主庫在執行完客戶端提交的事務後會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理。原理最簡單,性能最好,但是主從之間數據不一致的概率很大。
全同步複製(Fully synchronous replication),指當主庫執行完一個事務,所有的從庫都執行了該事務才返回給客戶端。因為需要等待所有從庫執行完該事務才能返回,所以全同步複製的性能必然會收到嚴重的影響。
半同步複製(Semisynchronous replication),介於非同步複製和全同步複製之間,主庫在執行完客戶端提交的事務後不是立刻返回給客戶端,而是等待至少一個從庫接收到並寫到relay log中才返回給客戶端。相對於非同步複製,半同步複製犧牲了一定的性能,提高了數據的安全性。
二、半同步複製原理
預設情況下,MySQL的主從複製是非同步的,非同步複製可以提供最佳的性能, 主庫把binlog日誌發送給從庫,然後將結果返回給客戶端,並不會驗證從庫是否接收完畢。這也就意味著有可能出現當主庫或從庫發生故障的時候,從庫沒有接收到主庫發送過來的binlog日誌,導致主庫和從庫的數據不一致,甚至在恢復時造成數據的丟失。
為瞭解決上述出現的問題,MySQL 5.5 引入了一種半同步複製模式。該模式可以確保從庫接收完主庫發送的binlog日誌文件並寫入到自己的中繼日誌relay log里,然後會給主庫一個反饋,告訴主庫已經接收完畢,這時主庫才返回結果給客戶端告知操作完成。當出現從庫響應超時情況時,主庫會暫時切換到非同步複製模式,直到下一次同步沒有超時轉為半同步複製為止。(master的dump線程除了發送binlog數據到slave,還承擔了接收slave的ack工作。如果出現異常,沒有收到ack,那麼將自動降為普通的非同步複製,直到異常修複)
三、半同步複製--MySQL5.7版
MySQL5.5半同步複製帶來的新問題:
1)如果有故障發生,會切換為非同步的複製。 那麼從庫出現數據不一致的幾率會減少,並不是完全消失。
2)主機dump線程承擔的工作變多了(發送binlog數據到slave,接收slave的ack。兩者是串列的,dump線程必須等待slave返回ack之後才會傳送下一個events事務。dump線程是整個半同步提高性能的瓶頸),這樣顯然會降低整個資料庫的性能。
3)在MySQL 5.5和5.6使用after_commit的模式下, 如果slave沒有收到事務,也就是還沒有寫入到relay log之前,網路出現異常或者不穩定,此時剛好master掛了,系統切換到從庫,兩邊的數據就會出現不一致,slave會少一個事務的數據。
在此情況下,MySQL5.7的半同步複製技術升級為全新的Loss-less Semi-Synchronous Replication架構,新版本的semi sync增加了rpl_semi_sync_master_wait_point參數, 來控制半同步模式下主庫在返回結果給會話之前提交事務的方式。
該參數有兩個值:
1)AFTER_COMMIT(5.5,5.6預設值)
master將每個事務寫入binlog之後,先提交事務,然後將binlog數據傳遞到slave並刷新到磁碟(relay log)。接著master等待slave反饋收到relay log,只有收到ack之後master才將commit OK結果反饋給客戶端。如圖一所示。
2)AFTER_SYNC(5.7預設值)
master將每個事務寫入binlog,然後將binlog數據傳遞到slave並刷新到磁碟(relay log)。master等待slave反饋接收到relay log的ack之後,再提交事務並且返回commit OK結果給客戶端。即使主庫crash了,所有在主庫上已經提交的事務都能保證已經同步到slave的relay log中。如圖二所示。
MySQL5.7的半同步複製引入after_sync模式,主要是解決了after_commit導致的主庫crash後主從之間數據不一致的問題。在引入after_sync模式後,所有提交的數據都已經被覆制,故障切換時數據一致性將得到提升。(另外,在5.7版本的semi sync框架中,獨立出一個ack collector thread,專門用於接收slave的反饋信息。這樣master上有兩個線程獨立工作,可以同時發送binlog到slave,和接收slave的反饋)
四、半同步複製的安裝
開啟半同步複製,必須是MySQL5.5以上版本並且已經搭建好普通的主從非同步複製。此處以MySQL5.5版本演示,如下所示:
1、安裝半同步插件
#半同步功能主要是下麵兩個插件 [root@master ~]# ls -l /application/mysql/lib/plugin/ ...... -rwxr-xr-x 1 mysql mysql 173396 Sep 15 2017 semisync_master.so -rwxr-xr-x 1 mysql mysql 94066 Sep 15 2017 semisync_slave.so #分別在主從庫載入上面兩個插件 master: mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so'; slave: mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so'; #查看插件是否載入成功,有兩種方法 1)mysql> show plugins; | rpl_semi_sync_master | ACTIVE | REPLICATION | semisync_master.so | GPL | 2)mysql> select plugin_name,plugin_status from information_schema.plugins where plugin_name like '%semi%'; +----------------------+---------------+ | plugin_name | plugin_status | +----------------------+---------------+ | rpl_semi_sync_master | ACTIVE | +----------------------+---------------+ 1 row in set (0.10 sec)
2、開啟半同步複製
在安裝完插件後,半同步複製預設是關閉的,這時需設置參數來開啟半同步。
mater: mysql> set global rpl_semi_sync_master_enabled = 1; slave: mysql> set global rpl_semi_sync_slave_enabled = 1;
#以上的啟動方式是在命令行操作,是臨時生效的;永久生效需將如下設置寫在配置文件中。 master: plugin-load = rpl_semi_sync_master=semisync_master.so #此項可以讓plugin在任何時候都被mysql載入 rpl_semi_sync_master_enabled = 1 slave: plugin-load = rpl_semi_sync_slave=semisync_slave.so rpl_semi_sync_slave_enabled = 1
#在有的高可用架構下,master和slave需同時啟動,以便在切換後能繼續使用半同步複製 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
3、重啟slave上的IO線程使半同步生效
mysql> stop slave io_thread; mysql> start slave io_thread; #如果沒有重啟,則預設還是非同步複製,重啟後,slave會在master上註冊為半同步複製的slave角色。 #查看半同步是否在運行 master: mysql> show status like 'Rpl_semi_sync_master_status'; +-----------------------------+-------+ | Variable_name | Value | +-----------------------------+-------+ | Rpl_semi_sync_master_status | ON | +-----------------------------+-------+ slave: mysql> show status like 'Rpl_semi_sync_slave_status'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Rpl_semi_sync_slave_status | ON | +----------------------------+-------+
4、半同步複製測試
master: mysql> create database db; mysql> use db Database changed mysql> create table t1(id int); mysql> insert into t1 values(1); mysql> select * from t1; +------+ | id | +------+ | 1 | +------+ 1 row in set (0.00 sec) slave: mysql> select * from db.t1; +------+ | id | +------+ | 1 | +------+ 1 row in set (0.00 sec) #可以看到數據很快同步到了從庫上,下麵關閉io_thread測試 slave: mysql> stop slave io_thread; Query OK, 0 rows affected (0.00 sec) master: mysql> insert into t1 values(2); #此處有一個10s的超時等待時間,超時後轉為非同步插入 Query OK, 1 row affected (10.11 sec) mysql> show status like 'Rpl_semi_sync_master_status'; #半同步已失效 +-----------------------------+-------+ | Variable_name | Value | +-----------------------------+-------+ | Rpl_semi_sync_master_status | OFF | +-----------------------------+-------+ slave: mysql> show status like 'Rpl_semi_sync_slave_status'; #從庫的半同步也失效 +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Rpl_semi_sync_slave_status | OFF | +----------------------------+-------+ 1 row in set (0.01 sec) slave: mysql> start slave io_thread; #從庫開啟io線程 Query OK, 0 rows affected (0.00 sec) master: 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) slave: mysql> select * from db.t1; #從庫上數據已同步 +------+ | id | +------+ | 1 | | 2 | +------+ 2 rows in set (0.00 sec)
5、其他說明
1)環境變數
mysql> show variables like '%semi%'; +------------------------------------+-------+ | Variable_name | Value | +------------------------------------+-------+ | rpl_semi_sync_master_enabled | ON | | 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)
rpl_semi_sync_master_enabled=ON 表示開啟半同步複製
rpl_semi_sync_master_timeout=10000 單位為毫秒,即10秒超時,將切換為非同步複製
rpl_semi_sync_master_wait_no_slave 表示是否允許master每個事務都要等待slave接收確認。預設為ON,每一個事務都會等待,如果slave crash後,當slave追趕上master的日誌時,可以自動的切換為半同步方式。如果為OFF,則slave追趕上後,也不會採用半同步的方式複製了,需要手工配置。
rpl_semi_sync_master_trace_level=32 表示用於開啟半同步複製時的調試級別,預設32
補充:
rpl_semi_sync_master_wait_for_slave_count MySQL 5.7.3引入的,該變數設置主庫需要等待多少個slave應答,才能返回給客戶端,預設為1。
2)狀態變數
mysql> show status like '%semi%'; +--------------------------------------------+--------+ | Variable_name | Value | +--------------------------------------------+--------+ | Rpl_semi_sync_master_clients | 1 | | Rpl_semi_sync_master_net_avg_wait_time | 21014 | | Rpl_semi_sync_master_net_wait_time | 126089 | | Rpl_semi_sync_master_net_waits | 6 | | 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 | 2186 | | Rpl_semi_sync_master_tx_wait_time | 4373 | | 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 | 4 | +--------------------------------------------+--------+ 14 rows in set (0.00 sec)
Rpl_semi_sync_master_status 標記master現在是否是半同步複製狀態
Rpl_semi_sync_master_clients 記錄支持半同步的slave的個數
Rpl_semi_sync_master_yes_tx master成功接收到slave的回覆的次數
Rpl_semi_sync_master_no_tx master沒有收到slave的回覆而提交的次數