可靠分布式系統(tǒng)- paxos 的直觀解釋
前言
paxos 是什么?
在分布式系統(tǒng)中保證多副本數(shù)據(jù)強(qiáng)一致的算法。
paxos 有啥用?
沒有 paxos 的一堆機(jī)器, 叫做分布式;
有 paxos 協(xié)同的一堆機(jī)器, 叫分布式系統(tǒng)。
Google Chubby 的作者 Mike Burrows 說過:
這個世界上只有一種一致性算法,那就是Paxos …
其他一致性算法, 都可以看做 paxos 在實現(xiàn)中的變體和擴(kuò)展。
另外一個經(jīng)常被提及的分布式算法是【raft】,raft 的貢獻(xiàn)在于把一致性算法落地。因為【Leslie Lamport】的理論很抽象,要想把他的理論應(yīng)用到現(xiàn)實中,還需要工程師完全掌握他的理論再添加工程必要的環(huán)節(jié)才能跑起來。
經(jīng)常有人問起 raft 和 paxos 的區(qū)別,或在實現(xiàn)中應(yīng)該選擇哪個,在不了解 paxos 之前可能會有這種疑問。對于這個問題, 就像是被問及四則運算和算盤有什么區(qū)別,小店老板應(yīng)該使用四則運算還是用算盤結(jié)賬一樣。
記得 Leslie Lamport 2015 年時來了一次北京,那時會場上有人也問了老爺子 paxos 和 raft 有啥區(qū)別。老爺子當(dāng)時給出的回答是:沒聽過 raft…

raft 的核心可以認(rèn)為是 multi paxos 的一個應(yīng)用,對于要掌握一致性算法的核心內(nèi)容,從 paxos 入手,更容易去掉無關(guān)干擾,直達(dá)問題本質(zhì)。所以我們選擇 paxos 作為了解一致性算法的入口,聊開了聊透了。
網(wǎng)絡(luò)上 raft 比 paxos 流行,因為 raft 的描述更直白一些,實際上 raft比 paxos 更復(fù)雜。raft 詳細(xì)的解釋了“HOW”,缺少“WHY”的解釋。paxos 從根本上解釋清楚了“WHY”,但一直缺少一份通俗易懂的教程,以至于沒有被更廣泛的接受。所以就有了本文,一篇 paxos 入門教程,從基本的分布式中的復(fù)制的問題出發(fā),通過逐步解決和完善這幾個問題,最后推導(dǎo)出 paxos 的算法。
本文分為 2 個部分:
前 1 部分是分布式一致性問題的討論和解決方案的逐步完善,用人話得出 paxos 算法的過程。如果只希望理解 paxos 而不打算花太多時間深入細(xì)節(jié), 只閱讀這 1 部分就可以啦。
第 2 部分是 paxos 算法和協(xié)議的嚴(yán)格描述。這部分可以作為 paxos 原 paper 的實現(xiàn)部分的概括。如果你打算實現(xiàn)自己的 paxos 或類似協(xié)議。需要仔細(xì)了解協(xié)議細(xì)節(jié),希望這部分內(nèi)容可以幫你節(jié)省閱讀原 paper 的時間。
圖片是 xp 之前做過的 paxos 分享使用的 slides,在此基礎(chǔ)上加入了更多口頭解釋的內(nèi)容。分布式系統(tǒng)要解決的問題
分布式系統(tǒng)要解決的問題
slide-01
paxos 的工作,就是把一堆運行的機(jī)器協(xié)同起來,讓多個機(jī)器成為一個整體系統(tǒng)。在這個系統(tǒng)中,每個機(jī)器都必須讓系統(tǒng)中的狀態(tài)達(dá)成一致,例如三副本集群如果一個機(jī)器上上傳了一張圖片,那么另外 2 臺機(jī)器上也必須復(fù)制這張圖片過來。整個系統(tǒng)才處于一個一致的狀態(tài)。

slide-02
我是無需解釋的目錄頁。

lide-03
分布式系統(tǒng)的一致性問題最終都?xì)w結(jié)為分布式存儲的一致性。像 aws 的對象存儲可靠性要求是 9 ~ 13 個 9。
而這么高的可靠性都是建立在可靠性沒那么高的硬件上的。

slide-04
幾乎所有的分布式存儲(甚至單機(jī)系統(tǒng)),參考【EC 第一篇:原理】,【EC 第二篇:實現(xiàn)】,【EC第三篇:極限】 都必須用某種冗余的方式在廉價硬件的基礎(chǔ)上搭建高可靠的存儲。而冗余的基礎(chǔ)就是多副本策略,一份數(shù)據(jù)存多份。多副本保證了可靠性,而副本之間的一致,就需要 paxos 這類分布式一致性算法來保證。

slide-05
在早些年各種各樣的復(fù)制策略都被提出來來解決各種場景下的需要。除了復(fù)制的份數(shù)之外,各種各樣的算法實際上都是在嘗試解決一致的問題。從下一頁開始簡單回顧下各種復(fù)制策略,看看他們的優(yōu)缺點以及 paxos 如何解決副本之間一致性的問題。

不太完美的復(fù)制策略
slide-06
無需解釋的目錄頁

slide-07
主從異步復(fù)制是最簡單的策略之一,它很容易實現(xiàn),但存在一個問題:客戶端收到一個數(shù)據(jù)已經(jīng)安全(OK)的信息,跟數(shù)據(jù)真正安全(數(shù)據(jù)復(fù)制到全部的機(jī)器上)在時間上有一個空隙,這段時間負(fù)責(zé)接收客戶端請求的那個機(jī)器(master)如果被閃電擊中或被隕石砸到或被打掃衛(wèi)生的大姐踢斷了電源,那數(shù)據(jù)就可能會丟失。因此它不是一個可靠的復(fù)制策略(使用主從異步復(fù)制要求你必須相信宇宙中不存在閃電隕石和掃地大姐)。

slide-08
跟主從異步復(fù)制相比,主從同步復(fù)制提供了完整的可靠性:直到數(shù)據(jù)真的安全的復(fù)制到全部的機(jī)器上之后,master 才告知客戶端數(shù)據(jù)已經(jīng)安全。但主從同步復(fù)制有個致命的缺點就是整個系統(tǒng)中有任何一個機(jī)器宕機(jī),寫入就進(jìn)行不下去了。相當(dāng)于系統(tǒng)的可用性隨著副本數(shù)量指數(shù)降低。

slide-09
然鵝,在同步和異步之間,做一個折中,看起來是一個不錯的方案。這就是半同步復(fù)制。它要求 master 在應(yīng)答客戶端之前必須把數(shù)據(jù)復(fù)制到足夠多的機(jī)器上,但不需要是全部。這樣副本數(shù)夠多可以提供比較高的可靠性;1臺機(jī)器宕機(jī)也不會讓整個系統(tǒng)停止寫入。但是它還是不完美,例如數(shù)據(jù) a 復(fù)制到 slave-1,但沒有到達(dá) slave-2;數(shù)據(jù) b 復(fù)制達(dá)到了 slave-2 但沒有到達(dá) slave-1,這時如果 master 掛掉了需要從某個 slave 恢復(fù)出數(shù)據(jù),任何一個 slave 都不能提供完整的數(shù)據(jù)。所以在整個系統(tǒng)中,數(shù)據(jù)存在某種不一致。

slide-10
為了解決半同步復(fù)制中數(shù)據(jù)不一致的問題,可以將這個復(fù)制策略再做一改進(jìn):多數(shù)派讀寫:每條數(shù)據(jù)必須寫入到半數(shù)以上的機(jī)器上。每次讀取數(shù)據(jù)都必須檢查半數(shù)以上的機(jī)器上是否有這條數(shù)據(jù)。在這種策略下,數(shù)據(jù)可靠性足夠,宕機(jī)容忍足夠,任一機(jī)器故障也能讀到全部數(shù)據(jù)。

slide-11
然鵝多數(shù)派讀寫的策略也有個但是,就是對于一條數(shù)據(jù)的更新時,會產(chǎn)生不一致的狀態(tài)。例如:
node-1,node-2 都寫入了 a=x
下一次更新時 node-2,node-3 寫入了 a=y
這時,一個要進(jìn)行讀取 a 的客戶端如果聯(lián)系到了 node- 1和 node-2,它將看到 2 條不同的數(shù)據(jù)。為了不產(chǎn)生歧義,多數(shù)派讀寫還必須給每筆寫入增加一個全局遞增的時間戳。更大時間戳的記錄如果被看見,就應(yīng)該忽略小時間戳的記錄。這樣在讀取過程中,客戶端就會看到 a=x?,a=y? 這 2 條數(shù)據(jù),通過比較時間戳 1 和 2 發(fā)現(xiàn) y 是更新的數(shù)據(jù),所以忽略 a=x? 這樣保證多次更新一條數(shù)據(jù)不產(chǎn)生歧義。

slide-12
是的,但是又來了。這種帶時間戳的多數(shù)派讀寫依然有問題。就是在客戶端沒有完成一次完整的多數(shù)派寫的時候:例如,上面的例子中寫入 a=x? 寫入了 node-1 和 node-2,a=y? 時只有 node-3 寫成功了,然后客戶端進(jìn)程就掛掉了,留下系統(tǒng)中的狀態(tài)如下:

這時另一個讀取的客戶端來了:
如果它聯(lián)系到 node-1 和 node-2,那它得到的結(jié)果是 a=x?
如果它聯(lián)系到 node-2 和 node-3,那它得到的結(jié)果是 a=y?
整個系統(tǒng)對外部提供的信息仍然是不一致的

slide-13
現(xiàn)在我們已經(jīng)非常接近最終奧義了,paxos 可以認(rèn)為是多數(shù)派讀寫的進(jìn)一步升級,paxos 中通過 2 次原本并不嚴(yán)謹(jǐn)?shù)亩鄶?shù)派讀寫,實現(xiàn)了嚴(yán)謹(jǐn)?shù)膹?qiáng)一致 consensus 算法。

從多數(shù)派讀寫到 paxos 的推導(dǎo)
slide-14
首先為了清晰的呈現(xiàn)出分布式系統(tǒng)中的核心問題:一致性問題, 我們先設(shè)定一個假象的存儲系統(tǒng),在這個系統(tǒng)上,我們來逐步實現(xiàn)一個強(qiáng)一致的存儲,就得到了 paxos 對一致性問題的解決方法。

slide-15
在實現(xiàn)中,set 命令直接實現(xiàn)為一個多數(shù)派寫,這一步非常簡單。而 inc 操作邏輯上也很簡單,讀取一個變量的值 i?,給它加上一個數(shù)字得到 i?,再通過多數(shù)派把 i? 寫回到系統(tǒng)中。

slide-16
冰雪如你一定已經(jīng)看到了這種實現(xiàn)方式中的問題:如果有 2 個并發(fā)的客戶端進(jìn)程同時做這個 inc 的操作,在多數(shù)派讀寫的實現(xiàn)中,必然會產(chǎn)生一個 Y 客戶端覆蓋 X 客戶端的問題,從而產(chǎn)生了數(shù)據(jù)更新點的丟失。而 paxos 就是為了解決這類問題提出的,它需要讓 Y 能檢測到這種并發(fā)沖突,進(jìn)而采取措施避免更新丟失。

slide-17
提取一下上面提到的問題:讓 Y 去更新的時候不能直接更新 i? 而是應(yīng)該能檢測到 i? 的存在,進(jìn)而將自己的結(jié)果保存在下一個版本 i? 中,再寫回系統(tǒng)中。而這個問題可以轉(zhuǎn)化成:i 的每個版本只能被寫入一次,不允許修改。如果系統(tǒng)設(shè)計能滿足這個要求,那么 X 和 Y 的 inc 操作就都可以正確被執(zhí)行了。

slide-18
于是我們的問題就轉(zhuǎn)化成一個更簡單,更基礎(chǔ)的問題:如何確定一個值(例如 i?)已經(jīng)被寫入了。直觀來看,解決方法也很簡單,在 X 或 Y 寫之前先做一次多數(shù)派讀,以便確認(rèn)是否有其他客戶端進(jìn)程已經(jīng)在寫了,如果有,則放棄。

slide-19
但是!?這里還有個并發(fā)問題,X 和 Y 可能同時做這個寫前讀取的操作,并且同時得出一個結(jié)論:還沒有其他進(jìn)程在寫入,我可以寫。這樣還是會造成更新丟失的問題。
slide-20
為了解決上面的問題,存儲節(jié)點還需要增加一個功能,就是它必須記住誰最后一個做過寫前讀取的操作。并且只允許最后一個完成寫前讀取的進(jìn)程可以進(jìn)行后續(xù)寫入,同時拒絕之前做過寫前讀取的進(jìn)程寫入的權(quán)限。
可以看到,如果每個節(jié)點都記得誰讀過,那么當(dāng) Y 最后完成了寫前讀取的操作后,整個系統(tǒng)就可以阻止過期的 X 的寫入。
這個方法之所以能工作也是因為多數(shù)派寫中,一個系統(tǒng)最多只能允許一個多數(shù)派寫成功。paxos 也是通過 2 次多數(shù)派讀寫來實現(xiàn)的強(qiáng)一致。
slide-21
以上就是 paxos 算法的全部核心思想了,是不是很簡單?剩下的就是如何實現(xiàn)的簡單問題了:如何標(biāo)識一個客戶端如 X 和 Y,如何確認(rèn)誰是最后一個完成寫前讀寫的進(jìn)程,等等。
slide-22
【Leslie Lamport】就這么把這么簡單的一個算法寫了個 paper 就獲得了圖領(lǐng)獎!騷年,改變世界就這么容易!
paxos 算法描述
接下來的篇幅中我們將用計算機(jī)的語言準(zhǔn)確的描述整個 paxos 運行的過程。
slide-23
首先明確要解決的問題:
slide-24
我們要介紹的 paxos 實際上是最樸實的 classic paxos,在這之后我們順提下幾個老爺子對 paxos 的優(yōu)化,multi paxso 和 fast paxos,它們都是針對 paxos 的理論層面的優(yōu)化。
slide-25
paxos 算法中解決了如何在不可靠硬件基礎(chǔ)上構(gòu)建一個可靠的分布式系統(tǒng)的方法。但 paxos 核心算法中只解決網(wǎng)絡(luò)延遲/亂序的問題,它不試圖解決存儲不可靠和消息錯誤的問題,因為這兩類問題本質(zhì)上跟分布式關(guān)系不大,屬于數(shù)據(jù)校驗層面的事情。有興趣可以參考【Byzantine Paxos】的介紹。
slide-26
本文盡量按照【Classic Paxos】的術(shù)語來描述。
老爺子后面的一篇 【Fast Paxos】實現(xiàn)了 fast-paxos,同時包含了 classic-paxos,但使用了一些不同的術(shù)語表示。
Proposer 可以理解為客戶端。
Acceptor 可以理解為存儲節(jié)點。
Quorum 在 99% 的場景里都是指多數(shù)派,也就是半數(shù)以上的 Acceptor。
Round 用來標(biāo)識一次 paxos 算法實例,每個 round 是 2 次多數(shù)派讀寫:算法描述里分別用 phase-1 和 phase-2 標(biāo)識。同時為了簡單和明確,算法中也規(guī)定了每個 Proposer 都必須生成全局單調(diào)遞增的 round,這樣 round既能用來區(qū)分先后也能用來區(qū)分不同的 Proposer(客戶端)。
slide-27
在存儲端(Acceptor)也有幾個概念:
last_rnd 是 Acceptor 記住的最后一次進(jìn)行寫前讀取的 Proposer(客戶端)是誰,以此來決定誰可以在后面真正把一個值寫到存儲中。
v 是最后被寫入的值。
vrnd 跟 v 是一對,它記錄了在哪個 Round 中 v 被寫入了。
v 和 vrnd 是用于恢復(fù)一次未完成的 paxos 用的。一次未完成的 paxos 算法運行可能留下一些沒有達(dá)到多數(shù)派的值的寫(就像原生的多數(shù)派寫的臟讀的問題), paxos 中通過 vrnd 來決定哪些值是最后寫入的,并決定恢復(fù)哪個未完成的 paxos 運行。后面我們會通過幾個例子來描述 vrnd 的作用。
slide-28
首先是 paxos 的 phase-1,它相當(dāng)于之前提到的寫前讀取過程。它用來在存儲節(jié)點(Acceptor)上記錄一個標(biāo)識:我后面要寫入;并從 Acceptor 上讀出是否有之前未完成的 paxos 運行。如果有則嘗試恢復(fù)它;如果沒有則繼續(xù)做自己想做的事情。
我們用類似 yaml 的格式來描述 phase-1 的請求/應(yīng)答的格式:
phase-1 成功后,acceptor 應(yīng)該記錄 X 的 rnd=1,并返回自己之前保存的 v 和 vrnd。
slide-29
Proposer X 收到多數(shù)(quorum)個應(yīng)答,就認(rèn)為是可以繼續(xù)運行的。如果沒有聯(lián)系到多于半數(shù)的 acceptor,整個系統(tǒng)就 hang 住了,這也是 paxos 聲稱的只能運行少于半數(shù)的節(jié)點失效。這時 Proposer 面臨 2 種情況:
所有應(yīng)答中都沒有任何非空的 v,這表示系統(tǒng)之前是干凈的,沒有任何值已經(jīng)被其他 paxos 客戶端完成了寫入(因為一個多數(shù)派讀一定會看到一個多數(shù)派寫的結(jié)果),這時 Proposer X 繼續(xù)將它要寫的值在 phase-2 中真正寫入到多于半數(shù)的 Acceptor 中。
如果收到了某個應(yīng)答包含被寫入的 v 和 vrnd,這時,Proposer X 必須假設(shè)有其他客戶端(Proposer)正在運行,雖然 X 不知道對方是否已經(jīng)成功結(jié)束, 但任何已經(jīng)寫入的值都不能被修改!所以 X 必須保持原有的值。于是 X 將看到的最大 vrnd 對應(yīng)的 v 作為 X 的 phase-2 將要寫入的值。這時實際上可以認(rèn)為 X 執(zhí)行了一次(不知是否已經(jīng)中斷的)其他客戶端(Proposer)的修復(fù)。
slide-30
在第 2 階段 phase-2,Proposer X 將它選定的值寫入到 Acceptor ,這個值可能是它自己要寫入的值,或者是它從某個 Acceptor 上讀到的 v(修復(fù))。同樣用類似 yaml 的方式描述請求應(yīng)答:
slide-31
當(dāng)然這時(在 X 收到 phase-1 應(yīng)答,到發(fā)送 phase-2 請求的這段時間),可能已經(jīng)有其他 Proposer 又完成了一個 rnd 更大的 phase-1,所以這時 X 不一定能成功運行完 phase-2。
Acceptor 通過比較 phase-2 請求中的 rnd,和自己本地記錄的 rnd,來確定 X 是否還有權(quán)寫入。如果請求中的 rnd 和 Acceptor 本地記錄的 rnd 一樣,那么這次寫入就是被允許的, Acceptor 將 v 寫入本地,并將 phase-2 請求中的 rnd 記錄到本地的 vrnd 中。

用例子看 paxos 運行
好了,paxos 的算法描述也介紹完了。這些抽象的算法描述,其中的規(guī)則覆蓋了實際所有可能遇到的情況的處理方式。一次不太容易看清楚它們的作用,所以我們接下來通過幾個例子來看看 paxos 如何處理各種不同狀態(tài)并最終使整個系統(tǒng)的狀態(tài)達(dá)成一致。
slide-32
沒沖突的例子不解釋了

slide-33
X 和 Y 同時運行 paxos,Y 迫使 X 中斷的例子:
X 成功完成了寫前讀取(phase-1),將 rnd=1 寫入到左邊 2 個 Acceptor。
Y 用更大的 rnd=2,覆蓋了 X 的 rnd,將 rnd=2 寫入到右邊 2 個Acceptor。
X 以為自己還能運行 phase-2,但已經(jīng)不行了,X 只能對最左邊的 Acceptor 成功運行 phase-2,而中間的 Acceptor 拒絕了 X 的 phase-2。
Y 對右邊 2 個 Acceptor 成功運行了 phase-2,完成寫入 v=y,vrnd=2。

slide-34
繼續(xù)上面的例子,看 X 如何處理被搶走寫入權(quán)的情況:這時 X 的 phase-2 沒成功,它需要重新來一遍,用更大的 rnd=3。
X 成功在左邊 2 個 Acceptor 上運行 phase-1 之后,X 發(fā)現(xiàn)了 2 個被寫入的值:v=x,vrnd=1 和 v=y,vrnd=2;這時 X 就不能再寫入自己想要寫入的值了。它這次 paxos 運行必須不能修改已存在的值,這次 X 的 paxos 的運行唯一能做的就是,修復(fù)(可能)已經(jīng)中斷的其他 proposer 的運行。
這里 v=y,vrnd=2 是可能在 phase-2 達(dá)到多數(shù)派的值。v=x,vrnd=1 不可能是,因為其他 proposer 也必須遵守算法約定,如果 v=x,vrnd=1 在某個 phase-2 達(dá)到多數(shù)派了,Y 一定能在 phase-1 中看到它,從而不會寫入 v=y, vrnd=2。
因此這是 X 選擇 v=y,并使用 rnd=3 繼續(xù)運行,最終把 v=y,vrnd=3 寫入到所有 Acceptor 中。

slide-35
Paxos 還有一個不太重要的角色 Learner,是為了讓系統(tǒng)完整加入的,但并不是整個算法執(zhí)行的關(guān)鍵角色,只有在最后在被通知一下。

Paxos 優(yōu)化
slide-36
第一個優(yōu)化?multi-paxos:
paxos 誕生之初為人詬病的一個方面就是每寫入一個值就需要 2 輪 rpc:phase-1 和 phase-2。因此一個尋常的優(yōu)化就是用一次 rpc 為多個 paxos 實例運行 phase-1。
例如,Proposer X 可以一次性為 i?~i?? 這 10 個值, 運行 phase-1,例如為這 10 個 paxos 實例選擇 rnd 為 1001,1002…1010,這樣就可以節(jié)省下 9 次 rpc,而所有的寫入平均下來只需要 1 個 rpc 就可以完成了。這么看起來就有點像 raft 了:
再加上 commit 概念(commit可以理解為: 值v送達(dá)到多數(shù)派這件事情是否送達(dá)到多數(shù)派了)
和組成員變更(將 quorum 的定義從“多于半數(shù)”擴(kuò)展到“任意2個quourm必須有交集”)

slide-37
第二個優(yōu)化?fast-paxos:
fast-paxos 通過增加 quorum 的數(shù)量來達(dá)到一次 rpc 就能達(dá)成一致的目的。如果 fast-paxos 沒能在一次 rpc 達(dá)成一致,則要退化到 classic paxos。

slide-38
fast-paxos 為了能在退化成 classic paxos 時不會選擇不同的值, 就必須擴(kuò)大 quorum 的值。也就是說 fast-round 時,quorum 的大小跟 classic paxos 的大小不一樣。同樣我們先來看看為什么 fast-quorum 不能跟 classic-quorum 一樣,這樣的配置會引起 classic 階段回復(fù)時選擇錯誤的值 y?:

slide-39
要解決這個問題,最粗暴的方法是把 fast-quorum 設(shè)置為 n,也就是全部的 acceptor 都寫入成功才認(rèn)為 fast-round 成功(實際上是退化到了主從同步復(fù)制)。這樣,如果 X 和 Y 兩個 proposer 并發(fā)寫入,誰也不會成功,因此 X 和 Y 都退化到 classic paxos 進(jìn)行修復(fù),選任何值去修復(fù)都沒問題。因為之前沒有 Proposer 認(rèn)為自己成功寫入了。
如果再把問題深入下,可以得出,如果 classic paxos 的 quorum 是 n/2+1,那么 fast-round 的 quorum 應(yīng)該是大于 ?n,? 的由來可以簡單理解為:在最差情況下,達(dá)到 fast-quorum 的 acceptor 在 classic-quorum 中必須大于半數(shù),才不會導(dǎo)致修復(fù)進(jìn)程選擇一個跟 fast-round 不同的值。

slide-40
下面是一個 fast-round 中 X 成功,Y 失敗的沖突的例子:X 已經(jīng)成功寫入到 4(fast-quorum>?n)個 acceptor,Y 只寫入 1 個,這時 Y 進(jìn)入 classic-round 進(jìn)行修復(fù),可以看到,不論 Y 選擇哪 3(classic quorum)個 acceptor,都可以看到至少 2 個 x?,因此 Y 總會選擇跟 X 一樣的值,保證了寫入的值就不會被修改的條件。

slide-41
再來看一個 X 和 Y 都沒有達(dá)到 fast-quorum 的沖突:這時 X 和 Y 都不會認(rèn)為自己的 fast-round 成功了,因此修復(fù)過程選擇任何值都是可以的。最終選擇哪個值,就回歸到 X 和 Y 兩個 classic-paxos 進(jìn)程的競爭問題了。最終會選擇 x? 或 y? 中的一個。

其他
slide-42
一個很容易驗證的優(yōu)化,各種情況下都能得到一致的結(jié)果。

參考鏈接
[raft]:https://raft.github.io/
[Leslie Lamport]:http://www.lamport.org/
[Byzantine Paxos]:https://en.wikipedia.org/wiki/Paxos_(computer_science)#Byzantine_Paxos
[Classic Paxos]:http://lamport.azurewebsites.net/pubs/pubs.html#paxos-simple
[Fast Paxos]:http://lamport.azurewebsites.net/pubs/pubs.html#fast-paxos
[EC第一篇:原理]:https://blog.openacid.com/storage/ec-1
[EC第二篇:實現(xiàn)]:https://blog.openacid.com/storage/ec-2
[EC第三篇:極限]:https://blog.openacid.com/storage/ec-3
關(guān)于 Databend
Databend 是一款開源、彈性、低成本,基于對象存儲也可以做實時分析的新式數(shù)倉。期待您的關(guān)注,一起探索云原生數(shù)倉解決方案,打造新一代開源 Data Cloud。
Databend 文檔:https://databend.rs/
twitter:https://twitter.com/Datafuse_Labs
Slack:https://datafusecloud.slack.com/
Wechat:Databend
GitHub :https://github.com/datafuselabs/databend
