1. 分布式術語1.1. 異常服務器宕機內(nèi)存錯誤、服務器停電等都會導致服務器宕機,此時節(jié)點無法正常工作,稱為不可用。 服務器宕機會導致節(jié)點失去所有內(nèi)存信息,因此需要將內(nèi)存信息保存到持久化介質(zhì)上。 網(wǎng)絡異常有一種特殊的網(wǎng)絡異常稱為——網(wǎng)絡分區(qū) ,即集群的所有節(jié)點被劃分為多個區(qū)域,每個區(qū)域內(nèi)部可以通信,但是區(qū)域之間無法通信。 磁盤故障磁盤故障是一種發(fā)生概率很高的異常。 使用冗余機制,將數(shù)據(jù)存儲到多臺服務器。 1.2. 超時在分布式系統(tǒng)中,一個請求除了成功和失敗兩種狀態(tài),還存在著超時狀態(tài)。 可以將服務器的操作設計為具有 冪等性 ,即執(zhí)行多次的結(jié)果與執(zhí)行一次的結(jié)果相同。如果使用這種方式,當出現(xiàn)超時的時候,可以不斷地重新請求直到成功。 1.3. 衡量指標性能常見的性能指標有:吞吐量、響應時間。 其中,吞吐量指系統(tǒng)在某一段時間可以處理的請求總數(shù),通常為每秒的讀操作數(shù)或者寫操作數(shù);響應時間指從某個請求發(fā)出到接收到返回結(jié)果消耗的時間。 這兩個指標往往是矛盾的,追求高吞吐的系統(tǒng),往往很難做到低響應時間,解釋如下:
可用性可用性指系統(tǒng)在面對各種異常時可以提供正常服務的能力。可以用系統(tǒng)可用時間占總時間的比值來衡量,4 個 9 的可用性表示系統(tǒng) 99.99% 的時間是可用的。 一致性可以從兩個角度理解一致性:從客戶端的角度,讀寫操作是否滿足某種特性;從服務器的角度,多個數(shù)據(jù)副本之間是否一致。 可擴展性指系統(tǒng)通過擴展集群服務器規(guī)模來提高性能的能力。理想的分布式系統(tǒng)需要實現(xiàn)“線性可擴展”,即隨著集群規(guī)模的增加,系統(tǒng)的整體性能也會線性增加。 2. 數(shù)據(jù)分布分布式存儲系統(tǒng)的數(shù)據(jù)分布在多個節(jié)點中,常用的數(shù)據(jù)分布方式有哈希分布和順序分布。 數(shù)據(jù)庫的水平切分(Sharding)也是一種分布式存儲方法,下面的數(shù)據(jù)分布方法同樣適用于 Sharding。 2.1. 哈希分布哈希分布就是將數(shù)據(jù)計算哈希值之后,按照哈希值分配到不同的節(jié)點上。例如有 N 個節(jié)點,數(shù)據(jù)的主鍵為 key,則將該數(shù)據(jù)分配的節(jié)點序號為:hash(key)%N。 傳統(tǒng)的哈希分布算法存在一個問題:當節(jié)點數(shù)量變化時,也就是 N 值變化,那么幾乎所有的數(shù)據(jù)都需要重新分布,將導致大量的數(shù)據(jù)遷移。 一致性哈希 Distributed Hash Table(DHT):對于哈希空間 [0, 2n-1],將該哈??臻g看成一個哈希環(huán),將每個節(jié)點都配置到哈希環(huán)上。每個數(shù)據(jù)對象通過哈希取模得到哈希值之后,存放到哈希環(huán)中順時針方向第一個大于等于該哈希值的節(jié)點上。 一致性哈希的優(yōu)點是在增加或者刪除節(jié)點時只會影響到哈希環(huán)中相鄰的節(jié)點,例如下圖中新增節(jié)點 X,只需要將數(shù)據(jù)對象 C 重新存放到節(jié)點 X 上即可,對于節(jié)點 A、B、D 都沒有影響。 2.2. 順序分布哈希分布式破壞了數(shù)據(jù)的有序性,順序分布則不會。 順序分布的數(shù)據(jù)劃分為多個連續(xù)的部分,按數(shù)據(jù)的 ID 或者時間分布到不同節(jié)點上。例如下圖中,User 表的 ID 范圍為 1 ~ 7000,使用順序分布可以將其劃分成多個子表,對應的主鍵范圍為 1 ~ 1000,1001 ~ 2000,...,6001 ~ 7000。 順序分布的優(yōu)點是可以充分利用每個節(jié)點的空間,而哈希分布很難控制一個節(jié)點存儲多少數(shù)據(jù)。 但是順序分布需要使用一個映射表來存儲數(shù)據(jù)到節(jié)點的映射,這個映射表通常使用單獨的節(jié)點來存儲。當數(shù)據(jù)量非常大時,映射表也隨著變大,那么一個節(jié)點就可能無法存放下整個映射表。并且單個節(jié)點維護著整個映射表的開銷很大,查找速度也會變慢。為了解決以上問題,引入了一個中間層,也就是 Meta 表,從而分擔映射表的維護工作。 2.3. 負載均衡衡量負載的因素很多,如 CPU、內(nèi)存、磁盤等資源使用情況、讀寫請求數(shù)等。 分布式系統(tǒng)存儲應當能夠自動負載均衡,當某個節(jié)點的負載較高,將它的部分數(shù)據(jù)遷移到其它節(jié)點。 每個集群都有一個總控節(jié)點,其它節(jié)點為工作節(jié)點,由總控節(jié)點根據(jù)全局負載信息進行整體調(diào)度,工作節(jié)點定時發(fā)送心跳包(Heartbeat)將節(jié)點負載相關的信息發(fā)送給總控節(jié)點。 一個新上線的工作節(jié)點,由于其負載較低,如果不加控制,總控節(jié)點會將大量數(shù)據(jù)同時遷移到該節(jié)點上,造成該節(jié)點一段時間內(nèi)無法工作。因此負載均衡操作需要平滑進行,新加入的節(jié)點需要較長的一段時間來達到比較均衡的狀態(tài)。 3. 分布式理論3.1. CAP分布式系統(tǒng)不可能同時滿足一致性(C:Consistency)、可用性(A:Availability)和分區(qū)容忍性(P:Partition Tolerance),最多只能同時滿足其中兩項。 ![]() 一致性一致性指的是多個數(shù)據(jù)副本是否能保持一致的特性。 在一致性的條件下,系統(tǒng)在執(zhí)行數(shù)據(jù)更新操作之后能夠從一致性狀態(tài)轉(zhuǎn)移到另一個一致性狀態(tài)。 對系統(tǒng)的一個數(shù)據(jù)更新成功之后,如果所有用戶都能夠讀取到最新的值,該系統(tǒng)就被認為具有強一致性。 可用性可用性指分布式系統(tǒng)在面對各種異常時可以提供正常服務的能力,可以用系統(tǒng)可用時間占總時間的比值來衡量,4 個 9 的可用性表示系統(tǒng) 99.99% 的時間是可用的。 在可用性條件下,系統(tǒng)提供的服務一直處于可用的狀態(tài),對于用戶的每一個操作請求總是能夠在有限的時間內(nèi)返回結(jié)果。 分區(qū)容忍性網(wǎng)絡分區(qū)指分布式系統(tǒng)中的節(jié)點被劃分為多個區(qū)域,每個區(qū)域內(nèi)部可以通信,但是區(qū)域之間無法通信。 在分區(qū)容忍性條件下,分布式系統(tǒng)在遇到任何網(wǎng)絡分區(qū)故障的時候,仍然需要能對外提供一致性和可用性的服務,除非是整個網(wǎng)絡環(huán)境都發(fā)生了故障。 權衡在分布式系統(tǒng)中,分區(qū)容忍性必不可少,因為需要總是假設網(wǎng)絡是不可靠的。因此,CAP 理論實際在是要在可用性和一致性之間做權衡。 可用性和一致性往往是沖突的,很難都使它們同時滿足。在多個節(jié)點之間進行數(shù)據(jù)同步時,
3.2. BASEBASE 是基本可用(Basically Available)、軟狀態(tài)(Soft State)和最終一致性(Eventually Consistent)三個短語的縮寫。 BASE 理論是對 CAP 中一致性和可用性權衡的結(jié)果,它的理論的核心思想是:即使無法做到強一致性,但每個應用都可以根據(jù)自身業(yè)務特點,采用適當?shù)姆绞絹硎瓜到y(tǒng)達到最終一致性。 ![]() 基本可用指分布式系統(tǒng)在出現(xiàn)故障的時候,保證核心可用,允許損失部分可用性。 例如,電商在做促銷時,為了保證購物系統(tǒng)的穩(wěn)定性,部分消費者可能會被引導到一個降級的頁面。 軟狀態(tài)指允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認為該中間狀態(tài)不會影響系統(tǒng)整體可用性,即允許系統(tǒng)不同節(jié)點的數(shù)據(jù)副本之間進行同步的過程存在延時。 最終一致性最終一致性強調(diào)的是系統(tǒng)中所有的數(shù)據(jù)副本,在經(jīng)過一段時間的同步后,最終能達到一致的狀態(tài)。 ACID 要求強一致性,通常運用在傳統(tǒng)的數(shù)據(jù)庫系統(tǒng)上。而 BASE 要求最終一致性,通過犧牲強一致性來達到可用性,通常運用在大型分布式系統(tǒng)中。 在實際的分布式場景中,不同業(yè)務單元和組件對一致性的要求是不同的,因此 ACID 和 BASE 往往會結(jié)合在一起使用。 4. 分布式事務問題4.1. 兩階段提交(2PC)兩階段提交(Two-phase Commit,2PC) 主要用于實現(xiàn)分布式事務,分布式事務指的是事務操作跨越多個節(jié)點,并且要求滿足事務的 ACID 特性。 通過引入?yún)f(xié)調(diào)者(Coordinator)來調(diào)度參與者的行為,并最終決定這些參與者是否要真正執(zhí)行事務。 運行過程準備階段 協(xié)調(diào)者詢問參與者事務是否執(zhí)行成功,參與者發(fā)回事務執(zhí)行結(jié)果。 ![]() 提交階段 如果事務在每個參與者上都執(zhí)行成功,事務協(xié)調(diào)者發(fā)送通知讓參與者提交事務;否則,協(xié)調(diào)者發(fā)送通知讓參與者回滾事務。 ![]() 需要注意的是,在準備階段,參與者執(zhí)行了事務,但是還未提交。只有在提交階段接收到協(xié)調(diào)者發(fā)來的通知后,才進行提交或者回滾。 問題同步阻塞 所有事務參與者在等待其它參與者響應的時候都處于同步阻塞狀態(tài),無法進行其它操作。 單點問題 協(xié)調(diào)者在 2PC 中起到非常大的作用,發(fā)生故障將會造成很大影響,特別是在階段二發(fā)生故障,所有參與者會一直等待狀態(tài),無法完成其它操作。 數(shù)據(jù)不一致 在階段二,如果協(xié)調(diào)者只發(fā)送了部分 Commit 消息,此時網(wǎng)絡發(fā)生異常,那么只有部分參與者接收到 Commit 消息,也就是說只有部分參與者提交了事務,使得系統(tǒng)數(shù)據(jù)不一致。 太過保守 任意一個節(jié)點失敗就會導致整個事務失敗,沒有完善的容錯機制。 2PC 優(yōu)缺點優(yōu)點:盡量保證了數(shù)據(jù)的強一致,適合對數(shù)據(jù)強一致要求很高的關鍵領域。(其實也不能 100%保證強一致) 缺點:實現(xiàn)復雜,犧牲了可用性,對性能影響較大,不適合高并發(fā)高性能場景。 4.2. 補償事務(TCC)補償事務(TCC)其核心思想是:針對每個操作,都要注冊一個與其對應的確認和補償(撤銷)操作。它分為三個階段:
舉個例子,假設 Bob 要向 Smith 轉(zhuǎn)賬,思路大概是:
TCC 優(yōu)缺點
4.3. 本地消息表(異步確保)本地消息表與業(yè)務數(shù)據(jù)表處于同一個數(shù)據(jù)庫中,這樣就能利用本地事務來保證在對這兩個表的操作滿足事務特性。
![]() 這種方案遵循 BASE 理論,采用的是最終一致性。 本地消息表利用了本地事務來實現(xiàn)分布式事務,并且使用了消息隊列來保證最終一致性。 本地消息表優(yōu)缺點
4.4. MQ 事務消息有一些第三方的 MQ 是支持事務消息的,比如 RocketMQ,他們支持事務消息的方式也是類似于采用的二階段提交。但是市面上一些主流的 MQ 都是不支持事務消息的,比如 RabbitMQ 和 Kafka 都不支持。 以阿里的 RocketMQ 中間件為例,其思路大致為:
也就是說在業(yè)務方法內(nèi)要想消息隊列提交兩次請求,一次發(fā)送消息和一次確認消息。如果確認消息發(fā)送失敗了 RocketMQ 會定期掃描消息集群中的事務消息,這時候發(fā)現(xiàn)了 Prepared 消息,它會向消息發(fā)送者確認,所以生產(chǎn)方需要實現(xiàn)一個 check 接口,RocketMQ 會根據(jù)發(fā)送端設置的策略來決定是回滾還是繼續(xù)發(fā)送確認消息。這樣就保證了消息發(fā)送與本地事務同時成功或同時失敗。 MQ 事務消息優(yōu)缺點
5. 共識性問題5.1. Paxos用于達成共識性問題,即對多個節(jié)點產(chǎn)生的值,該算法能保證只選出唯一一個值。 主要有三類節(jié)點:
算法需要滿足 safety 和 liveness 兩方面的約束要求(實際上這兩個基礎屬性是大部分分布式算法都該考慮的):
基本過程包括 proposer 提出提案,先爭取大多數(shù) acceptor 的支持,超過一半支持時,則發(fā)送結(jié)案結(jié)果給所有人進行確認。一個潛在的問題是 proposer 在此過程中出現(xiàn)故障,可以通過超時機制來解決。極為湊巧的情況下,每次新的一輪提案的 proposer 都恰好故障,系統(tǒng)則永遠無法達成一致(概率很?。?。 Paxos 能保證在超過 單個提案者+多接收者如果系統(tǒng)中限定只有某個特定節(jié)點是提案者,那么一致性肯定能達成(只有一個方案,要么達成,要么失?。L岚刚咧灰盏搅藖碜远鄶?shù)接收者的投票,即可認為通過,因為系統(tǒng)中不存在其他的提案。 但一旦提案者故障,則系統(tǒng)無法工作。 多個提案者+單個接收者限定某個節(jié)點作為接收者。這種情況下,共識也很容易達成,接收者收到多個提案,選第一個提案作為決議,拒絕掉后續(xù)的提案即可。 缺陷也是容易發(fā)生單點故障,包括接收者故障或首個提案者節(jié)點故障。 以上兩種情形其實類似主從模式,雖然不那么可靠,但因為原理簡單而被廣泛采用。 當提案者和接收者都推廣到多個的情形,會出現(xiàn)一些挑戰(zhàn)。 多個提案者+多個接收者既然限定單提案者或單接收者都會出現(xiàn)故障,那么就得允許出現(xiàn)多個提案者和多個接收者。問題一下子變得復雜了。 一種情況是同一時間片段(如一個提案周期)內(nèi)只有一個提案者,這時可以退化到單提案者的情形。需要設計一種機制來保障提案者的正確產(chǎn)生,例如按照時間、序列、或者大家猜拳(出一個數(shù)字來比較)之類。考慮到分布式系統(tǒng)要處理的工作量很大,這個過程要盡量高效,滿足這一條件的機制非常難設計。 另一種情況是允許同一時間片段內(nèi)可以出現(xiàn)多個提案者。那同一個節(jié)點可能收到多份提案,怎么對他們進行區(qū)分呢?這個時候采用只接受第一個提案而拒絕后續(xù)提案的方法也不適用。很自然的,提案需要帶上不同的序號。節(jié)點需要根據(jù)提案序號來判斷接受哪個。比如接受其中序號較大(往往意味著是接受新提出的,因為舊提案者故障概率更大)的提案。 如何為提案分配序號呢?一種可能方案是每個節(jié)點的提案數(shù)字區(qū)間彼此隔離開,互相不沖突。為了滿足遞增的需求可以配合用時間戳作為前綴字段。 此外,提案者即便收到了多數(shù)接收者的投票,也不敢說就一定通過。因為在此過程中系統(tǒng)可能還有其它的提案。 5.2. RaftRaft 算法是 Paxos 算法的一種簡化實現(xiàn)。 包括三種角色:leader、candidate 和 follower,其基本過程為:
注:此處 log 并非是指日志消息,而是各種事件的發(fā)生記錄。 單個 Candidate 的競選有三種節(jié)點:Follower、Candidate 和 Leader。Leader 會周期性的發(fā)送心跳包給 Follower。每個 Follower 都設置了一個隨機的競選超時時間,一般為 150ms~300ms,如果在這個時間內(nèi)沒有收到 Leader 的心跳包,就會變成 Candidate,進入競選階段。
![]()
![]()
![]()
![]() 多個 Candidate 競選
![]()
![]() 同步日志
![]()
![]()
![]()
![]() 6. 分布式緩存問題6.1. 緩存雪崩緩存雪崩是指:在高并發(fā)場景下,由于原有緩存失效,新緩存未到期間(例如:我們設置緩存時采用了相同的過期時間,在同一時刻出現(xiàn)大面積的緩存過期),所有原本應該訪問緩存的請求都去查詢數(shù)據(jù)庫了,而對數(shù)據(jù)庫 CPU 和內(nèi)存造成巨大壓力,嚴重的會造成數(shù)據(jù)庫宕機。從而形成一系列連鎖反應,造成整個系統(tǒng)崩潰。 解決方案:
緩存失效時產(chǎn)生的雪崩效應,將所有請求全部放在數(shù)據(jù)庫上,這樣很容易就達到數(shù)據(jù)庫的瓶頸,導致服務無法正常提供。盡量避免這種場景的發(fā)生。 6.2. 緩存穿透緩存穿透是指:用戶查詢的數(shù)據(jù),在數(shù)據(jù)庫沒有,自然在緩存中也不會有。這樣就導致用戶查詢的時候,在緩存中找不到,每次都要去數(shù)據(jù)庫再查詢一遍,然后返回空(相當于進行了兩次無用的查詢)。這樣請求就繞過緩存直接查數(shù)據(jù)庫,這也是經(jīng)常提的緩存命中率問題。 當在流量較大時,出現(xiàn)這樣的情況,一直請求 DB,很容易導致服務掛掉。 解決方案:
6.3. 緩存預熱緩存預熱這個應該是一個比較常見的概念,相信很多小伙伴都應該可以很容易的理解,緩存預熱就是系統(tǒng)上線后,將相關的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶請求的時候,先查詢數(shù)據(jù)庫,然后再將數(shù)據(jù)緩存的問題!用戶直接查詢事先被預熱的緩存數(shù)據(jù)! 解決方案:
6.4. 緩存更新除了緩存服務器自帶的緩存失效策略之外(Redis 默認的有 6 中策略可供選擇),我們還可以根據(jù)具體的業(yè)務需求進行自定義的緩存淘汰,常見的策略有兩種:
兩者各有優(yōu)劣,第一種的缺點是維護大量緩存的 key 是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復雜!具體用哪種方案,大家可以根據(jù)自己的應用場景來權衡。 6.5. 緩存降級當訪問量劇增、服務出現(xiàn)問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然需要保證服務還是可用的,即使是有損服務。系統(tǒng)可以根據(jù)一些關鍵數(shù)據(jù)進行自動降級,也可以配置開關實現(xiàn)人工降級。 降級的最終目的是保證核心服務可用,即使是有損的。而且有些服務是無法降級的(如加入購物車、結(jié)算)。 喜歡這篇文章的朋友可以點個喜歡,也可以關注一下我的個人專題:Java成長之路 針對于上面所涉及到的知識點我總結(jié)出了有1到5年開發(fā)經(jīng)驗的程序員在面試中涉及到的絕大部分架構(gòu)面試題及答案做成了文檔和架構(gòu)視頻資料免費分享給大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并發(fā)等架構(gòu)技術資料),希望能幫助到您面試前的復習且找到一個好的工作,也節(jié)省大家在網(wǎng)上搜索資料的時間來學習,也可以關注我一下以后會有更多干貨分享。 資料獲取方式: QQ群搜索“708-701-457” 即可免費領取![]() ![]() ![]() ? 著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者 |
|