阿里雲RDS金融資料庫(三節點版)系列文章之背景、理論篇
一、背景篇
標籤
PostgreSQL , MySQL , 三節點版 , 金融資料庫 , Raft , 分散式共享存儲版
背景
提到金融級資料庫,大家可能不約而同的會想到Oracle,DB2等商業資料庫。但是隨著開源資料庫的發展,開源資料庫正在逐漸成為資料庫產業的核心,比如MySQL、PostgreSQL資料庫 ,已經深入阿里、平安科技、蘇寧、高德、國家電網(還有很多)的核心。可以看到,不管是MySQL還是PostgreSQL,有越來越多成功的核心應用案例。
目前還有一些金融企業核心資料庫依舊是老牌的商業資料庫,個人認為並不是這些商業資料庫比開源資料庫有多優秀,而是牽一髮而動全身,非單純技術層面的問題。特別是關係民生的金融行業,更換資料庫可不是那麼容易。
開源資料庫在新生業務中是有巨大機會的,畢竟社會是在不斷進步和發展的,老物件會逐漸成為人們的回憶,消失在歷史的長河裡。
不管是商業資料庫,還是開源資料庫,在金融行業混,都必須跨過一道坎:高可用。
(當然,不可否認,解決金融問題,除了高可用,還有更多,包括 功能,性能,SQL標準 方方面面。不在本系列文章討論範疇)
硬體為王 - 傳統資料庫高可用架構
實際上扛起金融核心大旗的還不算Oracle,背後的硬體才是真正的王者,估計也是Oracle收購SUN的原因之一(感嘆一下,SUN的ZFS至今無人能及)。
IBM 大機、小機、高端存儲,以其穩定性、可用性、性能等方面的卓越表現征服了當時的市場。而軟體層面,實際上更多的是圍繞硬體來進行設計,包括Oracle的RAC架構,也是需要依賴共享存儲的。
生態的原因,在硬體為王時代的資料庫,由於硬體的強勢,資料庫軟體依附這些硬體,這也是為什麼又這麼多基於共享存儲的高可用的架構。
傳統資料庫的高可用架構存在的問題
價格昂貴,集中式存儲單點故障(好的存儲可能會在 鏈路、機頭、存儲介質、電源模塊、內部背板等 層面全面解決單點問題)
如果存儲層存在單點(不管是機頭還是鏈路或者其他),軟體層面需要再做一層mirror或RAID冗餘,例如LVM,ZFS,ASM等技術,但是存儲的強一致一定會引入RT(需要軟體層彌補,例如事務分組提交、非同步WAL等)。彎道超車 - 開源資料庫高可用架構
隨著x86硬體架構(以及對應的軟體生態freebsd,linux等)、SSD硬碟的發展,到現在GPUFPGATPU等晶元及其軟體生態的成長。開放性硬體在功能、軟體生態、硬體性能等方面全面提升,以IBM為代表的封閉式硬體逐漸失去了核心地位。
業務的發展和開放性硬體生態的發展,助長了開源資料庫的發展,MySQL、PostgreSQL資料庫就是非常典型的代表。
開放性使得更多的用戶可以獲取到,更多的用戶又助長了軟體本身的發展,這使得最近10年開源資料庫已經開始全面超越商業資料庫。最典型的例子是PostgreSQL,從SQL兼容性,硬體生態對接(LLVM,向量計算,多核並行,GPU計算等),軟體生態對接(PL/R, PL/JAVA, PL/Python, PL/CUDA, 機器學習庫等等),擴展性(9種擴展索引介面支持各種類型的檢索,擴展類型支持DNA、圖像特徵值、化學類型等,擴展語言介面、擴展外部數據源介面等),雲生態(RDS PG OSS可並行讀寫OSS海量存儲外部表)等各個方面全面超越商業資料庫。
開源資料庫通過內部的複製,實現了高可用架構的彎道超車。以MySQL為代表的binlog複製,以PostgreSQL為代表的stream replication。
開源資料庫採樣通用硬體,多節點,更低的成本,更優秀的擴展性,解決了用戶的高可用問題。
兩節點方案
兩節點的HA方案,屬於廉價的解決方案,無法同時保證高可用和高可靠。
要保證高可靠(0數據丟失),就必須等BINLOG或WAL複製到備庫才返回,備庫只要稍有抖動或者備庫故障,就會導致可用性下降。(也就是說,主備任何一個異常都會影響可用性)。
兩節點方案採用自動降級機制,在備庫正常的情況下,採用同步模式(數據需要寫雙份才返回給用戶),保證可用性和可靠性。在備庫異常時,則自動降級為非同步,只能保證可用性(可靠性無法保證,如果此時主庫掛了,備庫恢復,發生HA切換,可能導致部分未同步的數據丟失)。
阿里雲RDS率先推出三節點方案,同時保證資料庫的高可靠和高可用,滿足了金融行業高可用和零數據丟失的需求。
三節點方案
可靠性保證:三節點方案中,用戶在提交事務時,需要等待至少一個備庫收到日誌副本,才返回給用戶事務成功結束的信號,確保資料庫的可靠性(用戶收到確認的事務,已持久化到多數派主機中)。
可用性保證:三節點方案中,即使一台伺服器掛掉(無論哪台),也不影響業務的可用性,因為已提交的數據至少有2份副本,掛掉一台,還有至少1台主機是包含了已提交事務的持久化內容的。
多節點引入的世界問題
多節點同時解決了可用性、可靠性的問題。但是實現並非易事,在解決可用性問題時,會涉及到另一個問題,因為異常時需要選出一個新的主庫,什麼情況下開始選舉?選誰?都是問題。
選主問題有一個非常著名的典故,拜占庭將軍的問題。
以下截取自互聯網:
拜占庭位於如今的土耳其的伊斯坦布爾,是東羅馬帝國的首都。由於當時拜占庭羅馬帝國國土遼闊,為了防禦目的,軍隊相隔很遠,將軍與將軍之間靠信差傳消息。進行軍事決策時,所有將軍必需達成 「一致的共識」。但是,在軍隊內有可能存有叛徒和敵軍的間諜,左右將軍們的決定,在進行共識時,結果並不一定代表大多數人的意見。於是在已知有成員不可靠的情況下,其餘忠誠的將軍在不受叛徒或間諜的影響下如何達成一致的協議,拜占庭問題就此形成。
拜占庭假設是對現實世界的模型化,由於硬體錯誤、網路擁塞或斷開以及遭到惡意攻擊,計算機和網路可能出現不可預料的行為。和我們提到的三節點要解決的問題是一致的。
下一篇將講解RDS三節點的理論基礎 - Raft協議。
二、理論篇
標籤
PostgreSQL , MySQL , 三節點版 , 金融資料庫 , Raft , 分散式共享存儲版
背景
上一篇說明了為什麼需要推出金融級資料庫的三節點版本,以及三節點引入的一個世界難題 - 拜占庭將軍問題。
Lamport 在論文 《The Part-Time Parliament》中提出了一種演算法Paxos,並使用了大量的數學公式論證了通過Paxos演算法解決拜占庭問題的可行性。緊接著在《Paxos Made Simple》論文中,則完全放棄了所有數學符號的證明,使用純英文的邏輯推導。原因是 Lamport 認為 Paxos 很 simple,但也許只是針對他的頭腦而言。事實是大家理解起來都還是很困難,所以 Raft 就是建立在希望得到一個更易於理解的 Paxos 演算法的替代品。把可理解性作為演算法的主要目標之一,從論文題目就可看出來《In Search of an Understandable Consensus Algorithm》。
拜占庭將軍的問題和三節點選舉主節點的問題類似,Raft是目前一種非常流行可靠(在有限前提下)的選舉演算法,也是RDS 金融資料庫(三節點版)的理論基礎,RDS對其演算法與資料庫進行融合,彌補了一些演算法的缺陷,實現了高可用、高可靠兼具的金融資料庫(三節點版)。
Raft 協議的易理解性描述
在一個由 Raft 協議組織的集群中有三類角色:
1、Leader(領袖)
2、Follower(群眾)
3、Candidate(候選人)
就像一個民主社會,領袖由民眾投票選出。剛開始沒有「領袖」,所有集群中的參與者都是「群眾」,那麼首先開啟一輪大選,在大選期間所有群眾都能參與競選,這時所有群眾的角色就變成了「候選人」,民主投票選出領袖後就開始了這屆領袖的任期,然後選舉結束,所有除領袖的候選人又變回群眾角色服從領袖領導。這裡提到一個概念「任期」,用術語 Term 表達(Term ID是自增的,每一輪成功的選舉都會產生一個新的Term ID,注意所有角色發現了新Term ID時自動服從他,解決了腦裂的問題)。關於 Raft 協議的核心概念和術語就這麼多而且和現實民主制度非常匹配,所以很容易理解。三類角色的變遷圖如下,結合後面的選舉過程來看很容易理解。
三種角色的轉變說明如下:1. Follower(群眾)
所有節點一開始都是Follower。
Follower在150ms ~ 300ms的隨機超時時間(Election Timeout)內,如果沒有收到任何Leader發過來的心跳消息,將會轉變為Candidate,給自己投票,同時請求其他人給自己投票,同時重置150ms ~ 300ms的隨機超時時間。
2. Candidate(候選人)
Candidate在150ms ~ 300ms的隨機超時時間內,沒有發生角色變化(即沒有轉換為new Leader的Follower,也沒有獲得足夠的票數轉換為Leader),那麼將重新發起選舉(給自己投票,同時請求其他人給自己投票,同時重置150ms ~ 300ms的隨機超時時間。)
在選舉過程中,Candidate獲得了多數票數,則轉換為new Leader。
Candiate發現了當前任期(自選任期)或更新任期的Leader時(即收到Leader發來的心跳),轉變為該Leader的Follower。
3. Leader(領袖)
Leader發現了更新任期的Leader時,轉變為新任期Leader的Follower。
客戶端視角事務的三種狀態
不管是三節點還是單節點,都可能會出現這幾種狀態。
- 提交、回滾成功。客戶端正常收到資料庫的事務結束的信號,明確事務成功按要求結束。
- UNKNOWN。客戶端發出了提交、回滾請求,但是未收到反饋。
- 提交失敗。客戶端收到事務結束失敗的信號,明確事務失敗。
無論是單節點還是多節點,都會有這三種事務狀態的可能存在。
Leader 選舉過程
在極簡的思維下,一個最小的 Raft 民主集群需要三個參與者(如下圖:A、B、C),這樣才可能投出多數票。初始狀態 ABC 都是 Follower,Follower在150ms ~ 300ms的隨機超時時間內,如果沒有收到任何Leader發過來的心跳消息,將會轉變為Candidate,給自己投票,同時請求其他人給自己投票,同時重置150ms ~ 300ms的隨機超時時間。
發起選舉這時有三種可能情形發生。下圖中前二種都能選出 Leader,第三種則表明本輪投票無效(Split Votes),每方都投給了自己,結果沒有任何一方獲得多數票。之後每個參與方隨機休息一陣(Election Timeout)重新發起投票直到一方獲得多數票。這裡的關鍵就是 隨機 timeout,最先從 timeout 中恢複發起投票的一方向還在 timeout 中的另外兩方請求投票,這時它們就只能投給對方了,很快達成一致。
選出 Leader 後,Leader 通過定期(heart timeout,heart timeout必須小於150ms)向所有 Follower 發送心跳信息維持其統治,每次Follower收到Leader心跳後,重置隨機Election Timeout。
若 Follower 一段時間(Election Timeout)未收到 Leader 的心跳則認為 Leader 可能已經掛了,Follower將發起選主(election)過程。
Leader 節點對一致性的影響
Raft 協議強依賴 Leader 節點的可用性來確保集群數據的一致性。數據的流向只能從 Leader 節點向 Follower 節點轉移。當 Client 向集群 Leader 節點提交數據後,Leader 節點接收到的數據處於未提交狀態(Uncommitted),接著 Leader 節點會並發向所有 Follower 節點複製數據並等待接收響應,確保至少集群中超過半數節點(quorum based)已接收到數據後再向 Client 確認數據已接收。一旦向 Client 發出數據接收 Ack 響應後,表明此時數據狀態進入已提交(Committed),Leader 節點再向 Follower 節點發通知告知該數據狀態已提交。
步驟4.1成功,客戶端就認為事務提交成功,換句話說事務已經持久化了。
因此4.2如果沒有發送成功,並且此時如果Leader異常,並發生了重新選舉,有沒有風險?New Leader的這筆事務到底是commit還是uncommit?
對於資料庫來說,只要事務的WAL日誌到位了,那麼就該事務就持久化了,由於Follower已經有了WAL,因此資料庫是不會讓這筆事務丟失的,這也是ACID的D持久化,即用戶看到COMMIT了,那就一定COMMIT了(開啟非同步提交遇到異常DOWN庫或DOWN機除外)。
在這個過程中,主節點可能在任意階段掛掉,看下 Raft 協議如何針對不同階段保障數據一致性的。1. 數據到達 Leader 節點前
這個階段 Leader 掛掉不影響一致性,不多說。
2. 數據到達 Leader 節點,但未複製到 Follower 節點
這個階段 Leader 掛掉,數據屬於未提交(uncommit)狀態,Client 不會收到 Ack 會認為超時事務失敗。Follower 節點上沒有該數據,重新選主後 Client 重試 (重新發起整個事務請求) 重新提交可成功。原來的 Leader 節點恢復後作為 Follower 加入集群重新從當前任期的新 Leader 處同步數據,強制保持和 NEW Leader 數據一致。
(為了達到一致,這裡涉及到OLD Leader rewind的操作。)
3. 數據到達 Leader 節點,成功複製到 Follower 所有節點,但還未向 Leader 響應接收
這個階段 Leader 掛掉,同時數據在 Follower 節點處於未提交狀態(Uncommitted)但保持一致,重新選出 Leader 後可完成數據提交,此時 Client 不知到底提交成功沒有,也就是說客戶端視角事務狀態為UNKNOWN。
但是對於NEW Leader,和OLD Leader的數據是一致的。
如何解決UNKNOWN的事務,後面的系列文章會講到。4. 數據到達 Leader 節點,成功複製到 Follower 部分節點,但還未向 Leader 響應接收
這個階段 Leader 掛掉,數據在 Follower 節點處於未提交狀態(Uncommitted)且不一致,Raft 協議要求投票只能投給擁有最新數據的節點。所以擁有最新數據的節點會被選為 Leader 再強制同步數據到其他 Follower,數據不會丟失並最終一致。
與第三種情況類似,此時 Client 不知到底提交成功沒有,也就是說客戶端視角事務狀態為UNKNOWN。
但是對於NEW Leader,和OLD Leader的數據是一致的。
5. 數據到達 Leader 節點,成功複製到 Follower 所有或多數節點,數據在 Leader 處於已提交狀態,但在 Follower 處於未提交狀態。(實際上就是圖中標註的4.2步驟沒有被執行)
這個階段 Leader 掛掉,重新選出新 Leader 後的處理流程和階段 3 一樣。
這個情況下,Follower實際上已經包含了最新的資料庫WAL日誌,NEW Leader只要APPLY WAL即可達到事務committed的最終狀態,不會丟失數據,也不會改變客戶端視角對事務提交成功狀態的認知。
6. 網路分區導致的腦裂情況,出現雙 Leader
網路分區將原先的 Leader 節點和 Follower 節點分隔開,Follower 收不到 Leader 的心跳將發起選舉產生新的 Leader。這時就產生了雙 Leader,原先的 Leader 獨自在一個區,向它提交數據不可能複製到多數節點所以「永遠提交不成功」
(雖然提交不成功,從資料庫WAL日誌角度來看,依舊可能出現 舊Leader 和 新Leader 存在差異的情況。例如 舊Leader 接收到某些請求,產生了WAL,只是提交事務的信息由於無法到達多數派,舊Leader是不會向客戶端返回commit ack的,因此向OLD Leader發起事務提交請求的客戶端會超時失敗。)。
客戶端向新的 Leader 提交數據可以提交成功。
網路恢復後 舊Leader 發現集群中有更新任期(Term)的新 Leader,舊Leader 自動降級為 Follower 並從 新Leader 處同步數據(對於資料庫,可能OLD Leader首先要rewind,然後才能從NEW Leader同步)達成集群數據一致。
一些邏輯定理:- 永遠不可能存在兩個Term ID相同的Leader,因為同一個Term ID每個角色只有一票,所以絕對只有一個Leader得到多數票。
- 如果同時存在兩個Leader,Term ID低的那個,事務提交一定會超時,因為它的Follower一定是不足的,副本數不足,永遠不會返回Client ack。
綜上窮舉分析了最小集群(3 節點)面臨的所有情況,可以看出 Raft 協議都能很好的應對一致性問題,並且很容易理解。
但是要結合資料庫和Raft,實現金融級零數據丟失和一致性的資料庫多副本產品,會更加複雜,例如rewind,以及UNKNOWN事務的處理(即使是單節點,依舊需要處理unknown事務)。
總結
演算法以正確性、高效性、簡潔性作為主要設計目標。
雖然這些都是很有價值的目標,但這些目標都不會達成直到開發者寫出一個可用的實現。
所以我們相信可理解性同樣重要。
Raft 演算法是 2013 年發表的,大家在參考[5]上面可以看到有多少個不同語言開源的實現庫了,這就是演算法可理解性的重要性。
阿里雲RDS金融資料庫(三節點版)以Raft協議為基礎,將重做日誌的複製、選主與Raft進行結合,打造了一個可以同時滿足可用性、可靠性,並保持高性能的金融級的資料庫。
參考
[1]. LESLIE LAMPORT, ROBERT SHOSTAK, MARSHALL PEASE. The Byzantine General Problem. 1982
[2]. Leslie Lamport. The Part-Time Parliament. 1998
[3]. Leslie Lamport. Paxos Made Simple. 2001
[4]. Diego Ongaro and John Ousterhout. Raft Paper. 2013
[5]. Raft Website. The Raft Consensus Algorithm
[6]. Raft Demo. Raft Animate Demo
[7]. Raft 為什麼是更易理解的分散式一致性演算法
系列文章
《阿里雲RDS金融資料庫(三節點版) - 背景篇》
《阿里雲RDS金融資料庫(三節點版) - 理論篇》
《阿里雲RDS金融資料庫(三節點版) - 性能篇》
《阿里雲RDS金融資料庫(三節點版) - 案例篇》
阿里雲RDS金融資料庫(三節點版)
阿里雲RDS金融資料庫 - MySQL三節點版
阿里雲RDS金融資料庫 - PostgreSQL三節點版(敬請期待)
推薦閱讀:
※PostgreSQL 在國內公司應用的多嗎?
※Vert.x裡面那些b格很高的玩意
※PG(PostgreSQL)在一捅到底架構中的使用
TAG:数据存储技术 | 数据库 | PostgreSQL |