阿里資深架構師教你如何設計出一個完美的分佈式系統?

1. 分佈式系統相關概念

1.1 模型程序員

阿里資深架構師教你如何設計出一個完美的分佈式系統?


1.1.1 節點面試

節點是一個能夠獨立按照分佈式協議完成一組邏輯的程序個體,工程中每每指進程。spring

1.1.2 通訊數據庫

節點之間徹底獨立互相隔離,通訊惟一方式是經過不可靠的網絡。服務器

1.1.3 存儲網絡

節點能夠經過將數據寫入與節點在同一臺機器的本地存儲設備保存數據mybatis

1.1.4 異常多線程

(1) 機器down機架構

大型集羣每日down機發生機率0.1%,後果是該機器節點不能工做、重啓後失去全部內存信息。併發

(2) 網絡異常

  • 消息丟失:網絡擁塞、路由變更、設備異常、network partition(部分不正常)

  • 消息亂序:IP存儲轉發、路由不肯定性、網絡報文亂序

  • 數據錯誤:比特錯誤

  • 不可靠TCP:到達協議棧以後與到達進程之間、忽然down機、分佈式多個節點的tcp亂序

(3) 分佈式系統的三態

任何請求都要考慮三種狀況:成功、失敗、超時。對於超時的請求,沒法獲知該請求是否被成功執行。

(4) 存儲數據丟失

(5) 其餘異常

IO操做緩慢、網絡抖動、擁塞

1.2 副本

1.2.1 副本的概念

replica/copy 指在分佈式系統中爲數據或服務提供的冗餘:

  • 數據副本:在不一樣的節點上持久化同一份數據。例如GFS同一個chunk的數個副本

  • 服務副本:數個節點提供相同的服務,服務不依賴本地存儲,數據來自其餘節點。例如Map Reduce的Job Worker

1.2.2 副本的一致性

副本的consistency是針對分佈式系統而言的,不是針對某一個副本而言。根據強弱程度分爲:

  • 強一致性:任什麼時候刻任何用戶/節點均可以讀到最近一次更新成功的副本數據

  • 單調一致性:任什麼時候刻任何用戶一旦讀到某個數據某次更新後的值,就不會再讀到更舊的值

  • 會話一致性:任什麼時候刻任何用戶在某次會話內一旦讀到某個數據某次更新後的值,就不會在此次會話再讀到更舊的值

  • 最終一致性:各個副本的數據最終將達到一致狀態,但時間不保證

  • 弱一致性:沒有實用價值,略。

1.3 衡量分佈式系統的指標

1.3.1 性能

  • 吞吐量:某一時間能夠處理的數據總量

  • 響應延遲:完成某一功能須要使用的時間

  • 併發能力:QPS(query per second)

1.3.2 可用性

系統停服務的時間與正常服務的時間的比例

1.3.3 可擴展性

經過擴展集羣機器提升系統性能、存儲容量、計算能力的特性,是分佈式系統特有的性質

1.3.4 一致性

副本帶來的一致性問題

1.3.5:分佈式架構系統的可視化監控方案

一、架構師是如何解決分佈式架構系統監控難題的。

二、ELK是誰,從哪裏來,要到哪裏去?

三、京東海量數據檢索,咱們一塊兒來感覺。

四、只需點擊鼠標,高逼格監控界面一鍵搞定。

五、你離互聯網架構師到底有遠?聽聽就知道。

六、架構師的技術棧應該是怎樣的?你來問,我必定答。

阿里資深架構師教你如何設計出一個完美的分佈式系統?


阿里資深架構師教你如何設計出一個完美的分佈式系統?


轉發 轉發 轉發 重要的事情說3遍 轉發關注我私信會發:Java架構 領取分佈式架構思惟導圖 以及資深架構師講解的分佈式精講視頻資料(還會提供高併發,spring源碼,mybatis源碼,dubbo,netty等多個知識點的視頻技術分享!

2. 分佈式系統原理

2.1 數據分佈方式

不管計算仍是存儲,問題輸入對象都是數據,如何拆分分佈式系統的輸入數據稱爲分佈式系統的基本問題。

2.1.1 哈希方式

一種常見的哈希方式是按照數據屬於的用戶id計算哈希。

阿里資深架構師教你如何設計出一個完美的分佈式系統?


優勢:

  • 散列性:好

  • 元信息:只須要函數+服務器總量

缺點:

  • 可擴展性:差。一旦集羣規模擴展,大多數數據都須要被遷移並從新分佈

  • 數據傾斜:當某個用戶id的數據量異常龐大時,容易達到單臺服務器處理能力的上限

2.1.2 按數據範圍分佈

將數據按特徵值的值域範圍劃分數據。例如將用戶id的值域分爲[1, 33), [33, 90), [90, 100),由三臺服務器處理。注意區間大小與區間內的數據大小沒有關係。

阿里資深架構師教你如何設計出一個完美的分佈式系統?


優勢:

  • 可擴展性:好。靈活根據數據量拆分原有數據區間

缺點:

  • 元信息:大。容易成爲瓶頸。

2.1.3 按數據量分佈

與按範圍分佈數據方式相似,元信息容易成爲瓶頸

2.1.4 一致性哈希

(1) 以機器爲節點

用一個hash函數計算數據(特徵)的hash值,令該hash函數的值域成爲一個封閉的環,將節點隨機分佈在環上。每一個節點負責處理從本身開始順時針到下一節點的值域上的數據。

優勢:

  • 可擴展性:極好。任意動態添加、刪除節點,隻影響相鄰節點

缺點:

  • 元信息:大並且複雜

  • 隨機分佈節點容易形成不均勻

  • 動態增長節點後只能緩解相鄰節點

  • 一個接點異常時壓力全轉移到相鄰節點

(2) 虛節點

虛節點,虛節點個數遠大於機器個數,將虛節點均勻分佈到值域環上,經過元數據找到真實機器節點。

優勢:

  • 某一個節點不可用致使多個虛節點不可用,均衡了壓力

  • 加入新節點致使增長多個虛節點,緩解了全局壓力

2.1.5 副本與數據分佈

前邊4中數據分佈方式的討論中沒有考慮數據副本的問題。

(1) 以機器爲單位的副本

阿里資深架構師教你如何設計出一個完美的分佈式系統?


缺點:

  • 恢復效率:低。假如1出問題,從2 3 中全盤拷貝數據較消耗資源,爲避免影響服務通常會將2下線專門作拷貝,致使正常工做的副本只有3

  • 可擴展性:差。假如系統3臺機器互爲副本,只增長兩臺機器的狀況下沒法組成新的副本組。

  • 可用性:差。一臺donw機,剩下兩臺壓力增長50%。理想狀況會均攤到整個集羣,而不是單個副本組

(2) 以數據段爲單位的副本

例如3臺服務器,10G數據,按100hash取模獲得100M每一個的數據段,每臺服務器負責333個數據段。一旦將數據分紅數據段,就能夠以數據段爲單位管理副本,副本與機器再也不硬相關。

例如系統中3個數據o p q, 每一個數據段有三個副本,系統中有4臺機器:

阿里資深架構師教你如何設計出一個完美的分佈式系統?


優勢:

  • 恢復效率:高。能夠整個集羣同時拷貝

  • 可用性:好。機器donw機的壓力分散到整個集羣

工程中徹底按照數據段創建副本會引發元數據開銷增大,這種作法是將數據段組成一個大數據段。

2.1.6 本地化計算

若是計算節點和存儲節點位於不一樣的物理機器,開銷很大,網絡帶寬會成爲系統的瓶頸;將計算調度到與存儲節點在同一臺物理機器上的節點計算,稱爲計算本地化。

2.2 基本副本協議

2.2.1 中心化副本控制協議

  • 中心化副本控制協議的基本思路:由一箇中心節點協調副本數據的更新、維護副本之間一致性,併發控制

  • 併發控制:多個節點同時須要修改副本數據時,須要解決的「寫寫」、「讀寫」等併發衝突

單機系統使用加鎖等方式進行併發控制,中心化協議也可使用。缺點是過度依賴中心節點。

阿里資深架構師教你如何設計出一個完美的分佈式系統?


2.2.2 primary-secondary協議

這是一種經常使用的中心化副本控制協議,有且僅有一個節點做爲primary副本。有4個問題須要解決:

(1) 數據更新基本流程

  • 由primary協調完成更新

  • 外部節點將更新操做發給primary節點

  • primary節點進行併發控制並肯定併發更新操做的前後順序

  • primary節點將更新操做發送給secondary節點

  • primary根據secondary節點的完成狀況決定更新是否成功,而後將結果返回外部節點

阿里資深架構師教你如何設計出一個完美的分佈式系統?


其中第4步,有些系統如GFS使用接力的方式同步數據,primary -> secondary1 ->secondary2,避免primary的帶寬稱爲瓶頸。

(2) 數據讀取方式

  • 方法一:因爲數據更新流程都是由primary控制的,primary副本上數據必定最新。因此永遠只讀primary副本的數據可以實現強一致性。爲了不機器浪費,可使用以前討論的方法,將數據分段,將數據段做爲副本單位。達到每臺機器都有primary副本的目的。

  • 方法二:由primary控制secondary的可用性。當primary更新某個secondary不成功時,將其標記爲不可用。不可用的secondary副本繼續嘗試與primary同步數據,直到成功同步後轉爲可用狀態。

  • 方法三:Quorum機制。後續討論。

(3) primary副本的肯定與切換

  • 如何肯定primary副本?primary副本所在機器異常時,如何切換副本?

  • 一般在primary-secondary分佈式系統中,哪一個副本爲primary這一信息屬於元信息,由專門元數據服務器維護。執行更新操做時,首先查詢元數據服務器獲取副本的primary信息,進一步執行數據更新流程。

  • 切換副本難點有兩個方面:如何肯定節點狀態以發現原primary節點出現異常(Lease機制)。切換primary後不能影響一致性(Quorum機制)。

(4) 數據同步

當發生secondary與primary不一致的狀況,須要secondary向primary進行同步(reconcile)。

不一致的緣由有3種:

  • 網絡分化等異常致使secondary落後於primary

  • 經常使用的方式是回放primary上的操做日誌(redo日誌),追上primary的更新進度

  • 某些協議下secondary是髒數據

  • 丟棄轉到第三種狀況;或者設計基於undo日誌的方式

  • secondary是一個新增副本徹底沒有數據

  • 直接copy primary的數據,但要求同時primary能繼續提供更新服務,這就要求primary副本支持快照(snapshot)功能。即對某一刻的副本數據造成快照,而後copy快照,再使用回放日誌的方式追趕快照後的更新操做。

2.2.3 去中心化副本控制協議

去中心化副本控制協議沒有中心節點,節點之間經過平等協商達到一致。工程中惟一能應用在強一致性要求下的是paxos協議。後續介紹。

2.3 lease機制

2.3.1 基於lease的分佈式cache系統

(1) 需求:分佈式系統中有一個節點A存儲維護系統的元數據,系統中其餘節點經過訪問A讀取修改元數據,致使A的性能成爲系統瓶頸。爲此,設計一種元數據cache,在各個節點上cache元數據信息,使得:

  • 減小對A的訪問,提升性能

  • 各個節點cache數據始終與A一致

  • 最大可能處理節點down機、網絡中斷等異常

(2) 解決方案原理:

  • A向各個節點發送數據的同時向節點頒發一個lease,每一個lease具備一個有效期,一般是一個明確的時間點。一旦真實時間超過次時間點則lease過時

  • 在lease有效期內,A保證不會修改對應數據的值。

  • A在修改數據時,首先阻塞全部新的讀請求,等待以前爲該數據發出的全部lease過時,而後修改數據的值

(3) 客戶端節點讀取元數據的流程

if (元數據處於本地cache && lease處於有效期內) {
 直接返回cache中的元數據;
} else {
 Result = 向A請求讀取元數據信息;
 if (Result.Status == SUCCESS) {
 WriteToCache(Result.data, Result.lease);
 } else if (Result.Status == FAIL || Result.Status == TIMEOUT) {
 retry() or exit();
 }
}

(4) 客戶端節點修改元數據的流程

  • 節點向A發起修改元數據的請求

  • A收到修改請求後阻塞全部新的讀數據請求,即接受讀請求但不返回數據

  • A等待全部與該元數據相關的lease超時

  • A修改元數據並向節點返回修改爲功

(5) 優化點

  • A修改元數據時要阻塞全部新的讀請求

  • 這是爲了防止發出新的lease而引發不斷有新的cache節點持有lease,造成活鎖。優化的手段是:一旦A進入修改流程,不是盲目屏蔽讀請求,而是對讀請求只返回數據不返回lease。形成cache節點只能讀取數據,不能cache數據。進一步的優化是返回當前已發出的lease的最大值。這樣一樣能避免活鎖問題。

  • A在修改元數據時須要等待全部lease過時

  • 優化手段是:A主動通知各個持有lease的節點,放棄lease並清除cache中相關數據。若是收到cache節點的reply,確認協商經過,則能夠提早完成修改動做;若是中間失敗或超時,則進入正常等待lease過時的流程,不會影響協議正確性。

2.3.2 lease機制的深刻分析

(1) lease定義

lease是由頒發者授予的再某一有效期內的承諾。頒發者一旦發出lease,不管接收方是否收到,不管後續接收方處於何種狀態,只要lease不過時則頒發者必定嚴守承諾;另外一方面,接受者在lease的有效期內可使用頒發者的承諾,一旦lease過時則必定不能繼續使用。

(2) lease的解讀

因爲lease僅僅是一種承諾,具體的承諾內容能夠很是寬泛,能夠是上節中數據的正確性,也能夠是某種權限。例如併發控制中同一時刻只給某一個節點頒發lease,只有持有lease才能修改數據;例如primary-secondary中持有lease的節點具備primary身份等等

(3) lease的高可用性

  • 有效期的引入,很是好的解決了網絡異常問題。因爲lease是肯定的時間點,因此能夠簡單重發;一旦受到lease以後,就再也不依賴網絡通訊

(4) lease的時鐘同步

工程上將頒發者有效期設置的比接受者打,大過期鍾偏差,來避免對lease有效性產生影響。

2.3.3 基於lease機制肯定節點狀態。

在分 布式系統中肯定一個節點是否處於正常工做狀態困難的問題。由可能存在網絡分化,節點的狀態沒法經過網絡通訊來肯定的。

例如: a b c 互爲副本 a爲主節點,q爲監控節點。q經過ping來判斷abc的狀態,認爲a不能工做。就將主節點切換成b。可是事實上僅僅是ping沒收到,a本身認爲本身沒有問題,就出現了 a b都以爲本身是主節點的「雙主」問題。

解決方法是q在發送heartbeat時加上lease,表示確認了abc的狀態,並容許節點在lease有效期內正常工做。q給primary節點一個特殊的lease,表示該節點做爲primary工做。一旦q但願切換primary,只須要等待以前primary的lease過時,避免出現雙主問題。

2.3.4 lease的有效期時間選擇

工程上通常選擇10秒鐘

2.4 Quorum機制

2.4.1 Write-all-read-one

對於某次更新操做Wi,只有在全部N個副本上都更新成功,才認爲是一次「成功提交的更新操做」,對應的數據爲「成功提交的數據」,數據版本爲Vi。

缺點:

  • 頻繁讀寫版本號容易成爲瓶頸

  • N-1個副本成功的狀況下,仍然被認爲更新失敗

2.4.2 Quorum定義

WARO最大程度加強讀服務可用性,最大程度犧牲寫服務的可用性。將讀寫可用性折中,就會獲得Quorum機制:

Quorum機制下,某次更新Wi一旦在全部N個副本中的W個副本上成功,就稱爲「成功提交的更新操做」,對應的數據爲「成功提交的數據」。令R > N - W,最多須要讀取R個副本則必定能讀到Wi更新後的數據Vi。

阿里資深架構師教你如何設計出一個完美的分佈式系統?


因而可知WARO是Quorum中W = N時的一個特例。

2.4.3 讀取最新成功提交的數據

Quorum的定義基於兩個假設:

  • 讀取者知道當前已提交的版本號

  • 每次都是一次成功的提交

如今取消這兩個假設,分析下面這個實際問題:

N = 5, W = 3, R = 3,某一次的副本狀態爲(V2 V2 V2 V1 V1)。理論上讀取任何3個副本必定能讀到最新的數據V2,可是僅讀3個副本卻沒法肯定讀到最新的數據。

例如讀到的是(V2 V1 V1),由於當副本狀態爲(V2 V1 V1 V1 V1)時也會讀到(V2 V1 V1),而此時V2版本的數據是一次失敗的提交。所以只讀3個沒法肯定最新有效的版本是V2仍是V1。

阿里資深架構師教你如何設計出一個完美的分佈式系統?


解決方案:

  • 限制提交的更新操做必須嚴格遞增,只有前一個更新操做成功後才能夠提交下一個。保證成功的版本號連續

  • 讀取R個副本,對其中版本號最高的數據:若已存在W個,則該數據爲最新結果;不然假設爲X個,則繼續讀取其餘副本直到成功讀取W個該版本的副本。若是沒法找到W個,則第二大的版本號爲最新成功提交的版本。

所以單純使用Quorum機制時,最多須要讀取R + (W - R - 1) = N個副本才能肯定最新成功提交的版本。實際工程中通常使用quorum與primary-secondary結合的手段,避免須要讀取N個副本。

2.4.4 基於Quorum機制選擇primary

  • 在primary-secondary協議中引入quorum機制:即primary成功更新W個副本後向用戶返回成功

  • 當primary異常時須要選擇一個新的primary,以後secondary副本與primary同步數據

一般狀況下切換primary由監控節點q完成,引入quorum以後,選擇新的primary的方式與讀取數據類似,即q讀取R個副本,選擇R個副本中版本號最高的副本做爲新的primary。新primary與除去q選舉出的副本外,其他的至少W個副本完成數據同步後,再做爲新的primary。

蘊含的道理是:

  • R個副本中版本號最高的副本必定蘊含了最新的成功提交的數據。

  • 雖然不能肯定版本號最高的數據 == 這個最新成功提交的數據,但新的primary當即完成了對W個副本的更新,從而使其變成了成功提交的數據

例如:N = 5 W = 3 R = 3的系統,某時刻副本狀態(V2 V2 V1 V1 V1),此時V1是最新成功提交的數據,V2是處於中間狀態未成功提交的數據。V2是做爲髒數據扔掉,仍是做爲新數據被同步,徹底取決於可否參與q主持的新primary的選舉大會。若是q選擇(V1 V1 V1),則在接下來的更新過程當中 V2會被當成髒數據扔掉;若是q選擇(V2 V1 V1)則V2會將V1更新掉,成爲最新成功的數據。

阿里資深架構師教你如何設計出一個完美的分佈式系統?


阿里資深架構師教你如何設計出一個完美的分佈式系統?


2.5 日誌技術

日誌技術不是一種分佈式系統技術,但分佈式系統普遍使用日誌技術作down機恢復。

2.5.1 數據庫系統日誌回顧

數據庫的日誌分爲 undo redo redo/undo no-redo/no-undo四種,這裏不作過多介紹。

2.5.2 redo與check point

經過redo log恢復down機的缺點是須要掃描整個redolog,回放全部redo日誌。解決這個問題的辦法是引入checkpoint技術,簡化模型下checkpoint就是在begin和end中間,將內存以某種數據組織方式dump到磁盤上。這樣down機恢復時只須要從最後一個end向前找到最近一個begin,恢復中間的內存狀態便可。

2.5.3 no-undo/no-redo

這種技術也叫作01目錄,即有兩個目錄,活動目錄和非活動目錄,另外還有一個主記錄,要麼「記錄目錄0」,妖魔記錄「使用目錄1」,目錄0和1記錄了各個數據在日誌文件中的位置。

2.6 兩階段提交協議

2.7 基於MVCC的分佈式事務

因爲這兩個都與數據庫事務有關,且兩階段提交協議在工程中使用價值不高,均略去不談。

2.8 Paxos協議

惟一在工程中有使用價值的去中心化副本節點控制協議。過於複雜,沒看懂。

2.9 CAP理論

  • Consitency

  • Availiablity

  • Tolerance to the Partition of network

沒法設計一種分佈式協議,使得徹底具有CAP三個屬性。永遠只能介於三者之間折中。理論的意義是:不要妄想設計完美的分佈式系統。

推薦閱讀:

馬士兵教育2020最新最全版馬士兵高併發多線程450分鐘教程,【從入門到精通】

面試美團被JVM慘虐?阿里P9架構師用500分鐘把JVM從入門講到實戰#合集

硬核!清華雙大佬馬士兵VS周志磊把TCP協議、高併發負載均衡、多線程、JVM底層給講清楚了

四十歲的Java程序員活該被淘汰?馬士兵給全部Java程序員的忠告,告知當代應屆生進大廠的祕訣

相關文章
相關標籤/搜索