組復(fù)制簡(jiǎn)介
組復(fù)制MySQL Group Replication(簡(jiǎn)稱(chēng)MGR)是MySQL官方在已有的Binlog復(fù)制框架之上,基于Paxos協(xié)議實(shí)現(xiàn)的一種分布式復(fù)制形態(tài)。RDS MySQL集群系列實(shí)例支持組復(fù)制。本文介紹組復(fù)制的優(yōu)勢(shì)、技術(shù)實(shí)現(xiàn)原理、AliSQL對(duì)組復(fù)制穩(wěn)定性的優(yōu)化。
組復(fù)制的優(yōu)勢(shì)
組復(fù)制、半同步復(fù)制、異步復(fù)制的數(shù)據(jù)可靠性、數(shù)據(jù)一致性、全局事務(wù)一致性情況如下表所示。
特性 | 組復(fù)制 | 半同步復(fù)制 | 異步復(fù)制 |
數(shù)據(jù)可靠性 | ★★★★★ | ★★★ | ★ |
數(shù)據(jù)一致性 | 保證主備數(shù)據(jù)一致性 | 不保證 | 不保證 |
全局事務(wù)一致性 | 支持 | 不支持 | 不支持 |
數(shù)據(jù)強(qiáng)可靠性
組復(fù)制的數(shù)據(jù)強(qiáng)可靠性來(lái)源于Paxos協(xié)議的多數(shù)派原則,即當(dāng)多數(shù)派收到事務(wù)的Binlog后,事務(wù)才能在各節(jié)點(diǎn)提交。這保證了在多數(shù)派可用的情況下,任何節(jié)點(diǎn)故障都不會(huì)導(dǎo)致數(shù)據(jù)丟失。
例如,5個(gè)節(jié)點(diǎn)的集群,3個(gè)節(jié)點(diǎn)收到Binlog,2個(gè)節(jié)點(diǎn)未收到Binlog,此時(shí)有2個(gè)節(jié)點(diǎn)故障:
如果故障的2個(gè)節(jié)點(diǎn)是收到Binlog的節(jié)點(diǎn),那至少還有1個(gè)節(jié)點(diǎn)上有數(shù)據(jù)。
如果故障的2個(gè)節(jié)點(diǎn)是沒(méi)收到Binlog的節(jié)點(diǎn),那至少還有3個(gè)節(jié)點(diǎn)上有數(shù)據(jù)。
多數(shù)派指集群中超過(guò)半數(shù)的節(jié)點(diǎn)。
少數(shù)派指集群中少于半數(shù)的節(jié)點(diǎn)。
數(shù)據(jù)強(qiáng)一致性
在組復(fù)制中,事務(wù)總是先傳輸?shù)郊褐衅渌?jié)點(diǎn),然后寫(xiě)入Binlog文件,這保證無(wú)論主節(jié)點(diǎn)在什么時(shí)刻發(fā)生故障,重新啟動(dòng)后數(shù)據(jù)都不會(huì)比集群選出的新主節(jié)點(diǎn)多。舊主節(jié)點(diǎn)故障重啟后,能夠自動(dòng)加回集群,拉取它缺失的Binlog,就能夠獲得最新的數(shù)據(jù),不會(huì)導(dǎo)致主備節(jié)點(diǎn)數(shù)據(jù)不一致。
而在傳統(tǒng)主備復(fù)制模式中,事務(wù)是先寫(xiě)入Binlog文件,然后傳輸?shù)絺涔?jié)點(diǎn)。這樣,如果主節(jié)點(diǎn)在寫(xiě)入Binlog后,傳輸數(shù)據(jù)到備節(jié)點(diǎn)之前發(fā)生故障,重新啟動(dòng)后數(shù)據(jù)就會(huì)多于備節(jié)點(diǎn)。如果此時(shí)備節(jié)點(diǎn)已經(jīng)被切換成新主節(jié)點(diǎn),就會(huì)出現(xiàn)主節(jié)點(diǎn)數(shù)據(jù)少于備節(jié)點(diǎn),主備節(jié)點(diǎn)數(shù)據(jù)不一致的情況。
全局事務(wù)強(qiáng)一致性
組復(fù)制具備集群的節(jié)點(diǎn)間的數(shù)據(jù)全局強(qiáng)一致讀和全局強(qiáng)一致寫(xiě)能力,并且可根據(jù)業(yè)務(wù)需要修改group_replication_consistency參數(shù)來(lái)調(diào)整讀寫(xiě)的一致性等級(jí):
設(shè)置備節(jié)點(diǎn)的強(qiáng)一致讀能力:可以在備節(jié)點(diǎn)上設(shè)置Session級(jí)別的group_replication_consistency參數(shù)為BEFORE,然后執(zhí)行查詢(xún)語(yǔ)句。此時(shí),備節(jié)點(diǎn)會(huì)等到主節(jié)點(diǎn)上所有先于此查詢(xún)語(yǔ)句的事務(wù)應(yīng)用完成后,再執(zhí)行這條查詢(xún)語(yǔ)句。這樣在備節(jié)點(diǎn)和主節(jié)點(diǎn)上就會(huì)讀到一致的數(shù)據(jù)。
設(shè)置主節(jié)點(diǎn)的強(qiáng)同步寫(xiě)能力:可以在主節(jié)點(diǎn)上設(shè)置Session級(jí)別的group_replication_consistency參數(shù)為AFTER,然后執(zhí)行寫(xiě)事務(wù),這個(gè)事務(wù)會(huì)等到所有節(jié)點(diǎn)應(yīng)用成功后,再在主節(jié)點(diǎn)上返回提交成功的消息到客戶(hù)端。
組復(fù)制的部署模式
如上圖所示,組復(fù)制支持單主和多主兩種部署模式:
多主模式(Multiple Leader):
集群中所有節(jié)點(diǎn)均可讀可寫(xiě)。多主模式的組復(fù)制主要用于擴(kuò)展實(shí)例的寫(xiě)能力。它依賴(lài)Paxos協(xié)議的多點(diǎn)寫(xiě)入能力,輔以行級(jí)別的沖突檢測(cè),能夠保證所有節(jié)點(diǎn)收到數(shù)據(jù)的順序一致,實(shí)現(xiàn)多寫(xiě)。
但它的嚴(yán)重缺陷是,在多數(shù)派可用的情況下,任何節(jié)點(diǎn)的故障都會(huì)導(dǎo)致集群的抖動(dòng)(短時(shí)間不可用)。
單主模式(Single Leader):
集群中只有一個(gè)節(jié)點(diǎn)可以寫(xiě)入數(shù)據(jù),其他節(jié)點(diǎn)只能讀不能寫(xiě)。單主模式的組復(fù)制依賴(lài)Paxos Single Leader實(shí)現(xiàn),在擴(kuò)展讀能力、提高數(shù)據(jù)可靠性的同時(shí),保持了高可用性:
當(dāng)備節(jié)點(diǎn)故障時(shí),只要多數(shù)派可用,就不會(huì)影響集群的可用性。
當(dāng)主節(jié)點(diǎn)故障時(shí),集群能夠根據(jù)Paxos協(xié)議,在保證數(shù)據(jù)強(qiáng)一致性的情況下自主進(jìn)行主備切換。
RDS MySQL提供了單主模式的組復(fù)制實(shí)例,并對(duì)只讀節(jié)點(diǎn)做了優(yōu)化,在保證數(shù)據(jù)的高可靠和強(qiáng)一致的同時(shí),提供了更平滑的性能。
組復(fù)制的架構(gòu)
如上圖所示,在MySQL的Server層和Replica層之下,組復(fù)制的架構(gòu)分為三層:
組復(fù)制層(Group Replication Logic Layer):在單機(jī)MySQL的Server層之下,組復(fù)制增加了組復(fù)制層,該層通過(guò)鉤子(HOOK)與Server層相連,負(fù)責(zé)向組通訊層發(fā)送、接收并回放事務(wù)。
組通訊層(Group Communication System Layer):與XCom層共同實(shí)現(xiàn)組復(fù)制層與集群的通訊。該層除了負(fù)責(zé)消息的傳遞,還負(fù)責(zé)故障檢測(cè)和集群成員的管理。
XCom層(Paxos Layer):基于Paxos協(xié)議實(shí)現(xiàn),與組通訊層共同實(shí)現(xiàn)組復(fù)制層與集群的通訊,以及消息傳遞的全局有序性和集群成員的角色切換。它能夠保證所有節(jié)點(diǎn)收到數(shù)據(jù)的順序一致,同時(shí)保證只要多數(shù)派可用,數(shù)據(jù)就不會(huì)丟失。
XCom層
Paxos協(xié)議
Paxos協(xié)議在組復(fù)制中的作用主要有以下兩點(diǎn):
確保集群中各節(jié)點(diǎn)收到數(shù)據(jù)的順序一致,這是多主模式實(shí)現(xiàn)的基礎(chǔ)。
確保多數(shù)派收到數(shù)據(jù)后,事務(wù)才能提交。這對(duì)數(shù)據(jù)可靠性很重要,可以保證只要多數(shù)派可用,數(shù)據(jù)就不會(huì)丟失。
在Paxos協(xié)議中,使用鎖的方式來(lái)實(shí)現(xiàn)節(jié)點(diǎn)間順序一致性,這種方式存在一定的效率問(wèn)題,并且還存在著負(fù)載不均衡的問(wèn)題。在工程實(shí)現(xiàn)過(guò)程中,MySQL的XCom層基于Paxos的變種協(xié)議,Mencius協(xié)議。這是一種使用輪詢(xún)的方法實(shí)現(xiàn)的Leaderless Paxos協(xié)議,能夠有效提升節(jié)點(diǎn)間的負(fù)載均衡。
多主模式實(shí)現(xiàn)原理
多主模式基于Mencius協(xié)議。如上圖所示,在Mencius協(xié)議中,集群中每個(gè)節(jié)點(diǎn)都會(huì)主動(dòng)和其他節(jié)點(diǎn)建立連接,領(lǐng)導(dǎo)一個(gè)單主的Paxos組。對(duì)于n個(gè)節(jié)點(diǎn)的集群,會(huì)形成n個(gè)互不干預(yù)的Paxos組。每個(gè)組中只允許Leader節(jié)點(diǎn)發(fā)送數(shù)據(jù),當(dāng)多數(shù)派收到數(shù)據(jù)后,視為數(shù)據(jù)發(fā)送成功。當(dāng)一個(gè)節(jié)點(diǎn)的客戶(hù)端收到數(shù)據(jù)時(shí),會(huì)使用自己領(lǐng)導(dǎo)的Paxos組發(fā)出數(shù)據(jù),這個(gè)發(fā)送動(dòng)作是串行的,因此單個(gè)組內(nèi)的數(shù)據(jù)順序是一致的。
多個(gè)組在發(fā)出數(shù)據(jù)時(shí),為了保證順序性,使用輪詢(xún)處理機(jī)制。也就是說(shuō),XCom層在接收到多個(gè)Paxos組的數(shù)據(jù)后,必須按一個(gè)預(yù)先約定好的順序傳給組復(fù)制層。如上圖所示,數(shù)據(jù)必須按照 (1,1)、(1,2)、(1,3) 這樣的順序發(fā)送給組復(fù)制層。
當(dāng)一個(gè)節(jié)點(diǎn)發(fā)現(xiàn)比自己的順序號(hào)靠后的數(shù)據(jù)已經(jīng)完成了Paxos過(guò)程,并且自己的這個(gè)位置上沒(méi)有數(shù)據(jù)要發(fā)送時(shí),就會(huì)廣播一個(gè)Noop,通知其他節(jié)點(diǎn)自己的這個(gè)順序號(hào)可以跳過(guò)。每一個(gè)節(jié)點(diǎn)必須等順序在自己前面的一個(gè)節(jié)點(diǎn)發(fā)出數(shù)據(jù)或發(fā)出Noop后才能發(fā)出數(shù)據(jù)。當(dāng)某個(gè)節(jié)點(diǎn)故障或抖動(dòng)時(shí),它既不能發(fā)出數(shù)據(jù)又不能發(fā)出Noop,在故障恢復(fù)或節(jié)點(diǎn)抖動(dòng)期間,就會(huì)導(dǎo)致后續(xù)節(jié)點(diǎn)的數(shù)據(jù)無(wú)法發(fā)出,集群將完全不可用。這是多主模式的一個(gè)嚴(yán)重缺陷。
圖中(m,n)表示第n個(gè)組發(fā)出的第m條數(shù)據(jù)。例如,(2,1)表示第1個(gè)組發(fā)出的第2條數(shù)據(jù)。
單主模式實(shí)現(xiàn)原理
上文中提到的多主模式的缺陷可以?xún)?yōu)化,但無(wú)法從根源上避免。為此MySQL推出了組復(fù)制的單主模式,來(lái)解決少數(shù)派故障對(duì)集群可用性的影響。
上圖是單主模式的XCom架構(gòu),由于只有一個(gè)節(jié)點(diǎn)可寫(xiě),只需激活一個(gè)Paxos組。接收方的XCom在輪詢(xún)數(shù)據(jù)時(shí),會(huì)自動(dòng)忽略其他Paxos組。這樣,只要多數(shù)派可用,Paxos就能正常發(fā)送數(shù)據(jù),集群的可用性不受影響。
在單主模式下,備節(jié)點(diǎn)不會(huì)發(fā)送事務(wù)數(shù)據(jù),但有時(shí)需要發(fā)送一些集群管理信息。備節(jié)點(diǎn)在發(fā)送數(shù)據(jù)時(shí),必須向主節(jié)點(diǎn)請(qǐng)求一個(gè)發(fā)送信息的位置,如上圖中的 <3, 1>,并使用這個(gè)位置向全集群發(fā)送自己的數(shù)據(jù)。這種發(fā)送方式效率低、時(shí)延高,但由于集群管理信息發(fā)送的頻率很低,并不會(huì)對(duì)性能造成影響。
組復(fù)制層
組復(fù)制層的主要工作是向集群發(fā)送、接收并回放事務(wù),其在主節(jié)點(diǎn)和備節(jié)點(diǎn)上的工作原理如下:
在主節(jié)點(diǎn)上:當(dāng)一個(gè)事務(wù)在主節(jié)點(diǎn)進(jìn)入提交階段時(shí),事務(wù)的Binlog會(huì)先被傳到XCom層中,發(fā)送給其他節(jié)點(diǎn)。當(dāng)確認(rèn)多數(shù)派收到事務(wù)后,會(huì)對(duì)事務(wù)進(jìn)行沖突檢測(cè),如果成功則寫(xiě)入Binlog文件并提交,如果失敗則回滾事務(wù)。
在備節(jié)點(diǎn)上:當(dāng)一個(gè)事務(wù)被多數(shù)派接收后,會(huì)由XCom層傳給組復(fù)制層,進(jìn)行沖突檢測(cè)。如果成功則事務(wù)會(huì)被寫(xiě)入Relay Log,隨后被Applier線程應(yīng)用,如果失敗則此事務(wù)的數(shù)據(jù)會(huì)被直接丟棄。
沖突檢測(cè)
場(chǎng)景
組復(fù)制在以下兩種場(chǎng)景中,都需要將不同節(jié)點(diǎn)的事務(wù)在同一個(gè)節(jié)點(diǎn)上執(zhí)行,因此需要對(duì)不同節(jié)點(diǎn)間的事務(wù)進(jìn)行沖突檢測(cè),以確保它們的修改沒(méi)有沖突:
多主模式下,所有寫(xiě)操作都需要沖突檢測(cè)。
單主模式下,如果發(fā)生切主,并且新主節(jié)點(diǎn)在應(yīng)用完舊主的Relay log前,就執(zhí)行寫(xiě)事務(wù),也需要沖突檢測(cè)。
原理
在組復(fù)制中,使用數(shù)據(jù)行的主鍵哈希值來(lái)進(jìn)行行級(jí)別的沖突檢測(cè)。每個(gè)節(jié)點(diǎn)都會(huì)維護(hù)一個(gè)事務(wù)認(rèn)證信息數(shù)組,這是一個(gè)哈希數(shù)組,它的key是數(shù)據(jù)行的哈希值,它的value是最近修改這一行的事務(wù)的GTID與此事務(wù)在源節(jié)點(diǎn)提交時(shí)的gtid_executed(源節(jié)點(diǎn)上所有提交過(guò)的事務(wù)的gtid集合)的并集。
一個(gè)事務(wù)在源節(jié)點(diǎn)準(zhǔn)備提交時(shí),除了發(fā)送自己修改的數(shù)據(jù)到其他節(jié)點(diǎn)外,還會(huì)發(fā)送一個(gè)gtid 集合,這個(gè)集合是該事務(wù)提交時(shí),源節(jié)點(diǎn)上的gtid executed(源節(jié)點(diǎn)上所有提交過(guò)的事務(wù)的gtid集合)。這個(gè)集合標(biāo)識(shí)了當(dāng)前事務(wù)提交前,源節(jié)點(diǎn)上哪些事務(wù)已經(jīng)完成提交,這里將其稱(chēng)為提交集合。
同時(shí),集群內(nèi)的所有節(jié)點(diǎn)(包括源節(jié)點(diǎn)),都會(huì)使用當(dāng)前事務(wù)修改的所有數(shù)據(jù)行(下文簡(jiǎn)稱(chēng)為相關(guān)行)的哈希值作為key,到認(rèn)證信息數(shù)組中讀取value,并將讀到的這些value合并為一個(gè)gtid集合。這個(gè)集合標(biāo)識(shí)了當(dāng)前事務(wù)提交前,哪些事務(wù)必須完成提交,這里將其稱(chēng)為依賴(lài)集合。
在當(dāng)前事務(wù)提交或?qū)懭隦elay Log前,需要將上述兩個(gè)集合進(jìn)行比較:
如果提交集合包含了依賴(lài)集合,則說(shuō)明所有之前修改過(guò)相關(guān)行的事務(wù)均已提交。此時(shí)沖突檢測(cè)成功,源節(jié)點(diǎn)上需要將當(dāng)前事務(wù)寫(xiě)入Binlog 并提交,其他節(jié)點(diǎn)上需要將當(dāng)前事務(wù)寫(xiě)入Relay Log。
如果提交集合沒(méi)有包含依賴(lài)集合,則說(shuō)明有之前修改過(guò)相關(guān)行的事務(wù)未提交。此時(shí)沖突檢測(cè)失敗,源節(jié)點(diǎn)上需要回滾當(dāng)前事務(wù),其他節(jié)點(diǎn)上需要丟棄Relay Log。
認(rèn)證信息數(shù)組還必須及時(shí)清理無(wú)用數(shù)據(jù),以節(jié)省內(nèi)存空間。當(dāng)一個(gè)事務(wù)在所有節(jié)點(diǎn)上都被執(zhí)行之后,任何其他事務(wù)都不會(huì)跟它沖突了,此事務(wù)修改的所有行都可以從認(rèn)證信息數(shù)組中清理掉。在組復(fù)制中每60秒會(huì)清理一次已執(zhí)行的事務(wù)的數(shù)據(jù)。
AliSQL對(duì)組復(fù)制穩(wěn)定性的優(yōu)化
組復(fù)制的穩(wěn)定性在引入單主模式后有了較大的改善,但是在一些場(chǎng)景下,仍存在穩(wěn)定性問(wèn)題。當(dāng)備節(jié)點(diǎn)的延遲較大時(shí),會(huì)有大量的事務(wù)無(wú)法及時(shí)應(yīng)用,這會(huì)導(dǎo)致認(rèn)證信息大量積累,會(huì)有以下兩方面影響:
大量的認(rèn)證信息會(huì)占用很多內(nèi)存,導(dǎo)致實(shí)例內(nèi)存溢出(OOM)。
認(rèn)證信息堆積可能導(dǎo)致清理的代價(jià)變高,影響實(shí)例的穩(wěn)定性。
AliSQL對(duì)認(rèn)證信息的清理做了兩點(diǎn)優(yōu)化:
在主節(jié)點(diǎn)上:無(wú)論何種情況,認(rèn)證信息數(shù)組都不會(huì)被使用,因此主節(jié)點(diǎn)上不再保留認(rèn)證信息數(shù)組,可以消除認(rèn)證信息對(duì)主節(jié)點(diǎn)的資源和穩(wěn)定性的影響。
在備節(jié)點(diǎn)上:只有當(dāng)group_replication_consistency參數(shù)設(shè)置為EVENTUAL時(shí)需要保留認(rèn)證信息。因?yàn)樵谶@個(gè)配置下,備節(jié)點(diǎn)在切為主節(jié)點(diǎn)后會(huì)立刻對(duì)外提供服務(wù),不會(huì)等待Relay Log回放完成,有可能產(chǎn)生數(shù)據(jù)操作的沖突。這種不等新主節(jié)點(diǎn)應(yīng)用完成,就對(duì)外提供服務(wù)的方式在日常生產(chǎn)中并不常用。在禁止這種行為后,可以減少備節(jié)點(diǎn)的認(rèn)證信息保留量,節(jié)省備節(jié)點(diǎn)的內(nèi)存開(kāi)銷(xiāo),提升集群的穩(wěn)定性。