訂閱
糾錯(cuò)
加入自媒體

分布式系統(tǒng):?jiǎn)栴}及其可復(fù)用的解決方案

作者:  Unmesh Joshi

譯者:  java達(dá)人

在過(guò)去的幾個(gè)月中,我一直在ThoughtWorks上進(jìn)行有關(guān)分布式系統(tǒng)的研討會(huì)。舉辦研討會(huì)時(shí)面臨的主要挑戰(zhàn)之一是如何將分布式系統(tǒng)的理論映射到諸如Kafka或Cassandra之類的開(kāi)源代碼庫(kù),同時(shí)保持研討的通用性足以涵蓋廣泛的解決方案。模式的概念提供了一個(gè)不錯(cuò)的方式。

模式結(jié)構(gòu)本質(zhì)上使我們能夠?qū)W⒂谔囟▎?wèn)題,從而很清楚地說(shuō)明了為什么需要特定解決方案。然后,解決方案描述中給出一個(gè)代碼結(jié)構(gòu),該結(jié)構(gòu)足夠具體以顯示實(shí)際的解決方案,但又足夠通用以涵蓋各種變體。模式技術(shù)還允許我們將各種模式鏈接在一起以構(gòu)建一個(gè)完整的系統(tǒng)。這為討論分布式系統(tǒng)實(shí)現(xiàn)提供了很好的術(shù)語(yǔ)。

接下來(lái)是在主流開(kāi)源分布式系統(tǒng)中觀察到的第一組模式。我希望這些模式集對(duì)所有開(kāi)發(fā)人員都有用。

分布式系統(tǒng) - 實(shí)現(xiàn)的角度來(lái)看

當(dāng)今的企業(yè)體系結(jié)構(gòu)充滿了自然分布的平臺(tái)和框架。如果我們看到今天在典型的企業(yè)體系結(jié)構(gòu)中使用的框架和平臺(tái)的示例列表,它將類似于以下內(nèi)容:

所有這些本質(zhì)上都是“分布式的”。分布式系統(tǒng)意味著什么?有兩個(gè)方面:

?它們?cè)诙嗯_(tái)服務(wù)器上運(yùn)行。集群中的服務(wù)器數(shù)量可以從三臺(tái)到幾千臺(tái)不等。

   ?  它們管理數(shù)據(jù)。因此,這些天生就是“有狀態(tài)”的系統(tǒng)。

當(dāng)多個(gè)服務(wù)器參與數(shù)據(jù)存儲(chǔ)時(shí),有幾種途徑可能會(huì)導(dǎo)致問(wèn)題。上述所有系統(tǒng)都需要解決這些問(wèn)題。這些系統(tǒng)的實(shí)現(xiàn)對(duì)這些問(wèn)題有一些可復(fù)用的解決方案。理解這些解決方案的一般形式,有助于理解這些系統(tǒng)的廣泛實(shí)現(xiàn),并且在需要構(gòu)建新系統(tǒng)時(shí)也可以作為很好的指導(dǎo)。下面進(jìn)入模式章節(jié)。

問(wèn)題及其可復(fù)用的解決方案

當(dāng)數(shù)據(jù)存儲(chǔ)在多個(gè)服務(wù)器上時(shí),可能會(huì)出現(xiàn)幾個(gè)問(wèn)題。

進(jìn)程崩潰

進(jìn)程隨時(shí)會(huì)由于硬件故障或軟件故障崩潰。進(jìn)程崩潰的方式有很多種。

?系統(tǒng)管理員可以將其下線進(jìn)行日常維護(hù)。?由于磁盤已滿并且該異常無(wú)法正確被處理,因此在執(zhí)行某些文件IO時(shí)被殺死。?在云環(huán)境中,這可能會(huì)更加棘手,因?yàn)橐恍┎幌嚓P(guān)的事件可能會(huì)使服務(wù)器宕機(jī)。

最重要的是,如果進(jìn)程負(fù)責(zé)存儲(chǔ)數(shù)據(jù),則必須對(duì)存儲(chǔ)在服務(wù)器上的數(shù)據(jù)提供持久性保證。即使進(jìn)程突然崩潰,它也應(yīng)保留所有已通知用戶已成功存儲(chǔ)的數(shù)據(jù)。根據(jù)訪問(wèn)模式,不同的存儲(chǔ)引擎具有不同的存儲(chǔ)結(jié)構(gòu),從簡(jiǎn)單的哈希映射到復(fù)雜的圖存儲(chǔ)。由于將數(shù)據(jù)刷新到磁盤是最耗時(shí)的操作之一,因此無(wú)法將每次對(duì)存儲(chǔ)的插入或更新都刷新到磁盤。因此,大多數(shù)數(shù)據(jù)庫(kù)都具有內(nèi)存存儲(chǔ)結(jié)構(gòu),這些存儲(chǔ)結(jié)構(gòu)僅定期刷新到磁盤。如果進(jìn)程突然崩潰,則可能會(huì)丟失所有數(shù)據(jù)。

一種稱為Write-Ahead Log的技術(shù)用于解決這種情況。服務(wù)器將每個(gè)狀態(tài)更改作為命令存儲(chǔ)在硬盤上的append-only文件中。append文件通常是非?焖俚牟僮,因此可以在不影響性能的情況下進(jìn)行。通過(guò)順序附加單個(gè)日志的方式存儲(chǔ)每一次更新。在服務(wù)器啟動(dòng)時(shí),可以重放日志以再次建立內(nèi)存狀態(tài)。

這提供了持久性保證。即使服務(wù)器突然崩潰,然后重新啟動(dòng),數(shù)據(jù)也不會(huì)丟失。但是,在恢復(fù)服務(wù)器之前,客戶端將無(wú)法獲取或存儲(chǔ)任何數(shù)據(jù)。因此,如果服務(wù)器發(fā)生故障,缺乏可用性。

一種顯而易見(jiàn)的解決方案是將數(shù)據(jù)存儲(chǔ)在多個(gè)服務(wù)器上。因此,我們可以在多個(gè)服務(wù)器上復(fù)制預(yù)寫日志。

當(dāng)涉及多個(gè)服務(wù)器時(shí),還有更多的故障情況需要考慮。

網(wǎng)絡(luò)延遲

在TCP / IP協(xié)議棧中,在跨網(wǎng)絡(luò)傳輸消息時(shí)所引起的延遲沒(méi)有上限。它可以根據(jù)網(wǎng)絡(luò)上的負(fù)載而變化。例如,一條1 Gbps的網(wǎng)絡(luò)連接可能會(huì)被觸發(fā)的大數(shù)據(jù)作業(yè)吞沒(méi),從而填滿網(wǎng)絡(luò)緩沖區(qū),并可能導(dǎo)致某些消息到達(dá)服務(wù)器的超長(zhǎng)延遲。

在典型的數(shù)據(jù)中心中,服務(wù)器一起放在機(jī)架中,并且有多個(gè)機(jī)架通過(guò)機(jī)架交換機(jī)連接?赡軙(huì)有一個(gè)交換機(jī)樹將數(shù)據(jù)中心的一部分連接到另一部分。在某些情況下,一組服務(wù)器可以相互通信,但與另一組服務(wù)器斷開(kāi)連接。這種情況稱為網(wǎng)絡(luò)分區(qū)。服務(wù)器通過(guò)網(wǎng)絡(luò)進(jìn)行通信的基本問(wèn)題之一是何時(shí)知道特定服務(wù)器發(fā)生故障。

這里有兩個(gè)問(wèn)題要解決。

?某臺(tái)的服務(wù)器不能無(wú)限期地等待其他服務(wù)器是否崩潰。?不應(yīng)有兩組服務(wù)器,每組服務(wù)器都認(rèn)為另一組服務(wù)器發(fā)生了故障,因此繼續(xù)為不同組的客戶端提供服務(wù)。這稱為腦裂。

為了解決第一個(gè)問(wèn)題,每臺(tái)服務(wù)器都會(huì)定期向其他服務(wù)器發(fā)送HeartBeat消息。如果心跳丟失,則將發(fā)送心跳的服務(wù)器視為已崩潰。心跳間隔足夠小,以確保不需要花費(fèi)很多時(shí)間來(lái)檢測(cè)服務(wù)器故障。如我們將下面看到的,在最壞的情況下,服務(wù)器可能已啟動(dòng)并正在運(yùn)行,但是考慮到服務(wù)器出現(xiàn)故障,集群作為一個(gè)整體可以繼續(xù)運(yùn)行。這樣可以確保提供給客戶端的服務(wù)不會(huì)中斷。

第二個(gè)問(wèn)題是腦裂。腦裂,如果兩組服務(wù)器獨(dú)立接受更新請(qǐng)求,則不同的客戶端可以獲取和設(shè)置不同的數(shù)據(jù),一旦腦裂得到解決,就不可能自動(dòng)解決數(shù)據(jù)沖突。

為了解決腦裂問(wèn)題,我們必須確保彼此斷開(kāi)連接的兩組服務(wù)器不能獨(dú)立運(yùn)展。為確保這一點(diǎn),該服務(wù)器執(zhí)行的每個(gè)動(dòng)作只有獲得大多數(shù)服務(wù)器的確認(rèn)才被認(rèn)為是成功的。如果服務(wù)器無(wú)法獲得多數(shù)確認(rèn),則它們將無(wú)法提供所需的服務(wù),并且某些客戶端組可能無(wú)法接收該服務(wù)的響應(yīng),但是集群中的服務(wù)器將始終處于一致?tīng)顟B(tài)。占多數(shù)的服務(wù)器數(shù)量稱為Quorum。如何確定Quorum?這是根據(jù)群集可以容忍的故障數(shù)決定的。因此,如果我們有五個(gè)節(jié)點(diǎn)的集群,則需要三個(gè)仲裁。通常,如果我們要容忍f個(gè)故障,則需要2f + 1的集群大小。

Quorum確保我們有足夠的數(shù)據(jù)副本以承受某些服務(wù)器故障。但是,僅向客戶提供強(qiáng)大的一致性保證是不夠的。假設(shè)客戶端在quorum上開(kāi)始了寫操作,但是該寫操作僅在一臺(tái)服務(wù)器上成功。quorum的其他服務(wù)器仍是舊值。當(dāng)客戶端從quorum 取值時(shí),如果具有最新值的服務(wù)器可用,則它可能會(huì)獲得最新值。但是,當(dāng)客戶端開(kāi)始讀取值時(shí),具有最新值的服務(wù)器不可用,它就會(huì)獲取舊值。為了避免這種情況,需有設(shè)備跟蹤quorum是否同意特定的操作,并且僅將值發(fā)送給保證在所有服務(wù)器上都可用的客戶端。在這種情況下使用 Leader and Followers模式。其中一臺(tái)服務(wù)器當(dāng)選領(lǐng)導(dǎo)者,其他服務(wù)器充當(dāng)追隨者。領(lǐng)導(dǎo)者控制并協(xié)調(diào)對(duì)跟隨者的復(fù)制。領(lǐng)導(dǎo)者現(xiàn)在需要確定哪些更改應(yīng)該對(duì)客戶可見(jiàn)。High-Water Mark用于跟蹤已知已成功復(fù)制到追隨者Quorum的預(yù)寫日志中的條目。客戶端可以看到所有High-Water之前的條目。領(lǐng)導(dǎo)者還將High-Water Mark傳播給跟隨者。因此,如果領(lǐng)導(dǎo)者失敗并且其中一個(gè)跟隨者成為新領(lǐng)導(dǎo)者,那么客戶看到的內(nèi)容就不會(huì)出現(xiàn)不一致之處。

進(jìn)程暫停

但這還不是全部,即使有了Quorums和Leader and Followers,仍然需要解決一個(gè)棘手的問(wèn)題。領(lǐng)導(dǎo)者進(jìn)程暫停。進(jìn)程暫停的原因有很多。具有較長(zhǎng)垃圾收集暫停時(shí)間的領(lǐng)導(dǎo)者會(huì)與追隨者者斷開(kāi)連接,并在恢復(fù)后繼續(xù)向追隨者發(fā)送消息。同時(shí),由于追隨者沒(méi)有收到領(lǐng)導(dǎo)者的任何心跳,因此他們可能選擇了新的領(lǐng)導(dǎo)者并接受了客戶的更新。如果舊領(lǐng)導(dǎo)者的請(qǐng)求按原邏輯處理,它們可能會(huì)覆蓋某些更新。因此,我們需要一種機(jī)制來(lái)檢測(cè)過(guò)時(shí)領(lǐng)導(dǎo)者的請(qǐng)求。Generation Clock 用于標(biāo)記和檢測(cè)來(lái)自過(guò)期領(lǐng)導(dǎo)者的請(qǐng)求。Generation是單調(diào)增加的數(shù)字。

不同步的時(shí)鐘和事件順序

從較新的消息中檢測(cè)較舊的領(lǐng)導(dǎo)者消息的問(wèn)題是保持消息順序的問(wèn)題。我們似乎可以使用系統(tǒng)時(shí)間戳來(lái)排序一組消息,但事實(shí)上不能。我們不能使用系統(tǒng)時(shí)鐘的主要原因是不能保證跨服務(wù)器的系統(tǒng)時(shí)鐘是同步的。計(jì)算機(jī)中的一天中的時(shí)鐘由石英晶體管理,并根據(jù)晶體的振蕩來(lái)測(cè)量時(shí)間。

這種機(jī)制易于出錯(cuò),因?yàn)榫w可以更快或更慢地振蕩,因此不同的服務(wù)器可能具有截然不同的時(shí)間。一組服務(wù)器上的時(shí)鐘由稱為NTP的服務(wù)進(jìn)行同步。該服務(wù)會(huì)定期檢查一組全局時(shí)間服務(wù)器,并相應(yīng)地調(diào)整計(jì)算機(jī)時(shí)鐘。

因?yàn)檫@是通過(guò)網(wǎng)絡(luò)上的通信發(fā)生的,并且網(wǎng)絡(luò)延遲可能會(huì)如上一節(jié)中所述發(fā)生變化,所以時(shí)鐘同步可能會(huì)由于網(wǎng)絡(luò)問(wèn)題而延遲。這可能會(huì)導(dǎo)致服務(wù)器時(shí)鐘彼此偏移,并且在NTP同步發(fā)生后甚至?xí)蚝笠。由于?jì)算機(jī)時(shí)鐘存在這些問(wèn)題,因此通常不將一天中的時(shí)間用于排序事件。取而代之的是使用一種稱為L(zhǎng)amport時(shí)間戳的簡(jiǎn)單技術(shù)。Generation Clock就是一個(gè)例子。

這些問(wèn)題可能會(huì)發(fā)生在最復(fù)雜的設(shè)置中?紤]Amazon、谷歌和Github的例子。

一次Github宕機(jī)實(shí)質(zhì)上導(dǎo)致了東海岸和西海岸數(shù)據(jù)中心之間的連接中斷。這會(huì)導(dǎo)致數(shù)據(jù)無(wú)法跨數(shù)據(jù)中心復(fù)制,使兩臺(tái)mysql服務(wù)器的數(shù)據(jù)不一致。

https://github.blog/2018-10-30-oct21-post-incident-analysis/

一次AWS宕機(jī)是由人為錯(cuò)誤造成的,其中自動(dòng)化腳本錯(cuò)誤地傳遞了一個(gè)參數(shù),關(guān)閉了大量服務(wù)器。https://aws.a(chǎn)mazon.com/message/41926/

一次谷歌中斷是由一些錯(cuò)誤配置引起的,對(duì)網(wǎng)絡(luò)容量造成了重大影響,從而導(dǎo)致網(wǎng)絡(luò)擁塞和服務(wù)中斷。

https://status.cloud.google.com/incident/cloud-networking/19009

匯總-分布式系統(tǒng)示例

我們可以發(fā)現(xiàn)理解這些模式如何幫助我們從頭開(kāi)始建立一個(gè)完整的系統(tǒng)。我們將以共識(shí)實(shí)現(xiàn)為例。分布式共識(shí)是分布式系統(tǒng)實(shí)現(xiàn)的特例,它提供了最強(qiáng)的一致性保證。在流行的企業(yè)系統(tǒng)中常見(jiàn)的示例有Zookeeper,etcd和Consul。他們實(shí)現(xiàn)了zab和Raft等共識(shí)算法,以提供復(fù)制和強(qiáng)一致性。還有其他流行的算法可以實(shí)現(xiàn)共識(shí),Paxos用于Google的Chubby鎖服務(wù),查stamp replication和virtual-synchrony。用非常簡(jiǎn)單的術(shù)語(yǔ)來(lái)說(shuō),“共識(shí)”是指一組服務(wù)器,它們?cè)诖鎯?chǔ)的數(shù)據(jù),存儲(chǔ)的順序以及何時(shí)使該數(shù)據(jù)對(duì)客戶端可見(jiàn)方面達(dá)成一致。

實(shí)現(xiàn)共識(shí)的模式序列

共識(shí)實(shí)現(xiàn)使用狀態(tài)機(jī)復(fù)制來(lái)實(shí)現(xiàn)容錯(cuò)。在狀態(tài)機(jī)復(fù)制中,存儲(chǔ)服務(wù)(如鍵值存儲(chǔ))在所有服務(wù)器上復(fù)制,并且用戶的輸入在每個(gè)服務(wù)器上以相同順序執(zhí)行。實(shí)現(xiàn)此目的的關(guān)鍵技術(shù)是在所有服務(wù)器上復(fù)制預(yù)寫日志以獲得“ Replicated Wal”。

我們可以將這些模式放在一起以實(shí)現(xiàn)Replicated Wal,如下所示。

為了提供持久性保證,請(qǐng)使用Write-Ahead Log。使用Segmented Log將Write-Ahead Log分為多個(gè)段。這有助于Low-Water Mark 處理日志清理。通過(guò)在多個(gè)服務(wù)器上復(fù)制預(yù)寫日志來(lái)提供容錯(cuò)能力。服務(wù)器之間的復(fù)制是通過(guò)使用“領(lǐng)導(dǎo)者”和“追隨者”來(lái)管理的。Quorum法定數(shù)用于更新High-Water Mark,以確定客戶端可以看到哪些值。通過(guò)使用Singular Update Queue,所有請(qǐng)求均按嚴(yán)格順序處理。使用Single Socket Channel將領(lǐng)導(dǎo)者的請(qǐng)求發(fā)送給追隨者時(shí),順序?qū)⒌玫骄S護(hù)。為了優(yōu)化單個(gè)套接字通道上的吞吐量和延遲性,使用Request Pipeline。追隨者通過(guò)從領(lǐng)導(dǎo)者處獲得HeartBeat獲知其可用性。如果領(lǐng)導(dǎo)者由于網(wǎng)絡(luò)分區(qū)而暫時(shí)從集群斷開(kāi)連接,則可以使用Generation Clock進(jìn)行檢測(cè)。

通過(guò)這種方式,理解問(wèn)題及其一般形式的可復(fù)用解決方案,有助于理解完整系統(tǒng)的構(gòu)建模塊

下一步

分布式系統(tǒng)是一個(gè)廣泛的話題。這里討論的模式集只是一小部分,它涵蓋了不同類別,以展示模式方法如何幫助理解和設(shè)計(jì)分布式系統(tǒng)。我將繼續(xù)在這個(gè)集合中添加內(nèi)容,任何分布式系統(tǒng)中都廣泛地包含了以下問(wèn)題類別。

?集群成員和故障檢測(cè)?分區(qū)?復(fù)制和一致性?存儲(chǔ)?處理


聲明: 本文由入駐維科號(hào)的作者撰寫,觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

    掃碼關(guān)注公眾號(hào)
    OFweek人工智能網(wǎng)
    獲取更多精彩內(nèi)容
    文章糾錯(cuò)
    x
    *文字標(biāo)題:
    *糾錯(cuò)內(nèi)容:
    聯(lián)系郵箱:
    *驗(yàn) 證 碼:

    粵公網(wǎng)安備 44030502002758號(hào)