圖解分布式系統(tǒng)—程序員進(jìn)階之路
65 哥已經(jīng)工作兩年了,一直做著簡(jiǎn)單重復(fù)的編程工作,活活熬成了一個(gè)只會(huì) CRUD 的打工 boy。
65 哥:總是聽(tīng)大佬講分布式分布式,什么才是分布式系統(tǒng)呢?
分布式系統(tǒng)是一個(gè)硬件或軟件系統(tǒng)分布在不同的網(wǎng)絡(luò)計(jì)算機(jī)上,彼此之間僅僅通過(guò)消息傳遞進(jìn)行通信和協(xié)調(diào)的系統(tǒng)。在一個(gè)分布式系統(tǒng)中,一組獨(dú)立的計(jì)算機(jī)展現(xiàn)給用戶(hù)的是一個(gè)統(tǒng)一的整體,就好像是一個(gè)系統(tǒng)似的。系統(tǒng)擁有多種通用的物理和邏輯資源,可以動(dòng)態(tài)的分配任務(wù),分散的物理和邏輯資源通過(guò)計(jì)算機(jī)網(wǎng)絡(luò)實(shí)現(xiàn)信息交換。
那好,下面我們從平常最熟悉的事物開(kāi)始理解分布式系統(tǒng)如何出現(xiàn),發(fā)展的,并經(jīng)過(guò)實(shí)踐總結(jié)通用的理論,這些理論成為指導(dǎo)我們?nèi)绾卧O(shè)計(jì)更完善的分布式系統(tǒng)的基礎(chǔ)。
從此篇文章,你將學(xué)習(xí)到以下知識(shí):

Web 應(yīng)用的擴(kuò)展
為什么會(huì)出現(xiàn)分布式應(yīng)用?
65 哥:這個(gè)我也不清楚啊,以前我寫(xiě)的 web 應(yīng)用都是直接扔進(jìn) Tomcat 中,啟動(dòng) Tomcat 就可以訪問(wèn)了,這肯定不是分布式應(yīng)用。

嗯,我們就從大家最熟悉 web 后臺(tái)應(yīng)用講起,以前我們的系統(tǒng)訪問(wèn)量小,業(yè)務(wù)也不復(fù)雜,一臺(tái)服務(wù)器一個(gè)應(yīng)用就可以處理所有的業(yè)務(wù)請(qǐng)求了,后來(lái)我們公司發(fā)達(dá)了,訪問(wèn)量上去了,業(yè)務(wù)也拓展了,雖然老板依舊沒(méi)有給我們加工資,卻總是埋怨我們系統(tǒng)不穩(wěn)定,扛不住大并發(fā),是可忍孰不可也,加錢(qián),我們要升級(jí)。
如果我們的服務(wù)器可以無(wú)限添加配置,那么一切性能問(wèn)題都不是問(wèn)題。
為提高系統(tǒng)處理能力,我們首先想到的擴(kuò)展方式就是升級(jí)系統(tǒng)配置,8 核 cpu 升級(jí)為 32 核,64 核,內(nèi)存 64G 升級(jí)為 128G,256G,帶寬上萬(wàn)兆,十萬(wàn)兆,這就叫做垂直擴(kuò)展。但這樣的擴(kuò)展終將無(wú)法持續(xù)下去,原因如下。
單機(jī)系統(tǒng)的處理能力最終會(huì)達(dá)到瓶頸
單機(jī)升級(jí)的邊際成本將越來(lái)越大
沒(méi)有什么可以攔住我們編程打工人的步伐。
俗話(huà)說(shuō),系統(tǒng)撐不住了,就加服務(wù)器,一臺(tái)不行就加兩臺(tái)。
當(dāng)垂直擴(kuò)展到達(dá)技術(shù)瓶頸或投入產(chǎn)出比超過(guò)預(yù)期,我們可以考慮通過(guò)增加服務(wù)器數(shù)量來(lái)提高并發(fā)能力,這種方式就是水平擴(kuò)展。
系統(tǒng)拆分
65 哥:哦,這就是分布式系統(tǒng)了?這么簡(jiǎn)單的么。
我勒個(gè)呵呵,哪有那么簡(jiǎn)單,在水平擴(kuò)展中,我們?cè)黾恿朔?wù)器數(shù)量,但是如何讓這些服務(wù)器像一個(gè)整體一樣對(duì)外提供穩(wěn)定有效的服務(wù)才是關(guān)鍵。既然已經(jīng)有了多臺(tái)服務(wù)器,我們就要考慮如何將系統(tǒng)部署到到不同的節(jié)點(diǎn)上去。
- 65 哥:這還不簡(jiǎn)單,我將我的 SpringBoot 項(xiàng)目部署到多臺(tái)服務(wù)器上,前面加個(gè) nginx 就可以了,現(xiàn)在我們的系統(tǒng)都是這樣的,穩(wěn)定高效 perfect。給你畫(huà)個(gè)架構(gòu)圖(小聲,這個(gè)我在學(xué)校時(shí)就會(huì)了。)

哪有什么歲月靜好,只不過(guò)是有人在為你負(fù)重前行。上面你所認(rèn)為的簡(jiǎn)單,其實(shí)有兩個(gè)原因:
系統(tǒng)分離不徹底,很重要的一點(diǎn),就是依然在共享一個(gè)數(shù)據(jù)庫(kù)
在這個(gè)成熟的體系中,有太多成熟的中間件在為我們服務(wù),比如上面提到的 nginx
系統(tǒng)拆分也有兩種方式,垂直拆分和水平拆分,注意,這里和上面提到的垂直擴(kuò)展和水平擴(kuò)展不是處理同一個(gè)問(wèn)題的。(65 哥:哈哈,我知道,世間萬(wàn)物不外乎縱橫二字)。
系統(tǒng)的垂直拆分,就是將相同的系統(tǒng)部署多套,所有的節(jié)點(diǎn)并沒(méi)有任何不同,角色和功能都一樣,它們各自分擔(dān)一部分功能請(qǐng)求,這樣整個(gè)系統(tǒng)的處理能力的上升了。
從處理 web 請(qǐng)求上來(lái)看,垂直拆分的每個(gè)節(jié)點(diǎn)都處理一個(gè)完整的請(qǐng)求,每個(gè)節(jié)點(diǎn)都承擔(dān)一部分請(qǐng)求量;
從數(shù)據(jù)存儲(chǔ)的角度看,每個(gè)數(shù)據(jù)節(jié)點(diǎn)都存儲(chǔ)相同的業(yè)務(wù)數(shù)據(jù),每個(gè)節(jié)點(diǎn)存儲(chǔ)一部分?jǐn)?shù)據(jù)。

系統(tǒng)的水平拆分,就是將系統(tǒng)按不同模塊或角色拆分,不同的模塊處理不同的事情。
從 web 請(qǐng)求上來(lái)看,需要多個(gè)相互依賴(lài)的系統(tǒng)配合完成一個(gè)請(qǐng)求,每個(gè)節(jié)點(diǎn)處理的需求不一致;
從數(shù)據(jù)存儲(chǔ)角度上來(lái)看,每個(gè)數(shù)據(jù)節(jié)點(diǎn)都存儲(chǔ)著各自業(yè)務(wù)模塊相關(guān)的數(shù)據(jù),它們的數(shù)據(jù)都不一樣。
上面垂直拆分之后各個(gè)節(jié)點(diǎn)組成的就是一個(gè)集群,而水平拆分各個(gè)節(jié)點(diǎn)就是分布式。這就是集群和分布式的區(qū)別。集群除了上面提到的可以提高并發(fā)處理能力外,還可以保證系統(tǒng)的高可用,當(dāng)一部分節(jié)點(diǎn)失效后,整個(gè)系統(tǒng)依舊可以提供完整的服務(wù)。分布式也一樣,除了提高并發(fā)能力,解耦系統(tǒng),使系統(tǒng)邊界更清晰,系統(tǒng)功能更內(nèi)聚也是其一大好處,所以在實(shí)際的系統(tǒng)中我們往往這兩種方式同時(shí)都在使用,而且我們常常提及的分布式系統(tǒng)其實(shí)是包含著集群的概念在里面的。

分布式目標(biāo)
歸納和演繹是人類(lèi)理性的基石,學(xué)習(xí)和思考就是不斷的歸納過(guò)去的經(jīng)驗(yàn),從而得到普遍的規(guī)律,然后將得之的規(guī)律演繹于其他事物,用于指導(dǎo)更好的實(shí)踐過(guò)程。

上面我們講解了分布式系統(tǒng)的由來(lái),現(xiàn)在我們回顧和總結(jié)一下這個(gè)過(guò)程。我們引入分布式系統(tǒng)必然是基于現(xiàn)實(shí)的需求和目標(biāo)而來(lái)的。
65 哥:那分布式的目標(biāo)什么呢?
分布式就是為了滿(mǎn)足以下目標(biāo)而設(shè)計(jì)的:
- Transparency: 透明性,即用戶(hù)是不關(guān)心系統(tǒng)背后的分布式的,無(wú)論系統(tǒng)是分布式的還是單機(jī)的,對(duì)用戶(hù)來(lái)說(shuō)都應(yīng)該是透明的,用戶(hù)只需要關(guān)心系統(tǒng)可用的能力。這里的透明性就包括以下方面:
- 訪問(wèn)透明性:固定統(tǒng)一的訪問(wèn)接口和方式,不因?yàn)榉植际较到y(tǒng)內(nèi)部的變動(dòng)而改變系統(tǒng)的訪問(wèn)方式。
- 位置透明性:外部訪問(wèn)者不需要知道分布式系統(tǒng)具體的地址,系統(tǒng)節(jié)點(diǎn)的變動(dòng)也不會(huì)影響其功能。
- 并發(fā)透明性:幾個(gè)進(jìn)程能并發(fā)的使用共享資源而不互相干擾。
- 復(fù)制透明性:使用資源的多個(gè)實(shí)例提升可靠性和性能,而用戶(hù)和程序員無(wú)需知道副本的相關(guān)信息。
- 故障透明性:分布式系統(tǒng)內(nèi)部部分節(jié)點(diǎn)的故障不影響系統(tǒng)的整體功能。
- 移動(dòng)透明性:資源和客戶(hù)能夠在系統(tǒng)內(nèi)移動(dòng)而不受影響。
- 性能透明性:負(fù)載變化時(shí),系統(tǒng)能夠被重新配置以提高性能。
- 伸縮透明性:系統(tǒng)和應(yīng)用能夠進(jìn)行擴(kuò)展而不改變系統(tǒng)結(jié)構(gòu)和應(yīng)用算法。
- Openness: 開(kāi)放性,通用的協(xié)議和使用方式。
- Scalability: 可伸縮性,隨著資源數(shù)量的增加和用戶(hù)訪問(wèn)的增加,系統(tǒng)仍然能保持其有效性,該系統(tǒng)就被稱(chēng)為可伸縮的。分布式系統(tǒng)應(yīng)該在系統(tǒng)大小,系統(tǒng)管理方面都可擴(kuò)展。
- Performance: 性能,相對(duì)于單體應(yīng)用,分布式系統(tǒng)應(yīng)該用更加突出的性能。
- Reliability: 可靠性,與單體系統(tǒng)相比,分布式系統(tǒng)應(yīng)具有更好安全性,一致性和掩蓋錯(cuò)誤的能力。
分布式挑戰(zhàn)
分布式的挑戰(zhàn)來(lái)源于不確定性。想一想,分布式系統(tǒng)相對(duì)于單體應(yīng)用,多了哪些東西?
- 65 哥:有了更多的服務(wù)節(jié)點(diǎn),還有就是服務(wù)之間的網(wǎng)絡(luò)通信。
是的,看來(lái) 65 哥同學(xué)已經(jīng)懂得思考和分析系統(tǒng)了。分布式系統(tǒng)的所有挑戰(zhàn)就來(lái)源于這兩者的不確定性。
1.節(jié)點(diǎn)故障:
節(jié)點(diǎn)數(shù)量越多,出故障的概率就變高了。分布式系統(tǒng)需要保證故障發(fā)生的時(shí)候,系統(tǒng)仍然是可用的,這就需要系統(tǒng)能夠感知所有節(jié)點(diǎn)的服務(wù)狀態(tài),在節(jié)點(diǎn)發(fā)生故障的情況下將該節(jié)點(diǎn)負(fù)責(zé)的計(jì)算、存儲(chǔ)任務(wù)轉(zhuǎn)移到其他節(jié)點(diǎn)。
2.不可靠的網(wǎng)絡(luò):
節(jié)點(diǎn)間通過(guò)網(wǎng)絡(luò)通信,我們都知道網(wǎng)絡(luò)是不可靠的??赡艿木W(wǎng)絡(luò)問(wèn)題包括:網(wǎng)絡(luò)分割、延時(shí)、丟包、亂序。相比單機(jī)過(guò)程調(diào)用,網(wǎng)絡(luò)通信最讓人頭疼的是超時(shí)已經(jīng)雙向通行的不確定性。出現(xiàn)超時(shí)狀態(tài)時(shí),網(wǎng)絡(luò)通信發(fā)起方是無(wú)法確定當(dāng)前請(qǐng)求是否被成功處理的。
在不可靠的網(wǎng)絡(luò)和節(jié)點(diǎn)中,分布式系統(tǒng)依然要保證其可用,穩(wěn)定,高效,這是一個(gè)系統(tǒng)最基本的要求。因此分布式系統(tǒng)的設(shè)計(jì)和架構(gòu)充滿(mǎn)了挑戰(zhàn)。
分而治之
分布式系統(tǒng)就是充分利用更多的資源進(jìn)行并行運(yùn)算和存儲(chǔ)來(lái)提升系統(tǒng)的性能,這就是分而治之的原理。
- 65 哥:哦,懂了懂了,那 MapReduce 的 map,Elasticsearch 的 sharding,Kafka 的 partition 是不是都是分布式的分而治之原理。
可以啊,65 哥同學(xué)不僅能夠歸納,還能夠舉一反三了。不錯(cuò),無(wú)論是 map,sharding 還是 partition,甚至 請(qǐng)求路由負(fù)載均衡 都是在將計(jì)算或數(shù)據(jù)拆分,再分布到不同的節(jié)點(diǎn)計(jì)算和存儲(chǔ),從而提高系統(tǒng)的并發(fā)性。
不同集群類(lèi)型的分
sharding
同樣是分,在不同領(lǐng)域的,甚至不同實(shí)現(xiàn)的系統(tǒng)中通常會(huì)有不同的說(shuō)法。sharding 通常是在數(shù)據(jù)存儲(chǔ)系統(tǒng)中將不同數(shù)據(jù)分布到不同節(jié)點(diǎn)的方式,中文通常翻譯為數(shù)據(jù)分片。
比如在 MongoDB 中,當(dāng) MongoDB 存儲(chǔ)海量的數(shù)據(jù)時(shí),一臺(tái)機(jī)器可能不足以存儲(chǔ)數(shù)據(jù),也可能不足以提供可接受的讀寫(xiě)吞吐量。這時(shí),我們就可以通過(guò)在多臺(tái)機(jī)器上分割數(shù)據(jù),使得數(shù)據(jù)庫(kù)系統(tǒng)能存儲(chǔ)和處理更多的數(shù)據(jù)。

比如在 Elasticsearch 中,每個(gè)索引有一個(gè)或多個(gè)分片,索引的數(shù)據(jù)被分配到各個(gè)分片上,相當(dāng)于一桶水用了 N 個(gè)杯子裝。分片有助于橫向擴(kuò)展,N 個(gè)分片會(huì)被盡可能平均地(rebalance)分配在不同的節(jié)點(diǎn)上。
partition
partition的概念經(jīng)常在 Kafka 中可以看到,在 kafka 中 topic 是一個(gè)邏輯概念,從分布式隊(duì)列的角度看,topic 對(duì)使用者來(lái)說(shuō)就是一個(gè)隊(duì)列,topic 在 kafka 的具體實(shí)現(xiàn)中,由分布在不同節(jié)點(diǎn)上的 partition 組成,每個(gè) partition 就是根據(jù)分區(qū)算法拆分的多個(gè)分區(qū),在 kafka 中,同一個(gè)分區(qū)不能被同一個(gè) group 下的多個(gè) consumer 消費(fèi),所以一個(gè) topic 有多少 partition 在一定意義上就表示這個(gè) topic 具有多少并發(fā)處理能力。

在 Amazing 的分布式數(shù)據(jù)庫(kù)DynamoDB中,一張表在底層實(shí)現(xiàn)中也被分區(qū)為不同的 partition。
load balance
負(fù)載均衡是高可用網(wǎng)絡(luò)基礎(chǔ)架構(gòu)的關(guān)鍵組件,通常用于將工作負(fù)載分布到多個(gè)服務(wù)器來(lái)提高網(wǎng)站、應(yīng)用、數(shù)據(jù)庫(kù)或其他服務(wù)的性能和可靠性。
比如 nginx 的負(fù)載均衡,通過(guò)不同的負(fù)載均衡分配策略,將 http 請(qǐng)求分發(fā)到 web 應(yīng)用的不同節(jié)點(diǎn)之上,從而提高應(yīng)用的并發(fā)處理能力。
比如 dubbo 的客戶(hù)端負(fù)載能力,可以將 dubbo 請(qǐng)求路由到具體的 producer 提供節(jié)點(diǎn)上,負(fù)載均衡是一個(gè)完善的 RPC 所應(yīng)該具有的能力。
在 Spring Cloud 的體系中 Robbin 組件可以通過(guò) Spring Cloud 的各微服務(wù)之間通信的負(fù)載均衡分配問(wèn)題,依舊是將請(qǐng)求分發(fā)到集群中的不同節(jié)點(diǎn)上去。
分的策略
無(wú)論是分區(qū)還是分片,還是分區(qū)路由,其實(shí)都有一些通用的分區(qū)算法,以下的概念可能很多同學(xué)都在不同的領(lǐng)域看到過(guò),如上面看到的反向代理服務(wù)器 nginx 中,如分布式消息隊(duì)列 kafka 中,如 RPC 框架 Dubbo 中,這有時(shí)候會(huì)讓很多同學(xué)感到懵。
其實(shí)無(wú)論在什么領(lǐng)域中,你只要抓住它在完成的核心功能上就可以理解,它們就是在考慮如何分的問(wèn)題,把處理請(qǐng)求(即計(jì)算)如何均勻地分到不同的機(jī)器上,把數(shù)據(jù)如何分配到不同的節(jié)點(diǎn)上。
從大的方向看分有兩種策略,一種可復(fù)刻,一種不可復(fù)刻。
可復(fù)刻,這種策略根據(jù)一定算法分配計(jì)算和數(shù)據(jù),在相同的條件下,無(wú)論什么時(shí)間點(diǎn)得出的結(jié)果相同,因此對(duì)于相同條件的請(qǐng)求和數(shù)據(jù)來(lái)說(shuō)是可復(fù)刻的,在不同時(shí)間點(diǎn)相同的請(qǐng)求和數(shù)據(jù)始終都在統(tǒng)一節(jié)點(diǎn)上。這種策略一般用于有數(shù)據(jù)狀態(tài)在情況。
不可復(fù)刻,這種策略使用全隨機(jī)方式,即使在相同的條件下,不同時(shí)間點(diǎn)得出的結(jié)果也不一致,因此也是不可還原的,如果只是為了可還原,如果通過(guò)元數(shù)據(jù)記錄已經(jīng)分配好的數(shù)據(jù),之后需要還原時(shí)通過(guò)元數(shù)據(jù)就可以準(zhǔn)確的得知數(shù)據(jù)所在位置了。
65 哥:這么神奇么?我想看看不同系統(tǒng)都有什么策略。
Dubbo 的負(fù)載均衡
Dubbo 是阿里開(kāi)源的分布式服務(wù)框架。其實(shí)現(xiàn)了多種負(fù)載均衡策略。

Random LoadBalance
隨機(jī),可以按權(quán)重設(shè)置隨機(jī)概率。在一個(gè)截面上碰撞的概率高,但調(diào)用量越大分布越均勻,而且按概率使用權(quán)重后也比較均勻,有利于動(dòng)態(tài)調(diào)整提供者權(quán)重。
RoundRobin LoadBalance
輪詢(xún),按公約后的權(quán)重設(shè)置輪詢(xún)比率。存在慢的提供者累積請(qǐng)求的問(wèn)題,比如:第二臺(tái)機(jī)器很慢,但沒(méi)掛,當(dāng)請(qǐng)求調(diào)到第二臺(tái)時(shí)就卡在那,久而久之,所有請(qǐng)求都卡在調(diào)到第二臺(tái)上。
LeastActive LoadBalance
最少活躍調(diào)用數(shù),相同活躍數(shù)的隨機(jī),活躍數(shù)指調(diào)用前后計(jì)數(shù)差。使慢的提供者收到更少請(qǐng)求,因?yàn)樵铰奶峁┱叩恼{(diào)用前后計(jì)數(shù)差會(huì)越大。
ConsistentHash LoadBalance
一致性 Hash,相同參數(shù)的請(qǐng)求總是發(fā)到同一提供者。當(dāng)某一臺(tái)提供者掛時(shí),原本發(fā)往該提供者的請(qǐng)求,基于虛擬節(jié)點(diǎn),平攤到其它提供者,不會(huì)引起劇烈變動(dòng)。
Kafka 的分區(qū)分配策略
Kafka 中提供了多重分區(qū)分配算法(PartitionAssignor)的實(shí)現(xiàn):
RangeAssignor
RangeAssignor 策略的原理是按照消費(fèi)者總數(shù)和分區(qū)總數(shù)進(jìn)行整除運(yùn)算來(lái)獲得一個(gè)跨度,然后將分區(qū)按照跨度進(jìn)行平均分配,以保證分區(qū)盡可能均勻地分配給所有的消費(fèi)者。對(duì)于每一個(gè) Topic,RangeAssignor 策略會(huì)將消費(fèi)組內(nèi)所有訂閱這個(gè) Topic 的消費(fèi)者按照名稱(chēng)的字典序排序,然后為每個(gè)消費(fèi)者劃分固定的分區(qū)范圍,如果不夠平均分配,那么字典序靠前的消費(fèi)者會(huì)被多分配一個(gè)分區(qū)。
RoundRobinAssignor
RoundRobinAssignor 的分配策略是將消費(fèi)組內(nèi)訂閱的所有 Topic 的分區(qū)及所有消費(fèi)者進(jìn)行排序后盡量均衡的分配(RangeAssignor 是針對(duì)單個(gè) Topic 的分區(qū)進(jìn)行排序分配的)。
StickyAssignor
從字面意義上看,Sticky 是“粘性的”,可以理解為分配結(jié)果是帶“粘性的”——每一次分配變更相對(duì)上一次分配做最少的變動(dòng)(上一次的結(jié)果是有粘性的),其主要是為了實(shí)現(xiàn)以下兩個(gè)目標(biāo):
分區(qū)的分配盡量的均衡
每一次重分配的結(jié)果盡量與上一次分配結(jié)果保持一致
65 哥:哇,看來(lái)優(yōu)秀的系統(tǒng)都是相通的。
副本
副本是解決分布式集群高可用問(wèn)題的。在集群系統(tǒng)中,每個(gè)服務(wù)器節(jié)點(diǎn)都是不可靠的,每個(gè)系統(tǒng)都有宕機(jī)的風(fēng)險(xiǎn),如何在系統(tǒng)中少量節(jié)點(diǎn)失效的情況下保證整個(gè)系統(tǒng)的可用性是分布式系統(tǒng)的挑戰(zhàn)之一。副本就是解決這類(lèi)問(wèn)題的方案。副本同樣也可以提高并發(fā)處理能力,比如數(shù)據(jù)在不同的節(jié)點(diǎn)上可以讀寫(xiě)分離,可以并行讀等。
在這里其實(shí)也有很多說(shuō)法,如 Master-Salve、Leader-Follower、Primary-Shard、Leader-Replica 等等。

Mysql 的主從架構(gòu)
目前,大部分的主流關(guān)系型數(shù)據(jù)庫(kù)都提供了主從熱備功能,通過(guò)配置兩臺(tái)(或多臺(tái))數(shù)據(jù)庫(kù)的主從關(guān)系,可以將一臺(tái)數(shù)據(jù)庫(kù)服務(wù)器的數(shù)據(jù)更新同步到另一臺(tái)服務(wù)器上。這既可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)的讀寫(xiě)分離,從而改善數(shù)據(jù)庫(kù)的負(fù)載壓力,也可以提高數(shù)據(jù)高可用,多份數(shù)據(jù)備份降低了數(shù)據(jù)丟失的風(fēng)險(xiǎn)。

Elasticsearch 的副本機(jī)制
在 ES 中有主分片和副本分片的概念。副本分片的主要目的就是為了故障轉(zhuǎn)移,如果持有主分片的節(jié)點(diǎn)掛掉了,一個(gè)副本分片就會(huì)晉升為主分片的角色從而對(duì)外提供查詢(xún)服務(wù)。

CAP 理論
在理論計(jì)算機(jī)科學(xué)中,CAP 定理(CAP theorem),又被稱(chēng)作布魯爾定理(Brewer's theorem),它指出對(duì)于一個(gè)分布式計(jì)算系統(tǒng)來(lái)說(shuō),不可能同時(shí)滿(mǎn)足分布式系統(tǒng)一致性、可用性和分區(qū)容錯(cuò)(即 CAP 中的"C","A"和"P"):
- 65 哥:什么是一致性、可用性和分區(qū)容錯(cuò)性能?
一致性 (Consistency)
一致性意味著所有客戶(hù)端同時(shí)看到相同的數(shù)據(jù),無(wú)論它們連接到哪個(gè)節(jié)點(diǎn)。要發(fā)生這種情況,每當(dāng)將數(shù)據(jù)寫(xiě)入一個(gè)節(jié)點(diǎn)時(shí),必須立即將數(shù)據(jù)轉(zhuǎn)發(fā)或復(fù)制到系統(tǒng)中的所有其他節(jié)點(diǎn),然后才能將寫(xiě)入視為"成功"。
可用性 (Availability)
任何客戶(hù)端的請(qǐng)求都能得到響應(yīng)數(shù)據(jù),不會(huì)出現(xiàn)響應(yīng)錯(cuò)誤。換句話(huà)說(shuō),可用性是站在分布式系統(tǒng)的角度,對(duì)訪問(wèn)本系統(tǒng)的客戶(hù)的另一種承諾:我一定會(huì)給您返回?cái)?shù)據(jù),不會(huì)給你返回錯(cuò)誤,但不保證數(shù)據(jù)最新,強(qiáng)調(diào)的是不出錯(cuò)。
分區(qū)容錯(cuò)
分區(qū)即分布式系統(tǒng)中的通信中斷,兩個(gè)節(jié)點(diǎn)之間的丟失或暫時(shí)延遲的連接。分區(qū)容錯(cuò)意味著群集必須繼續(xù)工作,盡管系統(tǒng)中的節(jié)點(diǎn)之間存在的通信故障。
這三種性質(zhì)進(jìn)行倆倆組合,可以得到下面三種情況:
- CA:完全嚴(yán)格的仲裁協(xié)議,例如 2PC(兩階段提交協(xié)議,第一階段投票,第二階段事物提交)
- CP:不完全(多數(shù))仲裁協(xié)議,例如 Paxos、Raft
- AP:使用沖突解決的協(xié)議,例如 Dynamo、Gossip
CA 和 CP 系統(tǒng)設(shè)計(jì)遵循的都是強(qiáng)一致性理論。不同的是 CA 系統(tǒng)不能容忍節(jié)點(diǎn)發(fā)生故障。CP 系統(tǒng)能夠容忍 2f+1 個(gè)節(jié)點(diǎn)中有 f 個(gè)節(jié)點(diǎn)發(fā)生失敗。
Base 理論
CAP 理論表明,對(duì)于一個(gè)分布式系統(tǒng)而言,它是無(wú)法同時(shí)滿(mǎn)足 Consistency(強(qiáng)一致性)、Availability(可用性) 和 Partition tolerance(分區(qū)容忍性) 這三個(gè)條件的,最多只能滿(mǎn)足其中兩個(gè)。
在分布式環(huán)境中,我們會(huì)發(fā)現(xiàn)必須選擇 P(分區(qū)容忍)要素,因?yàn)榫W(wǎng)絡(luò)本身無(wú)法做到 100% 可靠,有可能出故障,所以分區(qū)是一個(gè)必然的現(xiàn)象。也就是說(shuō)分區(qū)容錯(cuò)性是分布式系統(tǒng)的一個(gè)最基本要求。
CAP 定理限制了我們?nèi)邿o(wú)法同時(shí)滿(mǎn)足,但我們可以盡量讓 C、A、P 都滿(mǎn)足,這就是 BASE 定理。
BASE 理論是 Basically Available(基本可用),Soft State(軟狀態(tài))和 Eventually Consistent(最終一致性)三個(gè)短語(yǔ)的縮寫(xiě)。即使無(wú)法做到強(qiáng)一致性(Strong consistency),但每個(gè)應(yīng)用都可以根據(jù)自身的業(yè)務(wù)特點(diǎn),采用適當(dāng)?shù)姆绞絹?lái)使系統(tǒng)達(dá)到最終一致性(Eventual consistency)。
基本可用 (Basically Available)
基本可用是指分布式系統(tǒng)在出現(xiàn)故障的時(shí)候,允許損失部分可用性,即保證核心可用。
電商大促時(shí),為了應(yīng)對(duì)訪問(wèn)量激增,部分用戶(hù)可能會(huì)被引導(dǎo)到降級(jí)頁(yè)面,服務(wù)層也可能只提供降級(jí)服務(wù),這就是損失部分可用性的體現(xiàn)。
軟狀態(tài) ( Soft State)
什么是軟狀態(tài)呢?相對(duì)于原子性而言,要求多個(gè)節(jié)點(diǎn)的數(shù)據(jù)副本都是一致的,這是一種“硬狀態(tài)”。
軟狀態(tài)指的是:允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認(rèn)為該狀態(tài)不影響系統(tǒng)的整體可用性,即允許系統(tǒng)在多個(gè)不同節(jié)點(diǎn)的數(shù)據(jù)副本存在數(shù)據(jù)延時(shí)。
最終一致性 ( Eventual Consistency)
最終一致性是指系統(tǒng)中的所有數(shù)據(jù)副本經(jīng)過(guò)一定時(shí)間后,最終能夠達(dá)到一致的狀態(tài)。
弱一致性和強(qiáng)一致性相反,最終一致性是弱一致性的一種特殊情況。
BASE 理論面向的是大型高可用、可擴(kuò)展的分布式系統(tǒng)。與傳統(tǒng) ACID 特性相反,不同于 ACID 的強(qiáng)一致性模型,BASE 提出通過(guò)犧牲強(qiáng)一致性來(lái)獲得可用性,并允許數(shù)據(jù)段時(shí)間內(nèi)的不一致,但是最終達(dá)到一致?tīng)顟B(tài)。
分布式是系統(tǒng)擴(kuò)展的必然方向,分布式系統(tǒng)所遇到的問(wèn)題是普遍,隨著大量?jī)?yōu)秀的項(xiàng)目在分布式的道路上披荊斬棘,前人已經(jīng)總結(jié)了大量豐富的理論。并且不同領(lǐng)域的分布式系統(tǒng)也層出不窮,我們既應(yīng)該學(xué)習(xí)好這些好的理論知識(shí),也應(yīng)該去多看看不同分布式系統(tǒng)的實(shí)現(xiàn),總結(jié)它們的共性,發(fā)現(xiàn)它們?cè)诓煌I(lǐng)域獨(dú)特的亮點(diǎn)權(quán)衡,更重要的,我們應(yīng)該將所學(xué)用于日常項(xiàng)目的實(shí)踐當(dāng)中,也應(yīng)該在實(shí)踐中總結(jié)出更多的規(guī)律理論。
感謝讀者看完本文,碼哥將為讀者持續(xù)輸出高質(zhì)量的文章,下期我們繼續(xù)深入講講分布式一致性的問(wèn)題和解決方案,敬請(qǐng)關(guān)注。