分散式強一致性資料庫的靈魂 - Raft 演算法

IT大咖說發表於2018-05-31

分散式強一致性資料庫的靈魂 - Raft 演算法

內容來源:2017 年 11 月 18 日,PingCAP首席架構師唐劉在“資料技術嘉年華——分會場五:雲架構、資料架構”進行《分散式強一致性資料庫的靈魂 - Raft 演算法的理論和實踐》演講分享。IT 大咖說(微信id:itdakashuo)作為獨家視訊合作方,經主辦方和講者審閱授權釋出。

閱讀字數:3258 | 10分鐘閱讀

嘉賓演講視訊及PPT回顧:t.cn/RmTm6GF

摘要

Raft 分散式一致性演算法在 2013 年釋出,以容易理解、實現方式明確的特點,迅速在業界流行起來。本次分享將介紹 TiDB 如何使用 Raft 演算法構建分散式可擴充套件的後端儲存系統,以及 TiDB 在可靠性、可用性、效能等方面對 Raft 做的工程優化。

Why Ralf

假設我們有某一個業務要實現資料儲存方面的功能,最簡單方法就是實現一個節點,所有的資料讀寫都是通過這一個節點。但是這樣會存在各種各樣的問題,比如資料量增大後無法承受壓力,單節點如何向多節點分佈,資料的一致性怎麼保證,最嚴重的就是資料節點掛掉,資料全部丟失了。

Replication

為了解決節點損壞的問題,業界通用的方案是採用Replication,在Master寫資料的時候掛多個Slave,寫完後保證將log同步到Slave,這樣的流程下來才能認為寫入是成功的。

通常情況下為了保證效能,我們都會使用非同步複製(Async Replication),不過會產生一些問題。當Master掛掉了之後很有可能有些資料並沒有同步到Slave,這時候如果把這個Slave提升到新的Master就會面臨資料丟失的問題。

強同步(Sync Replication)解決了非同步複製(Async Replication)可能潛在的問題。Master寫入資料後必須保證Slave接收到log寫入才算成功,當然這樣會損耗一些效能,不過最嚴重在於Master掛掉後,Slave提升為Master,單節點的問題就又出現了。

為了保證系統中N臺節點掛掉後,仍然能夠對外提供服務,至少需要2N+1臺機器,也就是傳統的Quorum,這樣最少就需要三臺機器,但是數量的增大也會帶來更多的問題。

首先Master掛掉後要需要判斷該提升哪個Slave為新的Master。另外在多型叢集下還容易遇到一個問題,就是在網路情況下以前的Master出現網路隔離,還在繼續對外提供服務,而這時新的叢集和Master已經形成了,新的資料被寫入到新的Master,可是讀取的卻是舊的資料,這就是在分散式一致性領域所面臨的線性一致性問題。

Consensus Algorithm

一致性演算法(Consensus Alogrithm)就是為了解決分散式叢集所面臨的諸多問題而準備的。它保證了系統在多個狀態上的Agreement,另外在叢集的大部分節點掛掉後能夠保證資料一致性。

Raft

Replicated State Machine

大多數的一致性演算法其實都是採用了Replicated State Machine的模型。對於這個模型你可以認為資料是被放在狀態機上,使用者操作叢集時 首先需要寫入log,然後通過一致性演算法將log複製到其他機器,一旦確定其他機器都接收到log後就會認為該log被提交了,最後其他節點會依次將log存放到狀態機。

State

Raft有著三個狀態,第一個狀態就是Leader,即使Raft Group存在多個節點,Leader也只會存在一個,也只有Leader能負責所有資料的讀寫,這樣就不會出現線性一致性的問題。

當一個叢集選出了Leader後其他叢集的節點都會變成Follow,這個Follow只負責一件事就是接收Leader的Replication logs。當一個Follow沒有接收到資料或者發現叢集中沒有Leader的時候,就會進入Candidate狀態,這個狀態表示可以開始選舉了。

Term

Raft是不依賴系統的時間,它是將時間分成一個個Term,每個Term可以是任意長度,每次Term開始的時候都是由一次新的選舉產生的,然後在這個Term內選出一個Leader,該Leader會一直服務到所在Leader結束。

結合Raft Term就可以進行Raft的選舉。首先當系統啟動後所有的節點都會進入Follow狀態,Follow沒有接收到任何請求的話,過一段時間就會進入Candidate狀態,然後詢問其他節點是否投票,如果其他節點反饋已經有新的Leader,這個Candidate就會變成Follow,而當Candidate接收到大多數的投票後就會變成Leader,之後會立即將一個log傳送給其他節點開始續租Leader的時間租約。

Log Replication

一個新的Leader被選出來之後就會開始工作了,它會不停的去接收客戶端傳送過來的請求,這些請求都會通過log落地,而這些log一定要是單調遞增,以保證資料的一致性。

之後log會被複制到其他的節點,絕大多數節點都接收到這個log後, Leader就認為該log是committed的。

Membership Change

對於分散式叢集來說新增節點其實是分成困難的操作,最常見的做法是先更改配置中心,然後將新的配置同步到舊的節點。不過這樣在同步配置的時候,就需要停止外部服務。而Raft採用了一種動態的成員節點變更,它會將新的節點到當作Raft log通過Leader傳遞給其他節點,這樣其他節點就知道了這個新的節點的資訊。不過這個過程中有可能會在某一階段出現2個Leader的情況,為了避免這種情況就要每次只變更一個節點,而不進行多節點變更。

Raft也提供了一種多節點變更的演算法,它是一種兩階段提交,Leader在第一階段會同時將新舊叢集的配置同時當成一個Raft log傳送給其他舊叢集節點,當這些節點接收到資料後就會和新的叢集節點進入join狀態,所有的操作都要進過新舊叢集的大多數節點同意才會執行,然後在新的join狀態內重新提交新的配置資訊,在配置被committed後新的節點會上線,舊的節點會下線。

Optimization

Pre-Vote

在Follow處於網路抖動無法接受到Leader的訊息的時候,它就會變成Candidate並且Term加一,但是其他叢集其實還是在正常工作的,這樣整個叢集的就混亂了。

Pre-Vote機制會在Follow沒有接收到Leader的訊息並且開始投票之前進入Pre-Candidate狀態,在想其他節點傳送投票請求,並獲得同意後才會進入Candidate狀態。

Pipeline

正常的Raft流程中,客戶端事先給Leader寫入資料,Leader處理後會追加到log中,追加成功後Replication到其他節點中,­當Leader發現log被整個叢集大多數節點接收後就會進行Apply。

這樣的一個過程其實是非常低效的,所以就需要引入Pipeline,它可以將多個請求進行併發處理,有效提高效率。

Batch

通常情況下接收到的客戶端請求都是依次過來的,而當有一批請求過來的時候,就可以通過Batch將這些請求打包成一個Raft log傳送出去。

Multi-Raft

當目前的Raft Group無法支撐所有的資料的時候,就需要引入Multi-Raft處理資料,第一種做法是將資料切分成多個Raft Group分擔到不同的機器上。

為了應對更復雜的情況就需要使用動態分裂的方法,假設最開始的只有3臺機器以及一個Region,這個Region就佈置在一臺機器上,所有的資料都寫入這臺機器,當資料量達到某個預值後Region就產生分裂,得到的新的Region就可以移植到新的機器上。


相關文章