MySQL Group Replication(MGR)框架讓MySQL具有了自動主從切換和故障恢復能力,舉single primary(單主)模式爲例,primary做爲主節點對外提供讀寫服務,是惟一的可寫節點,其餘節點均爲secondary節點,可提供讀服務。在傳統的master-slave主從複製模式下,若是master發生了crash,MySQL DBA須要手動將slave升級爲新master(好比關閉只讀開關等),舊的master重啓後需執行change master to進行復制關係重建,並執行start slave開啓複製。若是是semi-sync半同步複製,還須要進行半同步參數配置。但在MGR模式下MySQL能自動發現primary crash,經過選主產生新的primary節點對外提供讀寫服務。舊的primary節點重啓後,DBA只須要執行start group_replication便可將crash節點從新加入到Group中,在運維便利性和系統健壯性上有極大的提高。html
本文分爲3個部分,先分析MGR的成員管理機制,講解crash的節點如何從新加入到Group中,而後再分析該節點加入Group後如何進行故障恢復使其自身狀態從Recovery變爲ONLINE,最後分析目前存在的不足。node
1、成員管理mysql
視圖及視圖切換sql
MGR以組視圖(Group View,簡稱視圖)爲基礎來進行成員管理。視圖指Group在一段時間內的成員狀態,若是在這段時間內沒有成員變化,也就是說沒有成員加入或退出,則這段連續的時間爲一個視圖,若是發生了成員加入或退出變化,則視圖也就發生了變化,MGR使用視圖ID(View ID)來跟蹤視圖的變化並區分視圖的前後時間。在進一步介紹以前,咱們先看一個圖:mongodb
Group當前的視圖ViewID爲83973:2,該視圖中包括2個成員,分別爲DB1和DB2;一段時間後DB3節點請求加入Group,成功加入後視圖切換爲83973:3,包括3個成員,分別爲DB一、DB2和DB3;以後DB2節點crash而退出了Group,視圖切換爲83973:4;以後DB4加入Group,視圖切換爲83973:5。從上面的圖例咱們能夠發現,ViewID由2部分組成,分別以下。數據庫
前綴部分:是在這個Group初始化時產生,爲當時的時間戳,Group存活期間該值不會發生變化。因此,該字段可用於區分2個視圖是否爲同一個Group的不一樣時間點;bootstrap
序號部分:Group初始化時,第一個視圖的序號從1開始,其成員只有1個,爲進行初始化的節點。之後Group出現任何成員的加入或退出序號都須要增一。api
上面所述的是同個Group的視圖的變化狀況,這裏再補充說明下Group定義。一個組Group是在節點參數爲group_replication_bootstrap_group爲on的條件下執行start group_replication產生的,若是要加入現有的Group,節點須要確保group_replication_bootstrap_group爲off。一個節點加入Group後,須要連到其餘節點使本身的數據uptodate,若是該Group其餘成員都已不在線,那麼就沒法進行uptodate,在這種狀況下,就須要設置group_replication_bootstrap_group爲on來初始化新的Group。緩存
Group的當前視圖能夠經過performance_schema系統庫下的replication_group_member_stats表中查到,下圖表示該Group初始化時間爲2018/2/7 14:54:13,已經發生了321次視圖切換:app
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
node1>select * from replication_group_member_stats limit
1
\G
***************************
1
. row ***************************
CHANNEL_NAME: group_replication_applier
VIEW_ID:
15179864535059527
:
321
MEMBER_ID: 2e7b6e78-0bd3-11e8-9ba2-c81f66e48c6e
COUNT_TRANSACTIONS_IN_QUEUE:
0
COUNT_TRANSACTIONS_CHECKED:
382502
COUNT_CONFLICTS_DETECTED:
0
COUNT_TRANSACTIONS_ROWS_VALIDATING:
340084
TRANSACTIONS_COMMITTED_ALL_MEMBERS: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:
1
-
117137653
:
117596712
-
117597349
LAST_CONFLICT_FREE_TRANSACTION: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:
117273119
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE:
25586
COUNT_TRANSACTIONS_REMOTE_APPLIED:
356916
COUNT_TRANSACTIONS_LOCAL_PROPOSED:
0
COUNT_TRANSACTIONS_LOCAL_ROLLBACK:
0
1
row
in
set
(
0.00
sec)
|
視圖切換實現
上面咱們簡單一個節點加入Group後,須要連到其餘節點使本身數據uptodate,那麼基於什麼來判斷本身的數據uptodate了呢。下面咱們詳細介紹一個節點如何加入到Group中,用圖說話,以下:
一個節點請求加入Group時,其首先會根據配置的group_replication_group_seeds參數跟Group的種子成員創建TCP鏈接 (Gcs_xcom_control::do_join())。該種子成員會根據本身的group_replication_ip_whitelist(ip白名單)檢查是否容許新節點加入,MGR默認不限制新節點的ip。鏈接創建後,新節點發送請求申請加入組,如上圖左上所示;收到請求後,種子成員廣播視圖變化的消息給Group中的全部節點,包括申請加入的節點,如右上所示;各節點收到消息後開始作視圖切換。每一個節點都會廣播一個狀態交換消息,每一個交換消息包含了節點的當前狀態和信息,如圖左下所示。發送了交換消息後,各個節點開始接收其餘節點廣播的消息,將其中的節點信息更新到本節點所維護的成員列表中。狀態交換消息像事務數據包同樣走相同的Paxos(Mencius)協議進行發送,當收到全部成員的狀態交換消息時,通訊模塊將完整的新視圖封裝爲視圖數據包(view_change_log_event,即vcle的前身,但沒有數據庫當前的快照版本信息),Group中的每一個節點基於MGR的通訊模塊將其返回給全局事務認證模塊的消息隊列(簡稱認證隊列)。至此,視圖切換即告結束。視圖切換過程當中不會影響在線成員對外服務。
視圖數據包的做用
完成視圖切換隻是成員加入Group要作的第一步,只是說明該成員能夠接收到Group中經過Paxos協議達成共識的消息,並不意味着能夠將成員設置爲ONLINE(上線)對外提供服務。緣由是新成員還須要進行數據同步,創建起正確的數據版本(recovery_module->start_recovery)。以後才能執行Paxos協議消息,進而上線提供正常的用戶訪問服務。
在這過程當中,視圖數據包發揮了關鍵性的做用。如上所述,視圖數據包經過Paxos放入消息隊列,那麼各節點依次處理消息隊列中的數據包時就可以發現視圖數據包(Plugin_gcs_events_handler::on_view_changed),將視圖數據包封裝爲view_change_log_event後寫入Relay log文件中,group_replication_applier通道的並行複製線程讀取Relay log中的vcle並將其寫入到Binlog文件中。這樣,Binlog文件中的事務就被vcle劃分爲多個區間,每一個區間都表明一個視圖。vcle中包括了ViewID和用於進行全局事務認證模塊進行事務認證的衝突檢測數據庫。基於vcle,咱們能夠把節點上線前的過程劃分爲2個階段,分爲前一個視圖數據恢復和本視圖緩存事務執行。第一個階段又能夠細分爲本地恢復和全局恢復。下面分析這三個子過程的具體實現。
2、故障恢復實現
在開始介紹前,需簡單介紹下MGR所涉及的數據複製及其通道(channel),MGR正常運行時,即Group中各節點均在線,節點間經過Paxos協議傳輸數據,異地事務通過認證後寫入group_replication_applier Relay log中,由group_replication_applier通道的複製線程負責回放。當有節點加入Group時,須要用到另外一個複製通道group_replication_recovery,它是一個傳統的Master-Slave異步複製通道。
MGR故障恢復代碼位於MGR代碼目錄(rapid\plugin\group_replication\src)的Recovery.cc文件下,節點的故障恢復交由單獨的恢復線程(launch_handler_thread -> recovery_thread_handle)執行。
本地恢復階段
第一步:進行故障恢復初始化,包括故障恢復線程初始化,Group成員信息初始化等。
第二步:啓動group_replication_applier複製通道。對於故障恢復場景,待加入的成員不是新節點,也就是說其曾經加入過該節點,其group_replication_applier通道的Relay log可能還有一些Binlog未回放。因此須要先將這部分Relay log回放掉。因爲有後面所述對的第三步,非Group初始化場景下,其實能夠跳過回放本地恢復的環節,直接從其餘節點複製所需的數據,但引入本地恢復的好處在於可提升恢復性能,無需在拉取這部分Binlog,提升恢復過程健壯性,減少所需Binlog被purge的風險。
確認對應通道的複製線程空閒後,阻塞(suspend)認證隊列的處理線程,即容許新的Paxos消息入隊但不進行處理。這樣,本視圖的Paxos消息會在認證隊列中堆積起來。
若該節點是Group的第一個節點,即Group初始化場景,則故障恢復結束,可將此節點置爲在線狀態。
全局恢復階段
第三步:完成本地Relay log回放後,進入故障恢復第三步,即State transfer是經過group_replication_recovery複製通道從Group其餘在線節點拉取本節點欠缺的非本視圖的數據。與傳統的Master-Slave複製配置不一樣,MGR中僅需爲其配置帳號和密碼便可,配置方式形如:CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='rpl_pass' FOR CHANNEL 'group_replication_recovery'。顯然,該通道是基於GTID以MASTER_AUTO_POSITION的方式進行。恢復線程隨機選擇一個在線節點(donor),調用rpl_slave.cc中的request_dump函數創建與donor的複製關係,該函數攜帶了恢復節點的gtid_executed信息。donor端會逆序遍歷其Binlog文件,經過判斷Binlog文件起始的Previous-GTIDs來找到第一個不屬於gtid_executed的事務,從該事務開始進行數據複製。
MGR實現了全局恢復階段的容錯能力,可以處理異步複製過程當中出現的絕大部分狀況:
recovery_aborted:表示主動退出故障恢復過程。
on_failover:表示donor節點離開了Group,故障恢復線程選擇另外一個在線節點做爲donor,連上後繼續進行異步複製。該場景下,從退出的donor節點複製而來未回放的Relay log不會purge,而是完成回放後再繼續從當前donor進行復制。
donor_channel_applier_error:表示本節點回放從donor節點複製過來的事務時出錯,故障恢復線程也會選擇另外一個節點做爲donor繼續進行數據複製,但與on_failover不一樣的是,該場景下,未回放的Relay log被purge,從出錯事務位置開始重新donor節點從新拉取Binlog進行嘗試。
donor_transfer_finished:這是正常的狀況,表示全局恢復已經完成了所需數據複製。可進入到緩存事務執行階段。那麼如何獲知已經複製完所需數據呢,這就用到了咱們前述的vcle,複製vcle後,會判斷其攜帶的ViewID,若是其與節點當前的ViewID同等,就表示異步複製能夠中止了。在開始下一步處理前,還故障恢復線程還會基於vcle初始化認證所需的衝突檢查數據庫。
除了上述狀況外,還可能出現所選的donor沒法鏈接(好比配置了IP白名單)或所需的Binlog已經被purge的狀況。對於該狀況,故障恢復線程會選擇其餘donor進行重試,可經過參數group_replication_recovery_reconnect_interval和group_replication_recovery_retry_count對重試行爲進行控制,第一個參數表示重試的間隔時間,默認爲1分鐘,第二個參數爲重試的次數, 默認爲10次。
緩存事務執行
第四步:先喚醒在第二步被阻塞的認證隊列處理線程,讓本節點逐步跟上Group中的其餘節點,進而將其設置爲在線(ONLINE)。那麼,應該在何時容許節點上線呢,MGR引入參數group_replication_recovery_complete_at進行控制,可選TRANSACTIONS_CERTIFIED或TRANSACTIONS_APPLIED。分別表示認證隊列爲空或回放完全部已認證的事務時。雖然判斷條件很明確,但實際場景下代碼實現卻較爲困難,由於負載多是持續的,狀態是動態變化,不會存在靜態的事務均已認證或均已回放的狀態。
對於單主模式,在開始處理認證隊列以前,須要先將衝突檢測標誌位開啓,這樣在緩存的隊列請求時就會將事務攜帶的快照版本跟衝突檢測數據庫版本進行對比,決定事務是回滾仍是提交。此時開啓衝突檢測的緣由是緩存的事務有部分是在primary節點回放以前視圖產生的Relay log過程時執行的,也就是說,事務執行的時候,其基於的數據並非最新的數據,因此可能會被回滾,若是未開啓衝突檢測就會致使數據不一致。這裏須要說明一點,就是不管是否開啓衝突檢測,通過Paxos發送的消息都會進入認證隊列,而後依次進行處理。代碼實現上,衝突檢測只是認證的一個環節,除此以外,還須要爲事務肯定gtid,並確保相同的事務在各個節點產生的gtid是相同的。
成員上線與出錯處理
第五步:在達到了group_replication_recovery_complete_at所肯定的條件後,發送Recovery_message::RECOVERY_END_MESSAGE消息,通知Group中的各個節點,將該節點設置爲在線狀態。
第六步:在故障恢復全過程當中,若遇到了沒法繼續的狀況或錯誤,好比recovery_aborted被置位或恢復所需的數據在其餘節點均已被Purge或等待上線時回放出錯等,則先將該節點置爲ERROR狀態,確認該節點複製相關線程退出了,節點向Group發送leave信息退出Group,而不是置爲ERROR狀態候仍留在Group中。這是跟MongoDB Replica Set等其餘多節點數據庫系統不同的地方。
第七步:不論是否出錯,均須要重置故障恢復相關的參數,並銷燬故障恢復線程。
3、MGR故障恢復實現的不足
一、隨機選擇donor節點:早期的MGR版本按照節點設置group_replication_group_seeds參數中的種子節點順序來選擇donor節點,若各節點的參數配置一致,則存在同一個節點被反覆選擇爲donor節點,會致使該節點負載過大而出現複製延遲等問題,不利Group中各節點負載的均衡。當前的MGR版本已將其調整爲隨機選擇donor,有了很大進步,但仍能夠進一步優化,就是存在多個可選的節點狀況下,單主模式先排除primary節點,多主模式下排除本地負載壓力最大的節點;
二、本視圖事務緩存機制:MGR在節點進行全局恢復時,將本視圖產生的消息緩存在認證隊列中,若節點落後較多,需較長時間完成全局恢復,若Group的負載較高,會在認證隊列中堆積大量的消息,這些消息位於內存中,容易出現由於內存不足而OOM。可考慮的優化方案是基於必定的策略將緩存的消息臨時寫到系統表中,將壓力轉移到磁盤上。
三、Binlog被purge處理:相比Percona基於Galera封裝的Percona XtraDB Cluster(PXC),MongoDB Replica Set(ReplSet)方案,MGR目前還未提供節點全量恢復方案。便可往Group中加入一個全新的節點,由MGR來負責從其餘節點拷貝全量數據(State Snapshot Transfer,SST),並經過增量複製(Incremental State transfers,IST)直至將節點置爲上線狀態。PXC是個解決方案套件,採用xtrabackup來實現SST,ReplSet是進程,採用邏輯拷貝的方式實現Initial Sync。MGR可參考ReplSet來實現。
四、成員類型單一:MGR目前僅提供Primary和Secondary兩種成員類型,不支持Arbiter,Hidden等類型,也不支持像MongoDB和X-Cluster等其餘數據庫系統設置豐富的成員屬性。
參考資料:
一、 http://mysqlhighavailability.com/distributed-recovery-behind-the-scenes/
二、https://mysqlhighavailability.com/improvements-and-changes-to-group-replication-recovery/
三、MySQL 5.7.20、MySQL 8.0.4源碼
四、MySQL運維內參 27章MySQL Group Replication
五、https://www.percona.com/blog/2015/08/05/pxc-incremental-state-transfers-in-detail/
六、https://www.percona.com/doc/percona-xtradb-cluster/5.5/manual/state_snapshot_transfer.html
七、https://docs.mongodb.com/manual/core/replica-set-sync/#initial-sync
轉:溫正湖