随着以Google Spanner以及Amazon Aruora 為代表的NewSQL的快速發展,為資料庫的資料一緻性給出了與以往不同的思路: 基于分布式一緻性協定!我們也實作了一個獨立的分布式協定庫X-Paxos,并将這個特性繼承到了RDS 5.7三節點企業版中。
三節點企業版是面向企業使用者的雲資料庫産品, 基于一緻性協定的多副本複制技術,具有跨可用域RPO=0的強一緻能力,并在此基礎上大幅壓縮使用者成本,是具有低成本高可靠性的MySQL解決方案。
*新品釋出直播預告
預約直播,解鎖新品核心技術! 了解更多,檢視産品核心優勢!分布式一緻性協定
說到一緻性協定,我們通常就會講到複制狀态機。一般情況下,我們會用複制狀态機加上一緻性協定算法來解決分布式系統中的高可用和容錯。許多分布式系統,都是采用複制狀都是采用複制狀态機來進行副本之間的資料同步,比如HDFS,Chubby和Zookeeper等。

所謂複制狀态機,就是在分布式系統的每一個執行個體副本中,都維持一個持久化的日志,然後用一定的一緻性協定算法,保證每個執行個體的這個log都保持完全一緻,執行個體内部的狀态機按照日志的順序回放日志中的每一條指令,這樣用戶端來讀取資料時時,在每個副本上都能讀到一樣的資料。
複制狀态機的核心就是圖中的Consensus子產品,也就是我們要讨論的Paxos,Raft等一緻性協定算法(準确的說,Paxos并不指代一個協定,而是一類協定的統稱,比較常見的paxos類協定有Basic-Paxos 和Multi-Paxos)
1.Basic-Paxos
Basic-Paxos是Lamport最先提出的分布式一緻性算法。要了解Paxos,隻要記住一點就好了,Paxos隻能為一個值形成共識,一旦Propose被确定,之後值永遠不會變,也就是說整個Paxos Group隻會接受一個提案(或者說接受多個提案,但這些提案的值都一樣)。
Paxos協定中有三個角色,Proposer、Acceptor和Learner角色(Leaner隻是學習Proposer的結果,暫時不讨論該角色)。Paxos允許多個Proposer同時提案。Proposer要提出一個值讓所有Acceptor達成一個共識,達成一個共識分為2個階段:Prepare階段和Accept階段。
Prepare階段
Proposer會給出一個ProposeID N(注意,此階段Proposer不會把值傳給Acceptor)給每個Acceptor,如果某個Acceptor發現自己從來沒有接收過大于等于N的Propose,則會回複Proposer,同時承諾不再接收ProposeID小于等于N的提議的Prepare。如果這個Acceptor已經承諾過比N更大的propose,則不會回複Proposer。(如果Acceptor之前已經Accept了(完成了第二個階段)一個小于N的Propose,則會把這個Propose的值傳回給Proposer,否則會傳回一個null值。當Proposer收到大于半數的Acceptor的回複後,就可以開始第二階段。)
Accept階段
這個階段Propose能夠提出的值是受限的,隻有它收到的回複中不含有之前Propose的值,他才能提出一個新的value,否則隻能用回複中Propose最大的值作為提議的值。Proposer用這個值和ProposeID N對每個Acceptor發起Accept請求。也就是說就算Proposer之前已經得到過acceptor的承諾,但是在accept發起之前,Acceptor可能給了proposeID更高的Propose承諾,導緻accept失敗。也就是說由于有多個Proposer的存在,雖然第一階段成功,第二階段仍然可能會被拒絕掉。
2.Multi-Paxos
前面講的Paxos還過于理論,無法直接用到複制狀态機中,總的來說,有以下幾個原因:
1).Paxos隻能确定一個值,無法用作Log的連續複制
2).由于有多個Proposer,可能會出現活鎖
3).提案的最終結果可能隻有部分Acceptor知曉,無法達到複制狀态機每個instance 的log完全一緻。
Multi-Paxos,就是為了解決上述三個問題,使Paxos協定能夠實際使用在狀态機中。
解決第一個問題其實很簡單:為Log Entry每個index的值都用一個獨立的Paxos instance。解決第二個問題也很簡單,讓一個Paxos group中不要有多個Proposer,在寫入時先用Paxos協定選出一個leader(如我上面的例子),之後隻由這個leader寫入,就可以避免活鎖問題。并且,有了單一的leader之後,我們還可以省略掉大部分的prepare過程。隻需要在leader當選後做一次prepare,所有Acceptor都沒有接受過其他Leader的prepare請求,那每次寫入,都可以直接進行Accept,除非有Acceptor拒絕,這說明有新的leader在寫入。
為了解決第三個問題,Multi-Paxos給每個Server引入了一個firstUnchosenIndex,讓leader能夠向每個Acceptor同步被選中的值。解決這些問題之後Paxos就可以用于實際工程了。
Paxos到目前已經有了很多的補充和變種,實際上,ZAB也好,Raft也好,都可以看做是對Paxos的修改和變種。關于Paxos,還有一句流傳甚廣的話,“世上隻有一種一緻性算法,那就是Paxos”。
3.Raft
Raft是斯坦福大學在2014年提出的一種新的一緻性協定,協定的内容,網上材料太多,不做過多闡述,這裡僅和Paxos做一下比較:
1).Raft則将Multi-Paxos的功能做了子產品劃分,并對每個子產品做了詳細的闡述和理論證明:Leader Election、Log Replication、Commit Index Advance、Crash Recovery、Membership Change 等。
2).Multi-Paxos和Raft,最本質的差別在于,是否允許日志空洞。Raft必須連續,不允許空洞。Multi-Paxos允許日志空洞存在
X-Paxos
X-Paxos是一個從阿裡業務場景出發、基于分布式一緻性協定的實作(嚴格意義來說,X-Paxos的實作同時參考了經典的multi-Paxos和Raft協定),服務于RDS 5.7三節點企業版。同時X-Paxos是一個公共庫,可以應用在更多的系統。下面詳細講一下X-Paxos。
X-Paxos的整體架構如上圖所示,主要可分為網絡層、服務層、算法子產品、日志子產品4個部分。
1.網絡層
網絡層基于阿裡内部非常成熟的網絡庫libeasy實作。libeasy的異步架構和線程池非常契合我們的整體異步化設計,同時我們對libeasy的重連等邏輯進行了修改,以适應分布式協定的需求。
2.服務層
服務層是驅動整個Paxos運作的基礎,為Paxos提供了事件驅動,定時回調等核心的運作功能,每一個Paxos實作都有一個與之緊密相關的驅動層,驅動層的架構與性能和穩定性密切相關。X-Paxos的服務層是一個基于C++11特性實作的多線程異步架構。常見的狀态機/回調模型存在開發效率較低,可讀性差等問題,一直被開發者所诟病;而協程又因其單線程的瓶頸,而使其應用場景受到限制。C++11以後的新版本提供了完美轉發(argument forwarding)、可變模闆參數(variadic templates)等特性,借助C++11的這個特性,我們實作了一種全新的異步調用模型。
3.算法子產品
X-Paxos目前的算法基于強leadership的multi-paxos[3]實作,大量理論和實踐已經證明了強leadership的multi-paxos,性能好于multi-paxos/basic paxos,目前成熟的基于Paxos的系統,都采用了這種方式。
算法子產品的基礎功能部分本文不再重複,感興趣的同學可以參考相關論文。在基礎算法的基礎上,結合阿裡業務的場景以及高性能和生态的需求,X-Paxos做了很多的創新性的功能和性能的優化,使其相對于基礎的multi-paxos,功能變的更加豐富,性能也有明顯的提升。下一章中,将對這些優化進行詳細的介
4.日志子產品
日志子產品本是算法子產品的一部分,但是出于對極緻性能要求的考慮,我們把日志子產品獨立出來,并實作了一個預設的高性能的日志子產品;有極緻性能以及成本需求的使用者,可以結合已有的日志系統,對接日志子產品接口,以擷取更高的性能和更低的成本。這也是X-Paxos作為高性能獨立庫特有的優勢,後面也會對這塊進行詳細介紹。
RDS 5.7三節點企業版的資料一緻性解決方案
RDS 5.7三節點企業版是第一個接入X-Paxos生态的重要産品,它是一個自封閉、高可靠、強一緻、高性能的資料庫系統,可以憑借核心本身徹底解決資料品質的問題,無需外部介入。同時RDS 5.7三節點企業版也是基于MySQL生态,相容最新版本的MySQL 5.7,對于MySQL的使用者來說,可以無縫遷移到RDS 5.7三節點企業版。
1.整體架構
先來看一下RDS 5.7三節點企業版的基本架構。
上圖展示的是一個部署三個執行個體的RDS 5.7三節點企業版叢集。RDS 5.7三節點企業版是一個單點寫入,多點可讀的叢集系統。在同一時刻,整個叢集中至多會有一個Leader節點來承擔資料寫入的任務。相比多點寫入,單點寫入不需要處理資料集沖突的問題,可以達到更好的性能與吞吐率。
RDS 5.7三節點企業版的每個執行個體都是一個單程序的系統,X-Paxos被深度整合到了資料庫核心之中,替換了原有的複制子產品。叢集節點之間的增量資料同步完全是通過X-Paxos來自驅動,不再需要外部手動指定複制位點。RDS 5.7三節點企業版為了追求最高的性能,選擇了自己實作Consensus日志這種接入X-Paxos的方式,在MySQL Binlog的基礎上實作了一系列X-Paxos日志接口,賦予X-Paxos操縱Binlog的能力。
使用者在通路RDS 5.7三節點企業版時可以直接使用MySQL原生的用戶端進行通路,完美相容MySQL生态的周邊系統,包括中間件、備份恢複、DTS等等。
2.複制流程
RDS 5.7三節點企業版的複制流程是基于X-Paxos驅動Consensus日志進行複制,Leader節點在事務prepare階段會将事務産生的日志收集起來,傳遞給X-Paxos協定層後進入等待。X-Paxos協定層會将Consensus日志高效地轉發給叢集内其他節點,相比原生MySQL,日志發送采用了Batch,Pipeline等優化手段,特别是在長傳鍊路的場景中,效率提升明顯。當日志在超過叢集半數執行個體上落盤後 X-Paxos會通知事務可以進入送出步驟,否則通知事務復原。
Follower節點收到Leader傳遞過來的日志以後将日志内容Append到Consensus Log末尾,由協調者負責讀取并解析日志後傳遞給各個回放工作線程進行資料更新。由于Consensus日志是基于Binlog開發,回放可以利用MySQL-5.7的Logic clock并行複制特性。相比MySQL-5.6中回放并行度受到表數目限制,MySQL-5.7可以做到依賴主庫Group Commit的事務數進行并發回放,進一步提升回放的速度。
3.Failover
RDS 5.7三節點企業版隻要半數以上的節點存活就能保證叢集正常對外服務。當Leader節點故障時會觸發重新選主的流程。選主流程由X-Paxos驅動,在Paxos協定的基礎上,結合優先級進行新主的選舉。
如上圖所示,左上的Case是原Leader A節點當機,此時在選舉逾時後,B節點開始嘗試選自己為Leader, 并且C節點同意, 那麼B成為新的主節點,叢集正常運作。
左下的Case 是原Leader A節點發生網絡分區,此時在選舉逾時後,BC兩個節點的行為和之間的Case類似。A節點由于無法将心跳和日志發送給BC兩個節點在逾時後會降級,然後不斷嘗試選自己為Leader,但是因為沒有其他節點的同意,達不成多數派,一直都不會成功。
再看日志資料,RDS 5.7三節點企業版 承諾在failover的情況下不會丢失送出的資料。Paxos協定保證了不管叢集發生什麼樣的變故,在恢複後一定能保證日志的一緻性。那麼隻要資料是按照日志進行回放,就能保證所有節點的資料一緻。如右上所示,假設A節點當機或者分區前已經把3号日志複制到了B節點,那麼在重新選舉後,B節點會嘗試将3号日志再複制到C節點。
4.性能對比
Group Replication是MySQL 官方出品的叢集方案。它借鑒了Galera的思想,同樣支援多主多點寫入。Group Replication實作了一個X-COM的通信層,其新版本中已經使用了Paxos算法。目前一個GR叢集中最多可以有9個節點,響應延時相對穩定,在節點同步日志層面, GR使用binlog,相比Galera更加的通用。
Group Replication 為了保證能夠多點寫入,會傳遞WriteSet的資訊,其他節點收到WriteSet後需要進行合法性驗證,確定正确處理沖突事務。在測試中,我們發現為了支援多點寫入而做合法性驗證是一個非常明顯的性能瓶頸點,除此之外,Group Replication還是着重解決區域網路或者是同城下一緻性問題,長傳鍊路下基本沒有做任何優化。我們在跨城場景下,使用官方5.7.17與RDS 5.7三節點企業版做了對比測試,GR的性能劣勢非常明顯,純寫入的性能隻有RDS 5.7三節點企業版的五分之一,OLTP的性能也不足RDS 5.7三節點企業版的40%。
RDS 5.7三節點企業版是對阿裡業務場景非常有效的資料庫解決方案。RDS 5.7三節點企業版不僅能夠享受到開源社群帶來的紅利,關鍵的技術也能夠做到完全的自主、可控,能夠針對業務的需求進行靈活的變更。未來 RDS 5.7三節點企業版會在此基礎上做更多的優化、例如支援多分片的Paxos, Follower提供強一緻讀等功能。