分散式儲存架構知識,一篇講清楚!

ITPUB社群發表於2022-11-22

【摘要】本文介紹了分散式儲存的架構型別、分散式理論、不同的分散式檔案系統和分散式鍵值系統等,較為系統詳盡。全文約2萬字,可收藏。

【作者】Rock,目前擔任某國內著名餐飲連鎖企業運維負責人,從事過資料庫、大資料和容器叢集的工作,對DevOps流程和工具方面有比較深刻的理解。


目錄

一、集中儲存結構

二、分散式儲存

1 、分散式儲存的興起

2 、分散式儲存的重要性

3 、分散式儲存的種類和比較

三、分散式理論淺析

1 、一致性和可用性

2 、資料分佈

3 、複製

4 、分散式協議

5、跨機房部署

四、分散式檔案系統

1、 Google 檔案系統( GFS )

2、 Taobao 檔案系統( TFS )

3、 Fackbook Haystack 檔案系統

4、 CDN 內容分發網路

五、分散式鍵值系統

1、 Amazon Dynamo

2、 Taobao Tiar

3、 ETCD

4 、產品選型比較( Etcd , Zookeeper , Consul )


一、集中儲存結構

說到分散式儲存,我們先來看一下傳統的儲存是怎麼個樣子。

傳統的儲存也稱為集中式儲存, 從概念上可以看出來是具有集中性的,也就是整個儲存是集中在一個系統中的,但集中式儲存並不是一個單獨的裝置,是集中在一套系統當中的多個裝置,比如下圖中的 EMC 儲存就需要幾個機櫃來存放。

分散式儲存架構知識,一篇講清楚!

在這個儲存系統中包含很多元件,除了核心的機頭(控制器)、磁碟陣列( JBOD )和交換機等裝置外,還有管理裝置等輔助裝置。

結構中包含一個機頭,這個是儲存系統中最為核心的部件。通常在機頭中有包含兩個控制器,互為備用, 避免硬體故障導致整個儲存系統的不可用。機頭中通常包含前端埠和後端埠,前端埠使用者為伺服器提供儲存服務,而後端埠用於擴充儲存系統的容量。透過後端埠機頭可以連線更多的儲存裝置,從而形成一個非常大的儲存資源池。

在整個結構中,機頭中是整個儲存系統的核心部件,整個儲存系統的高階功能都在其中實現。控制器中的軟體實現對磁碟的管理,將磁碟抽象化為儲存資源池,然後劃分為 LUN 提供給伺服器使用。這裡的 LUN 其實就是在伺服器上看到的磁碟 。當然,一些集中式儲存本身也是檔案伺服器,可以提供共享檔案服務。無論如何,從上面我們可以看出集中式儲存 最大的特點是有一個統一的入口,所有資料都要經過這個入口 ,這個入口就是儲存系統的機頭。這也就是集中式儲存區別於分散式儲存最顯著的特點。如下圖所示:

分散式儲存架構知識,一篇講清楚!


二、分散式儲存

分散式儲存最早是由谷歌提出的,其目的是透過廉價的伺服器來提供使用與大規模,高併發場景下的 Web 訪問問題。它 採用可擴充套件的系統結構,利用多臺儲存伺服器分擔儲存負荷,利用位置伺服器定位儲存資訊,它不但提高了系統的可靠性、可用性和存取效率,還易於擴充套件。

1 、分散式儲存的興起

分散式儲存的興起與網際網路的發展密不可分,網際網路公司由於其資料量大而資本積累少,而通常都使用大規模分散式儲存系統。

與傳統的高階伺服器、高階儲存器和高階處理器不同的是,網際網路公司的分散式儲存系統由數量眾多的、低成本和高價效比的普通 PC 伺服器透過網路連線而成。其主要原因有以下三點

(1) 網際網路的業務發展很快,而且注意成本消耗,這就使得儲存系統不能依靠傳統的縱向擴充套件的方式,即先買小型機,不夠時再買中型機,甚至大型機。網際網路後端的分散式系統要求支援橫向擴充套件,即透過增加普通 PC 伺服器來提高系統的整體處理能力。

(2) 普通 PC 伺服器價效比高,故障率也高,需要在軟體層面實現自動容錯,保證資料的一致性。

(3) 另外,隨著伺服器的不斷加入,需要能夠在軟體層面實現自動負載均衡,使得系統的處理能力得到線性擴充套件。

2 、分散式儲存的重要性

從單機單使用者到單機多使用者,再到現在的網路時代,應用系統發生了很多的變化。而分散式系統依然是目前很熱門的討論話題,那麼,分散式系統給我們帶來了什麼,或者說是為什麼要有分散式系統呢?

(1)升級單機處理能力的價效比越來越低;

企業發現透過更換硬體做垂直擴充套件的方式來提升效能會越來越不划算;

(2)單機處理能力存在瓶頸;

某個固定時間點,單顆處理器有自己的效能瓶頸,也就說即使願意花更多的錢去買計算能力也買不到了;

(3)出於穩定性和可用性的考慮

如果採用單擊系統,那麼在這臺機器正常的時候一切 OK ,一旦出問題,那麼系統就完全不能用了。當然,可以考慮做容災備份等方案,而這些方案就會讓系統演變為分散式系統了;

(4)雲端儲存和大資料發展的必然要求

雲端儲存和大資料是構建在分散式儲存之上的應用。移動終端的計算能力和儲存空間有限,而且有在多個裝置之間共享資源的強烈的需求,這就使得網盤、相簿等雲端儲存應用很快流行起來。然而,萬變不離其宗,雲端儲存的核心還是後端的大規模分散式儲存系統。大資料則更近一步,不僅需要儲存海量資料,還需要透過合適的計算框架或者工具對這些資料進行分析,抽取其中有價值的部分。如果沒有分散式儲存,便談不上對大資料進行分析。仔細分析還會發現,分散式儲存技術是網際網路後端架構的神器,掌握了這項技能,以後理解其他技術的本質會變得非常容易。

3 、分散式儲存的種類和比較

分散式儲存包含的種類繁多,除了傳統意義上的分散式檔案系統、分散式塊儲存和分散式物件儲存外,還包括分散式資料庫和分散式快取等,但其中架構無外乎於三種

A、 中間控制節點架構

以 HDFS ( Hadoop Distribution File System )為代表的架構是典型的代表。在這種架構中,一部分節點 NameNode 是存放管理資料(後設資料),另一部分節點 DataNode 存放業務資料,這種型別的伺服器負責管理具體資料。這種架構就像公司的層次組織架構, namenode 就如同老闆,只管理下屬的經理( datanode ),而下屬的經理,而經理們來管理節點下本地盤上的資料。

分散式儲存架構知識,一篇講清楚!

在上圖中, 如果客戶端需要從某個檔案讀取資料,首先從 NameNode 獲取該檔案的位置(具體在哪個 DataNode ),然後從該 NameNode 獲取具體的資料。在該架構中 NameNode 通常是主備部署( Secondary NameNode ),而 DataNode 則是由大量節點構成一個叢集。由於後設資料的訪問頻度和訪問量相對資料都要小很多,因此 NameNode 通常不會成為效能瓶頸,而 DataNode 叢集中的資料可以有副本,既可以保證高可用性,可以分散客戶端的請求。因此,透過這種分散式儲存架構可以透過橫向擴充套件 datanode 的數量來增加承載能力,也即實現了動態橫向擴充套件的能力。

B、 完全無中心架構 – 計算模式

以 Ceph 為代表的架構是其典型的代表。在該架構中與 HDFS 不同的地方在於該架構中沒有中心節點。客戶端是透過一個裝置對映關係 計算出來 其寫入資料的位置,這樣客戶端可以直接與儲存節點通訊,從而避免中心節點的效能瓶頸。

分散式儲存架構知識,一篇講清楚!

如上圖所示, 在 Ceph 儲存系統架構中核心元件有 MON 服務、 OSD 服務和 MDS 服務等。

(1) MON 服務用於維護儲存系統的硬體邏輯關係,主要是伺服器和硬碟等線上資訊。MON 服務透過叢集的方式保證其服務的可用性。

(2) OSD 服務用於實現對磁碟的管理,實現真正的資料讀寫,通常一個磁碟對應一個 OSD 服務。

(3) MDS 只為 CephFS 檔案儲存系統跟蹤檔案的層次機構和儲存後設資料。Ceph 塊裝置和 RADOS 並不需要後設資料,因此也不需要 Ceph MDS 守護程式

(4) RADOS :RADOS 就是包含上述三種服務的 ceph 儲存叢集。在 Ceph 中所有的資料都以物件形式存在的,並且無論哪種資料型別 RADOS 物件儲存都將負責儲存這些物件。RADOS 層可以確保資料始終保持一致性。要做到這一點必須執行資料複製、故障檢測和恢復,以及資料遷移和所在叢集節點實現在平衡

(5) RBD (塊裝置):原名 RADOS 塊裝置,提供可靠的分散式和高效能塊儲存磁碟給客戶端。

(6) CephFS :Ceph 檔案系統提供了一個使用 Ceph 儲存叢集儲存使用者資料的與 POSIX 相容的檔案系統

(7) Librados :libRADOS 庫為 PHP 、 RUBY 、 Java 、 Python 、 C++ 等語言提供 了方便的訪問 RADOS 介面的方式

(8) RADOS GW :RGW 提供物件儲存服務,它允許應用程式和 Ceph 物件儲存建立連線, RGW 提供了與 Amazon S3 和 openstack Swift 相容的 RUSTFUL API

客戶端訪問儲存的大致流程是,客戶端在啟動後會首先透過 RADOS GW 進入,從 MON 服務拉取儲存資源佈局資訊,然後根據該佈局資訊和寫入資料的名稱等資訊計算出期望資料的位置(包含具體的物理伺服器資訊和磁碟資訊),然後和該位置資訊對應的 CephFS 對應的位置直接通訊,讀取或者寫入資料

C、 完全無中心架構 – 一致性雜湊

以 swift 為代表的架構是其典型的代表。與 Ceph 的透過計算方式獲得資料位置的方式不同,另外一種方式是透過一致性雜湊的方式獲得資料位置。一致性雜湊的方式就是將裝置做成一個雜湊環,然後根據資料名稱計算出的雜湊值對映到雜湊環的某個位置,從而實現資料的定位。

Swift 中存在兩種對映關係,對於一個檔案,透過雜湊演算法( MD5 )找到對應的虛節點(一對一的對映關係),虛節點再透過對映關係( ring 檔案中二維陣列)找到對應的裝置(多對多的對映關係),這樣就完成了一個檔案儲存在裝置上的對映。

分散式儲存架構知識,一篇講清楚!

D 、分散式儲存的比較

那麼現在問題來了,如果我們要選擇分散式儲存,選擇哪種好呢?其實它們各有各的優勢和使用場景,具體要看需求。

(1)HDFS

主要用於大資料的儲存場景,是 Hadoop 大資料架構中的儲存元件。HDFS 在開始設計的時候,就已經明確的它的應用場景,就是大資料服務。主要的應用場景有:

a 、對大檔案儲存的效能比較高,例如幾百兆,幾個 G 的大檔案。因為 HDFS 採用的是以後設資料的方式進行檔案管理,而後設資料的相關目錄和塊等資訊儲存在 NameNode 的記憶體中, 檔案數量的增加會佔用大量的 NameNode 記憶體。如果存在大量的小檔案,會佔用大量記憶體空間,引起整個分散式儲存效能下降,所以儘量使用 HDFS 儲存大檔案比較合適。

b 、適合低寫入,多次讀取的業務。就大資料分析業務而言,其處理模式就是一次寫入、多次讀取,然後進行資料分析工作, HDFS 的資料傳輸吞吐量比較高,但是資料讀取延時比較差,不適合頻繁的資料寫入。

c 、 HDFS 採用多副本資料保護機制,使用普通的 X86 伺服器就可以保障資料的可靠性,不推薦在虛擬化環境中使用。

( 2 ) Ceph

目前應用最廣泛的開源分散式儲存系統,已得到眾多廠商的支援,許多超融合系統的分散式儲存都是基於 Ceph 深度定製。而且 Ceph 已經成為 LINUX 系統和 OpenStack 的 “ 標配 ” ,用於支援各自的儲存系統。Ceph 可以提供物件儲存、塊裝置儲存和檔案系統儲存服務。同時支援三種不同型別的儲存服務的特性,在分散式儲存系統中,是很少見的。

a、 Ceph 沒有采用 HDFS 的後設資料定址的方案,而且採用 CRUSH 演算法,資料分佈均衡,並行度高。而且在支援塊儲存特性上,資料可以具有強一致性,可以獲得傳統集中式儲存的使用體驗。

b、 物件儲存服務, Ceph 支援 Swift 和 S3 的 API 介面。在塊儲存方面,支援精簡配置、快照、克隆。在檔案系統儲存服務方面,支援 Posix 介面,支援快照。但是目前 Ceph 支援檔案的效能相當其他分散式儲存系統,部署稍顯複雜,效能也稍弱,一般都將 Ceph 應用於塊和物件儲存。

c、 Ceph 是去中心化的分散式解決方案,需要提前做好規劃設計,對技術團隊的要求能力比較高。特別是在 Ceph 擴容時,由於其資料分佈均衡的特性,會導致整個儲存系統效能的下降

( 3 )Swift

主要面向的是物件儲存。和 Ceph 提供的物件儲存服務類似。主要用於解決非結構化資料儲存問題。它和 Ceph 的物件儲存服務的主要區別是。

a 、客戶端在訪問物件儲存系統服務時, Swift 要求客戶端必須訪問 Swift 閘道器才能獲得資料。而 Ceph 使用一個執行在每個儲存節點上的 OSD (物件儲存裝置)獲取資料資訊,沒有一個單獨的入口點,比 Swift 更靈活一些。

b 、資料一致性方面, Swift 的資料是最終一致,在海量資料的處理效率上要高一些,但是主要面向對資料一致性要求不高,但是對資料處理效率要求比較高的物件儲存業務。而 Ceph 是始終跨叢集強一致性。主要的應用場景,在 OpenStack 中,物件儲存服務使用的就是 Swift ,而不是 Ceph 。


三、分散式理論淺析

1 、一致性和可用性

由於異常的存在,分散式儲存系統設計時往往會將資料冗餘儲存多份,每一份稱為一個副本)。這樣,當某一個節點出現故障時,可以從其他副本上讀到資料。可以這麼認為,副本是分散式儲存系統容錯技術的唯一手段。由於多個副本的存在,如何保證副本之間的一致性是整個分散式系統的理論核心。

資料一致性這個單詞在平常開發中,或者各種文章中都能經常看見,我們常常聽見什麼東西資料不一致了,造成了一定的損失,趕快修復一下。那有幾種一致性呢?

a、 時間一致性:要求所有資料元件的資料在任意時刻都是完全一致的;

b、 事物一致性:事務一致性只能存在在事務開始前的和事務完成之後,在事務過程中資料有可能不一致,比如 A 轉 100 元給 B , A 扣減 100 , B 加上 100 ,在事務開始前和事務完成之後都能保證他們的帳是對上的,那麼這就是事務一致性。但是在事務過程中有可能會出現 A 扣減了 100 元, B 沒有加上 100 元的情況,這就是不一致

c、 在應用程式中涉及多個不同的單機事務,只有在所有的單機事務完成之前和完成之後,資料是完全一致的。

僅僅靠這三種一致性在實際的一些複雜場合是很難描述清楚的,所以,我們引出了一致性模型,這裡我們由強到弱簡單的介紹幾種常見的一致性模型。

A 、線性一致性

又稱強一致性, 可以看做只有一個單核處理器,或者可以看做只有一個資料副本,並且所有操作都是原子的。

分散式儲存架構知識,一篇講清楚!

如上圖所示,對於事件 e1 和 e2 來說,如果事件 e1 的 response 是在事件 e2 的 invoke 之前,我們就說 e1 happen before e2 。

對於同一個執行緒來說,前面的事件一定 happen before 後面的事件。但是對於不同執行緒上的兩個事件來說,它們之間只有在在時間線上沒有交叉的情況下,才會存在 happen before 關係。對於有交叉的那些事件,比如下圖中的 event2 和 event3 ,它們兩個就不存在 happen before 關係,對於我們要尋找的合法順序執行過程來說,它們兩個的順序可以是任意的。

B 、順序一致性

順序一致性弱於嚴格一致性。對變數的寫操作不一定要在瞬間看到,但是,不同處理器對變數的寫操作必須在所有處理器上以相同的順序看到,這裡處理器再分散式系統中可以換成不同的節點。

分散式儲存架構知識,一篇講清楚!
分散式儲存架構知識,一篇講清楚!

假設有兩個執行緒 A 和 B 併發執行。其中 A 執行緒由 3 個操作構成,它們在程式中的順序是:A1->A2->A3. B 執行緒也有 3 個操作,它們在程式中的順序是:B1->B2->B3. 假設如果在順序一致的模型中的效果就是如上兩個圖所示。

C 、因果一致性

因果一致性是弱於順序一致性的一致性模型,順序一致性要求所有的操作的順序都必須按照某個單個處理器 ( 節點 ) 的順序,而因果一致性只需要滿足有因果關係的操作是順序一致性即可。

分散式儲存架構知識,一篇講清楚!

簡單來說如果有人問你一個問題,那麼你給出答案,這兩個就是因果關係,但如果你給出答案再問題之前,那麼這個就違反了因果關係。舉個簡單的例子如果節點 1 更新了資料 A ,節點 2 讀取資料 A ,並更新資料 B ,這裡的資料 B 有可能是根據資料 A 計算出來的,所有具備因果關係,但是如果節點 3 看到的是先更新的 B ,再更新的 A 那麼就破壞了因果一致性。

D 、最終一致性

其實除了強一致以外,其他的一致性都可以看作為最終一致性,只是根據一致性不同模型的不同要求又衍生出了很多具體一致性模型。當然最簡單的最終一致性,是不需要關注中間變化的順序,只需要保證在某個時間點一致即可。只是這個某個時間點需要根據不同的系統,不同業務再去衡量。再最終一致性完成之前,有可能返回任何的值,不會對這些值做任何順序保證。

E 、可用性

可用性指“ Reads and writes always succeed” ,即服務一直可用,而且是正常響應時間。對於一個可用性的分散式系統,每一個非故障的節點必須對每一個請求作出響應。所以,一般我們在衡量一個系統的可用性的時候,都是透過停機時間來計算的。

可用性分類

可用水平(%)

年可容忍停機時間

容錯可用性

99.9999

<1 min

極高可用性

99.999

<5 min

具有故障自動恢復能力的可用性

99.99

<53 min

高可用性

99.9

<8.8h

商品可用性

99

<43.8 min

通常我們描述一個系統的可用性時,我們說淘寶的系統可用性可以達到 5 個 9 ,意思就是說他的可用水平是 99.999% ,即全年停機時間不超過 (1-0.99999)36524*60 = 5.256 min ,這是一個極高的要求。

好的可用性主要是指系統能夠很好的為使用者服務,不出現使用者操作失敗或者訪問超時等使用者體驗不好的情況。一個分散式系統,上下游設計很多系統如負載均衡、 WEB 伺服器、應用程式碼、資料庫伺服器等,任何一個節點的不穩定都可以影響可用性

F 、分散式系統的一致性

2000 年 7 月,加州大學伯克利分校的 Eric Brewer 教授在 ACM PODC 會議上提出 CAP 猜想。2 年後,麻省理工學院的 Seth Gilbert 和 Nancy Lynch 從理論上證明了 CAP 。之後, CAP 理論正式成為分散式計算領域的公認定理。

CAP 理論概述:一個分散式系統最多隻能同時滿足一致性( Consistency )、可用性( Availability )和分割槽容錯性( Partition tolerance )這三項中的兩項。

分散式儲存架構知識,一篇講清楚!

需要特別指出的 CAP 中的一致性是 all nodes see the same data at the same time ,也就是線性一致性。

一致性必須從兩個維度看:

( 1 )從客戶端角度,多程式併發訪問時,非分散式資料庫要求更新過的資料能被後續的訪問都能看到,所有都是強一致的;

( 2 )從服務端角度,如何儘快將更新後的資料分佈到整個系統,降低達到最終一致性的時間視窗,是提高系統的可用度和使用者體驗非常重要的方面。

參考以下公式:

N — 資料複製的份數

W — 更新資料時需要保證寫完成的節點數

R — 讀取資料的時候需要讀取的節點數

(1) 如果 W+R>N ,寫的節點和讀的節點重疊,則是強一致性。例如對於典型的一主一備同步複製的關係型資料庫, N=2,W=2,R=1 ,則不管讀的是主庫還是備庫的資料,都是一致的。

(2) 如果 W+R<=N ,則是弱一致性。例如對於一主一備非同步複製的關係型資料庫, N=2,W=1,R=1 ,則如果讀的是備庫,就可能無法讀取主庫已經更新過的資料,所以是弱一致性。

對於一個分散式系統來說。P 是一個基本要求, CAP 三者中,只能在 CA 兩者之間做權衡,並且要想盡辦法提升 P 。

包含兩種系統:CP without A**、 AP without C**

我們在上文所提到的 Hdfs 、 Ceph 、 Swift, 均是屬於CP without A的這個大類,只是並不是完全沒有 A ,為了實現一定的可用性,一般設定副本的個數為 N>=3 。不同的 N,W,R 組合,是在可用性和一致性之間取一個平衡,以適應不同的應用場景。

那麼,實際生活中,也有一些是AP without C的案例,如 CAP 圖中所示,大部分是 Nosql 、 CoachDB 、 Cassandra 資料庫,那場景是哪些呢?

其實就是不要求正確性的場合,如某米的搶購手機場景或 12306 搶購火車票的場景,可能前幾秒你瀏覽商品的時候頁面提示是有庫存的,當你選擇完商品準備下單的時候,系統提示你下單失敗,商品已售完。這其實就是先在 A(可用性)方面保證系統可以正常的服務,然後在資料的一致性方面做了些犧牲。

2 、資料分佈

分散式系統區別於傳統單機系統在於能夠將資料分佈到多個節點,並在多個節點之間實現負載均衡。資料分佈的方式主要有兩種,一種是雜湊分佈,如一致性雜湊,代表系統為

Amazon 的 Dynamo 系統, Openstack 的 Swift 系統;另外一種方法是順序分佈,即每張表格上的資料按照主鍵整體有序,代表系統為 Google 的 Bigtable 系統。Bigtable 將一張大表根據主鍵切分為有序的範圍,每個有序範圍是一個子表。

A 、雜湊分佈( Swift )

雜湊函式的雜湊特性很好,雜湊方式可以將資料比較均勻地分佈到叢集中去。而且,雜湊方式需要記錄的元資訊也非常簡單,每個節點只需要知道雜湊函式的計算方式以及模的伺服器的個數就可以計算出處理的資料應該屬於哪臺機器。

然而,找出一個雜湊特性很好的雜湊函式是很難的。這是因為,如果按照主鍵雜湊,那麼同一個使用者 id 下的資料可能被分散到多臺伺服器,這會使得一次操作同一個使用者 id 下的多條記錄變得困難;如果按照使用者 id 雜湊,容易出現 “ 資料傾斜 ” ( data skew )問題,即某些大使用者的資料量很大,無論叢集的規模有多大,這些使用者始終由一臺伺服器處理。

處理大使用者問題一般有兩種方式,一種方式是手動拆分,即線下標記系統中的大使用者(例如執行一次 MapReduce 作業),並根據這些大使用者的資料量將其拆分到多臺伺服器上。這就相當於在雜湊分佈的基礎上針對這些大使用者特殊處理;

另一種方式是自動拆分,即資料分佈演算法能夠動態調整,自動將大使用者的資料拆分到多臺伺服器上。其中包含兩種演算法。

一種是傳統的雜湊演算法,訪問資料時,首先計算雜湊值,再查詢後設資料伺服器,獲得該雜湊值對應的伺服器。在這種演算法下,伺服器的上線和下線將導致大量的資料遷移,不適合於生產。

另一致性雜湊( Distributed Hash Table,DHT )演算法。演算法思想如下:給系統中每個節點分配一個隨機 token ,這些 token 構成一個雜湊環。執行資料存放操作時,先計算 Key (主鍵)的雜湊值,然後存放到順時針方向第一個大於或者等於該雜湊值的 token 所在的節點。一致性雜湊的優點在於節點加入 / 刪除時只會影響到在雜湊環中相鄰的節點,而對其他節點沒影響。

分散式儲存架構知識,一篇講清楚!

如上圖所示,演算法本身的特性可以使得 磁碟劃分為比較多的較為均勻的虛擬分割槽,每個虛擬分割槽是雜湊環上的一個節點,整個環是從 0 到 32 位最大值的一個區間,並且首尾相連,當計算出資料(或者資料名稱)的雜湊值後,必然落到雜湊環的某個區間,然後以順時針,必然能夠找到一個節點。那麼這個節點就是儲存資料的位置。可見如果只有一個節點,最大到 32 還未找到節點,那麼資料就在第一個唯一節點上。

整個的資料定位就是基於上述的一致演算法,實現將請求重新定向到該裝置進行處理

(1) 在物件儲存上,透過賬戶名 / 容器名 / 物件名三個名稱組成一個位置的標識,透過該唯一標識可以計算出一個整型數;

(2) 儲存裝置方面, Swift 構建一個虛擬分割槽表,表的大小在建立叢集是確定(通常為幾十萬),這個表其實就是一個陣列;

(3) 整數值和這個陣列,透過一致性雜湊演算法就可以確定該整數在陣列的位置。

分散式儲存架構知識,一篇講清楚!

一致性演算法原理上可以保證資料的均衡性、單調性,避免資料的分散性,有效的保證資料的一致性,使得負載儘可能的被對映到一個特定的快取區。

因為 一致性雜湊演算法在服務節點太少時,容易因為節點分部不均勻而造成資料傾斜問題。所以在實際應用中,通常將虛擬節點數設定為比 32 更大的值,因此即使很少的服務節點也能做到相對均勻的資料分佈。

B 、順序分佈( Bigtable )

雜湊雜湊破壞了資料的有序性,只支援隨機讀取操作,不能夠支援順序掃描。某些系統可以在應用層做折衷,比如網際網路應用經常按照使用者來進行資料拆分,並透過雜湊方法進行資料分佈,同一個使用者的資料分佈到相同的儲存節點,允許對同一個使用者的資料執行順序掃描,由應用層解決跨多個使用者的操作問題。另外,這種方式可能出現某些使用者的資料量太大的問題,由於使用者的資料限定在一個儲存節點,無法發揮分散式儲存系統的多機並行處理能力。

順序分佈在分散式表格系統( Bigtable )中比較常見,一般的做法是將大表順序劃分為連續的範圍,每個範圍稱為一個子表,總控伺服器負責將這些子表按照一定的策略分配到儲存節點上。

分散式儲存架構知識,一篇講清楚!

如圖所示,使用者表( User 表)的主鍵範圍為 1 ~ 7000 ,在分散式儲存系統中劃分為多個子表,分別對應資料範圍 1 ~ 1000 , 1001 ~ 2000 , ……6001 ~ 7000 。其中 Meta 表是為了支援更大的叢集規模,它將原來的一層索引結分成兩層,使用 Meta 表來維護 User 子表所在的節點,從而減輕 Root 節點的負擔。

順序分佈與 B+ 樹資料結構比較類似,每個子表相當於葉子節點,隨著資料的插入和刪除,某些子表可能變得很大,某些變得很小,資料分佈不均勻。如果採用順序分佈,系統設計時需要考慮子表的分裂與合併,這將極大地增加系統複雜度。

C 、 CRUSH 分佈

CRUSH 演算法,全稱叫 Controlled, Scalable, Decentralized Placement of Replicated Data. 嚴格說起來 Crush 演算法,其實也是以 Hash 演算法為基礎的。只不過對映的方法和一致性雜湊不同。我們用 Ceph 分佈的過程來加以說明。

Ceph 分佈資料的過程:首先計算資料 x 的 Hash 值並將結果和 PG 數目取餘,以得到資料 x 對應的 PG 編號。然後,透過 CRUSH 演算法將 PG 對映到一組 OSD 中。最後把資料 x 存放到 PG 對應的 OSD 中。註明:PG 全稱是 Placement Group (放置組)。

這個過程中包含了兩次對映,第一次是資料 x 到 PG 的對映。如果把 PG 當作儲存節點,那麼傳統 Hash 演算法一樣。不同的是, PG 是抽象的儲存節點,它不會隨著物理節點的加入或則離開而增加或減少,因此資料到 PG 的對映是穩定的。

分散式儲存架構知識,一篇講清楚!

以 Dynamo 為例,在這個過程中, PG 起到了兩個作用:第一個作用是劃分資料分割槽。每個 PG 管理的資料區間相同,因而資料能夠均勻地分佈到 PG 上;第二個作用是充當 Dynamo 中 Token 的角色,即決定分割槽位置。實際上,這和 Dynamo 中固定分割槽數目,以及維持分割槽數目和虛擬節點數目相等的原則是同一回事。

以 Ceph 為例, CRUSH 演算法透過兩次對映計算資料儲存位置來確定如何儲存和檢索資料。CRUSH 使 Ceph 客戶機能夠直接與 OSDs 通訊,而不是透過集中的伺服器或代理。

透過演算法確定的資料儲存和檢索方法, Ceph 避免了單點故障、效能瓶頸和對其可伸縮性的物理限制。CRUSH 需要叢集的對映,並使用 CRUSH 對映在 OSDs 中偽隨機儲存和檢索資料,資料在叢集中均勻分佈。

3 、複製

為了保證分散式儲存系統的高可靠和高可用,資料在系統中一般儲存多個副本。當某個副本所在的儲存節點出現故障時,分散式儲存系統能夠自動將服務切換到其他的副本,從而實現自動容錯。分散式儲存系統透過複製協議將資料同步到多個儲存節點,並確保多個副本之間的資料一致性。

A 、強同步複製

客戶端將寫請求傳送給主副本,主副本將寫請求複製到其他備副本,常見的做法是同步操作日誌( Commit Log )。主副本首先將操作日誌同步到備副本,備副本回放操作日誌,完成後通知主副本。接著,主副本修改本機,等到所有的操作都完成後再通知客戶端寫成功。下圖中的複製協議要求主備同步成功才可以返回客戶端寫成功,這種協議稱為強同步協議。

分散式儲存架構知識,一篇講清楚!
假設所有副本的個數為 N ,且 N > 2 ,即備副本個數大於 1 。那麼,實現強同步協議時,主副本可以將操作日誌併發地發給所有備副本並等待回覆,只要至少 1 個備副本返回成功就可以回覆客戶端操作成功。強同步的好處在於如果主副本出現故障,至少有 1 個備副本擁有完整的資料,分散式儲存系統可以自動地將服務切換到最新的備副本而不用擔心資料丟失的情況。

B 、非同步複製

與強同步對應的複製方式是非同步複製。在非同步模式下,主副本不需要等待備副本的回應,只需要本地修改成功就可以告知客戶端寫操作成功。另外,主副本透過非同步機制,比如單獨的複製執行緒將客戶端修改操作推送到其他副本。非同步複製的好處在於系統可用性較好,但是一致性較差,如果主副本發生不可恢復故障,可能丟失最後一部分更新操作。

C 、 NWR 複製

分散式儲存系統中還可能使用基於寫多個儲存節點的複製協議( Replicated-write protocol )。比如 Dynamo 系統中的 NWR 複製協議,其中, N 為副本數量, W 為寫操作的副本數, R 為讀操作的副本數。

NWR 協議中多個副本不再區分主和備,客戶端根據一定的策略往其中的 W 個副本寫入資料,讀取其中的 R 個副本。只要 W+R > N ,可以保證讀到的副本中至少有一個包含了最新的更新。然而,這種協議的問題在於不同副本的操作順序可能不一致,從多個副本讀取時可能出現衝突。這種方式在實際系統中比較少見,不建議使用。

4 、分散式協議

分散式協議有很多,其中以兩階段提交和 Paxos 協議最具代表性。兩階段提交協議( 2PC )或三階段提交( 3PC )用於保證跨多個節點操作的原子性,也就是說,跨多個節點的操作要麼在所有節點上全部執行成功,要麼全部失敗。Paxos 協議用於確保多個節點對某個投票(例如哪個節點為主節點)達成一致。

A 、兩階段提交

二階段提交的演算法思路可以概括為 : 參與者將操作成敗通知協調者,再由協調者根據所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。

(1)請求階段 ( 表決 ) :

事務協調者協調者通知事務參與者準備提交或者取消事務,然後進入表決過程。在表決過程中,參與者將告知協調者自己的決策:同意(事務參與者本地執行成功)或者取消(事務參與者本地執行失敗)。

(2)提交階段 ( 執行 ):

在該階段,協調者將基於第一個階段的投票結果進行決策 : 提交或取消,當且僅當所有的參與者同意提交事務,協調者才通知所有的參與者提交事務,否則協調者將通知所有的參與者取消事務參與者在接收到協調者發來的訊息後將執行響應的操作。

分散式儲存架構知識,一篇講清楚!

(3)兩階段提交無法解決的問題

A )、如果一個參與者遲遲不投票,那整個階段都會處於等待狀態,但這可以透過超時機制解決

B )、當協調者出錯,同時參與者也出錯時,兩階段無法保證事務執行的完整性。

考慮協調者在發出 commit 訊息之後當機,而唯一接收到這條訊息的參與者同時也當機了。

那麼即使協調者透過選舉協議產生了新的協調者,這條事務的狀態也是不確定的,沒人知道事務是否被已經提交。

B 、三階段提交

三階段提交擁有 CanCommit 、 PreCommit 、 DoCommit 三個階段

( 1 )其中 CanCommit 階段近似等同於兩階段的請求階段;DoCommit 近似等同於兩階段的提交階段。而準備階段 PreCommit 是一個緩衝,保證了在最後提交階段之前各參與節點的狀態是一致的。

( 2 )三階段提交在兩階段提交的第一階段與第二階段之間插入了一個準備階段( PreCommit ),使得原先在兩階段提交中,參與者在投票之後,由於協調者發生崩潰或錯誤,而導致參與者處於無法知曉是否提交或者中止的“不確定狀態”所產生的可能相當長的延時的問題得以解決。

分散式儲存架構知識,一篇講清楚!

( 3 )三階段提交無法解決的問題

如果進入 PreCommit 後,協調者發出的是 commit 請求,假設只有一個參與者收到並進行了 commit 操作,而其他參與者對於網路中斷沒有收到,會根據 3PC 選擇 abort 操作,此時系統狀態發生不一致性。

C 、 Paxos 協議

要講 Paxos ,先要從拜占庭問題講起,其故事背景是這樣的:拜占庭位於現在土耳其的伊斯坦布林,是東羅馬帝國的首都。由於當時拜占庭羅馬帝國國土遼闊,為了防禦目的,因此每個軍隊都分隔很遠,將軍與將軍之間只能靠信差傳訊息。在戰爭的時候,拜占庭軍隊內所有將軍必需達成一致的共識,決定是否有贏的機會才去攻打敵人的陣營。但是,軍隊可能有叛徒和敵軍間諜,這些叛徒將軍們會擾亂或左右決策的過程。這時候,在已知有成員謀反的情況下,其餘忠誠的將軍在不受叛徒的影響下如何達成一致的協議,這就是拜占庭將軍問題。

我們否定假設,給出了非拜占庭模型定義:

( 1 )一致性模組的行為可以以任意速度執行,允許執行失敗,在失敗後也許會重啟並再次執行;

( 2 )一致性模組之間透過非同步方式傳送資訊通訊,通訊時間可以任意長,資訊可能會在傳輸過程中丟失,也允許重複傳送相同的資訊,多重資訊的順序可以任意。但是有一點:資訊不允許被篡改。

由此,我們得出了 Paxos 的基本二階段:Prepare 階段、 Accept 階段,這個兩個階段的邏輯非常複雜,是互信演算法的基礎,本文並不打算做過深的解讀。有興趣的讀者可以去參考《區塊鏈演算法》一書。

D 、 Raft 協議

Raft 是 Replicated And Fault Tolerant 的縮寫, Paxos 的簡化版本。

在一個分散式系統中,要提高系統的健壯性,可用性和資料的安全性,我們最正確的姿勢是什麼?當然是靠多備份了,服務多備份,資料多備份,去除單點,確保即使相關元件掛掉一些,系統還能健康服務。

去除單點,沒有固定不變的權威,固然好,但是帶來的問題就是,以誰的意見為準,在資訊可能丟失的環境下,這是一個相當困難的事(可見溝通是多麼的重要)!

在 1990 年提出來之時,幾乎沒有人能夠理解。經過作者多次簡化,再解釋,包括谷歌等團隊的實踐再創造,再解釋的過程,十幾年過去了,才漸漸的成為事實標準並被大家所瞭解和接受。但直到現在,無比抽象的 Paxos 演算法,還是沒有幾個人能理解。

大道至簡!這是永恆不變的真理, Raft 的目標問題,是構建一個容易理解和構建的分散式一致性協議,在容易的基礎上,確保理論正確的。

Raft 協議,如果照本宣讀,還是需要點時間的,本文采用通俗的辦法給大家做解釋

Raft 大致的原理,這是一個選主( leader selection )思想的演算法,叢集總每個節點都有三種可能的角色:

( 1 ) leader

對客戶端通訊的入口,對內資料同步的發起者,一個叢集通常只有一個 leader 節點

( 2 ) follower:

非 leader 的節點,被動的接受來自 leader 的資料請求

( 3 ) candidate:

一種臨時的角色,只存在於 leader 的選舉階段,某個節點想要變成 leader ,那麼就發起投票請求,同時自己變成 candidate 。如果選舉成功,則變為 candidate ,否則退回為 follower 。

演算法包含兩個過程:leader 選舉和日誌複製:

(1) 選舉過程:(假設有 5 個節點, S1~S5 )

a、 初始狀態下,大家都是平等的 follower ,那麼 follow 誰呢,總要選個老大吧。大家都蠢蠢欲動,每個 follower 內部都維護了一個隨機的 timer ;

b、 在 timer 時間到了的時候還沒有人主動聯絡它的話,那它就要變成 candidate ,同時發出投票請求( RequestVote )給其他人,假設 S1, S3 成為 candidate

c、 對於相同條件的 candidate , follower 們採取先來先投票的策略。如果超過半數的 follower 都認為他是合適做領導的,那麼恭喜,新的 leader 產生了,假如 S3 變成了新一屆的大哥 leader ;

d、 S1 很不幸,沒有人願意選這個悲劇的 candidate ,那它只有老老實實的變回小弟的狀態 follower;

e、 同樣的,如果在 timer 期間內沒有收到大哥的聯絡,這時很可能大哥已經跪了,如下圖,所有小弟又開始蠢蠢欲動,新的一輪 (term) 選舉開始了。

(2) 日誌複製:(假設有 5 個節點, S1~S5 )

a、 leader 扮演的是分散式事務中的協調者,每次有資料更新的時候產生二階段提交( two-phase commit )。在 leader 收到資料操作的請求,先不著急更新本地資料(資料是持久化在磁碟上的),而是生成對應的 log ,然後把生成 log 的請求廣播給所有的 follower ;

b、 每個 follower 在收到請求之後有兩種選擇:一種是聽從 leader 的命令,也寫入 log ,然後返回 success 回去;另一種情況,在某些條件不滿足的情況下, follower 認為不應該聽從 leader 的命令,返回 false ;

c、 此時如果超過半數的 follower 都成功寫了 log ,那麼 leader 開始_第二階段_的提交:正式寫入資料,然後同樣廣播給 follower , follower 也根據自身情況選擇寫入或者不寫入並返回結果給 leader ,最終所有節點的資料達成一致。

d、 這兩階段中如果任意一個都有超過半數的 follower 返回 false 或者根本沒有返回,那麼這個分散式事務是不成功的。此時雖然不會有回滾的過程,但是由於資料不會真正在多數節點上提交,所以會在之後的過程中被覆蓋掉

Raft 協議保證_leader_的強領導地位 ,client _讀寫都_透過_leader__,有很高的一致性,但有些同學會問,那分散式的價值在什麼地方呢?如何才能負載均衡呢?在實際中我們採用 Multi Raft 架構,結合應用,不同的應用選舉不同的 leader 節點,在負載均衡。

5、跨機房部署

在分散式系統中,跨機房問題一直都是老大難問題。機房之間的網路延時較大,且不穩定。跨機房問題主要包含兩個方面:資料同步以及服務切換。跨機房部署方案有三個:叢集整體切換、單個叢集跨機房、 Paxos 選主副本。下面分別介紹。

A 、叢集整體切換

叢集整體切換是最為常見的方案。如圖所示,假設某系統部署在兩個機房:機房 1 和機房 2 。兩個機房保持獨立,每個機房部署單獨的總控節點,且每個總控節點各有一個備份節點。當總控節點出現故障時,能夠自動將機房內的備份節點切換為總控節點繼續提供服務。另外,兩個機房部署了相同的副本數,例如資料分片 A 在機房 1 儲存的副本為 A11 和 A12 ,在機房 2 儲存的副本為 A21 和 A22 。在某個時刻,機房 1 為主機房,機房 2 為備機房。

分散式儲存架構知識,一篇講清楚!

機房之間的資料同步方式可能為強同步或者非同步。如果採用非同步模式,那麼,備機房的資料總是落後於主機房。當主機房整體出現故障時,有兩種選擇:要麼將服務切換到備機房,忍受資料丟失的風險;要麼停止服務,直到主機房恢復為止。因此,如果資料同步為非同步,那麼,主備機房切換往往是手工的,允許使用者根據業務的特點選擇“丟失資料”或者“停止服務”。

如果採用強同步模式,那麼,備機房的資料和主機房保持一致。當主機房出現故障時,除了手工切換,還可以採用自動切換的方式,即透過分散式鎖服務檢測主機房的服務,當主機房出現故障時,自動將備機房切換為主機房。

B 、單個叢集跨機房

將單個叢集部署到多個機房,允許不同資料分片的主副本位於不同的機房,如圖 3-11 所示。每個資料分片在機房 1 和機房 2 ,總共包含 4 個副本,其中 A1 、 B1 、 C1 是主副本, A1 和 B1 在機房 1 , C1 在機房 2 。整個叢集只有一個總控節點,它需要同機房 1 和機房 2 的所有工作節點保持通訊。當總控節點出現故障時,分散式鎖服務將檢測到,並將機房 2 的備份節點切換為總控節點。

分散式儲存架構知識,一篇講清楚!

如果採用這種部署方式,總控節點在執行資料分佈時,需要考慮機房資訊,也就是說,儘量將同一個資料分片的多個副本分佈到多個機房,從而防止單個機房出現故障而影響正常服務。

C 、 Paxos 選主副本

如果採用 Paxos 協議選主副本,那麼,每個資料分片的多個副本構成一個 Paxos 複製組。如圖所示, B1 、 B2 、 B3 、 B4 構成一個複製組,某一時刻 B1 為複製組的主副本,當 B1 出現故障時,其他副本將嘗試切換為主副本, Paxos 協議保證只有一個副本會成功。這樣,總控節點與工作節點之間不再需要保持租約,總控節點出現故障也不會對工作節點產生影響。它的優點在於能夠降低對總控節點的依賴,缺點在於工程複雜度太高,很難線上下模擬所有的異常情況。

分散式儲存架構知識,一篇講清楚!


四、分散式檔案系統

分散式檔案系統的主要功能有兩個:一個是儲存文件、影像、影片之類的 Blob 型別資料;另外一個是作為分散式表格系統的持久化層。

1、 Google 檔案系統( GFS )

GFS, Big Table, Map Reduce 稱為 Google 的三駕馬車,是許多基礎服務的基石。

GFS 於 2003 年提出,是一個分散式的檔案系統,與此前的很多分散式系統的前提假設存在很大的不同,適用於以下場景

( 1 )認為元件失效是一種常態,提供了容錯機制,自動負載均衡,使得分散式檔案系統可以在廉價機器上執行;

( 2 )面向大檔案儲存,系統主要的工作負載是大規模的流式讀取,寫操作主要是追加方式寫,很少有隨機寫;

( 3 )一次寫入,多次讀取,例如網際網路上的網頁儲存

分散式儲存架構知識,一篇講清楚!

GFS 檔案被劃分為固定大小的資料塊( chunk ),由主伺服器在建立時分配一個 64 位全域性唯一的 chunk 控制程式碼。CS 以普通的 Linux 檔案的形式將 chunk 儲存在磁碟中。為了保證可靠性, chunk 在不同的機器中複製多份,預設為三份。

主控伺服器中維護了系統的後設資料,包括檔案及 chunk 名稱空間、檔案到 chunk 之間的對映、 chunk 位置資訊。它也負責整個系統的全域性控制,如 chunk 租約管理、垃圾回收無用 chunk 、 chunk 複製等。主控伺服器會定期與 CS 透過心跳的方式交換資訊。

客戶端是 GFS 提供給應用程式的訪問介面,它是一組專用介面,不遵循 POSIX 規範,以庫檔案的形式提供。客戶端訪問 GFS 時,首先訪問主控伺服器節點,獲取與之進行互動的 CS 資訊,然後直接訪問這些 CS ,完成資料存取工作。

需要注意的是, GFS 中的客戶端不快取檔案資料,只快取主控伺服器中獲取的後設資料,這是由 GFS 的應用特點決定的。GFS 最主要的應用有兩個:MapReduce 與 Bigtable 。對於 MapReduce,GFS 客戶端使用方式為順序讀寫,沒有快取檔案資料的必要;而 Bigtable 作為分散式表格系統,內部實現了一套快取機制。另外,如何維護客戶端快取與實際資料之間的一致性是一個極其複雜的問題。

由此可見, Hadoop 的 HDFS 其實是 GFS 的簡化版,是 Cutting 博士“山寨” GFS 出來的產物。是盜火種的產物。

2、 Taobao 檔案系統( TFS )

網際網路應用經常需要儲存使用者上傳的文件、圖片、影片等,比如 Facebook 相簿、淘寶圖片、 Dropbox 文件等。文件、圖片、影片一般稱為 Blob 資料。Blob 檔案系統的特點是資料寫入後基本都是隻讀,很少出現更新操作,這就是 Taobao 檔案系統( TFS )的主要特點。

TFS 架構上借鑑了 GFS ,但與 GFS 又有很大的不同。

(1) TFS 內部不維護檔案目錄樹,扁平化的資料組織結構,可將檔名對映到檔案的實體地址,簡化了檔案的訪問流程;

(2) 針對海量小檔案的隨機讀寫訪問效能做了特殊最佳化,滿足了淘寶對小檔案儲存的需求,被廣泛地應用在淘寶各項應用中;

(3) 採用了 HA 架構和平滑擴容,保證了整個檔案系統的可用性和擴充套件性。

分散式儲存架構知識,一篇講清楚!

一個 TFS 叢集由兩個 NameServer 節點(一主一備)和多個 DataServer 節點組成, NameServer 透過心跳對 DataSrver 的狀態進行監測。NameServer 相當於 GFS 中的 Master,DataServer 相當於 GFS 中的 ChunkServer 。NameServer 區分為主 NameServer 和備 NameServer ,只有主 NameServer 提供服務,當主 NameServer 出現故障時,能夠被心跳守護程式檢測到,並將服務切換到備 NameServer 。每個 DataServer 上會執行多個 dsp 程式,一個 dsp 對應一個掛載點,這個掛載點一般對應一個獨立磁碟,從而管理多塊磁碟。

在 TFS 中,將大量的小檔案(實際資料檔案)合併成一個大檔案(這一點比 HDFS 有最佳化和改進),這個大檔案稱為塊( Block ),每個 Block 擁有在叢集內唯一的編號(塊 ID ),透過<塊 ID ,塊內偏移>可以唯一確定一個檔案。TFS 中 Block 的實際資料都儲存在 DataServer 中,大小一般為 64MB ,預設儲存三份,相當於 GFS 中的 chunk 。應用客戶端是 TFS 提供給應用程式的訪問介面,應用客戶端不快取檔案資料,只快取 NameServer 的後設資料。

3、 Fackbook Haystack 檔案系統

到 2014 年, Facebook 大概有超 4000 億張圖片,總大小為 30PB ,透過計算可以得出每張照片的平均大小為 30PB/260GB ,約為 100KB 。使用者每週新增照片數為 10 億(總大小為 60TB ),平均每秒新增的照片數為 109/7/40000 (按每天 40000s 計),約為每秒 3800 次寫操作,讀操作峰值可以達到每秒百萬次。

Facebook 相簿後端早期採用基於 NAS 的儲存,透過 NFS 掛載 NAS 中的照片檔案來提供服務。後來出於效能和成本考慮,自主研發了 Facebook Haystack 儲存相簿資料。

和 TFS 類似, Facebook Haystack 新架構主要解決圖片存取 IO 次數過多的檔案,主要的思路是多個邏輯檔案共享同一個物理檔案。Haystack 架構及讀請求處理流程圖如下

分散式儲存架構知識,一篇講清楚!

Haystack 架構主要有三個部分:Haystack Directory , Haystack Store 以及 Haystack Cache 。Haystack Store 是物理儲存節點,以物理卷軸 (physical volume) 的形式組織儲存空間,每個物理卷軸一般很大,比如 100GB ,這樣 10TB 的資料也只有 100 個物理卷軸。每個物理卷軸對應一個物理檔案,因此,每個儲存節點上的物理檔案元資訊都很小。多個物理儲存節點上的物理卷軸組成一個邏輯卷軸 (logical volume) ,用於備份。Haystack Directory 存放邏輯卷軸和物理卷軸的對應關係,假設每個卷軸的大小為 100GB ,對應關係的條數為 20PB / 100GB = 0.2MB ,佔用的記憶體可以忽略。Haystack cache 主要用於解決對 CDN 提供商過於依賴的問題,提供最近增加的圖片的快取服務。

Haystack 圖片讀取請求大致流程為:使用者訪問一個頁面時, Web Server 請求 Haystack Directory 構造一個 URL :http:// < CDN > / < Cache > / < Machine id > / < Logical volume,Photo > ,後續根據各個部分的資訊依次訪問 CDN , Cache 和後端的 Haystack Store 儲存節點。Haystack Directory 構造 URL 時可以省略 部分從而使得使用者直接請求 Haystack Cache 而不必經過 CDN 。Haystack cache 收到的請求包含兩個部分:使用者 Browser 的請求及 CDN 的請求, Haystack cache 只快取使用者 Browser 傳送的請求且要求請求的 Haystack Store 儲存節點是可寫的。一般來說, Haystack Store 的儲存節點寫一段時間以後達到容量上限變為只讀,因此,可寫節點的圖片為最近增加的圖片,是熱點資料。

Haystack 的寫請求 ( 圖片上傳 ) 處理流程為:Web Server 首先請求 Haystack Directory 獲取圖片的 id 和可寫的邏輯卷軸,接著將資料寫入對應的每一個物理卷軸 ( 備份數一般為 3) 。

Facebook Haystack 及 Taobao TFS 這樣的檔案系統一般稱為 Blob 檔案系統。它們都是解決大量的小圖片檔案的問題,因此架構很類似,不同點包括

(1) 邏輯卷軸大小的選擇,比如 Haystack 選擇 100GB 的邏輯卷軸大小, TFS 中 block 大小一般為 64MB ;

(2) Haystack 使用 RAID 6 ,且底層檔案系統使用效能更好的 XFS ,淘寶後期擯除了 RAID 機制,檔案系統使用 Ext3 ;

(3) Haystack 使用了 Akamai & Limelight 的 CDN 服務,而 Taobao 已經使用自建的 CDN ,當然, Facebook 也在考慮自建 CDN 。

4、 CDN 內容分發網路

CDN 的全稱是 Content Delivery Network ,即內容分發網路。其目的是透過在現有的 Internet 中增加一層新的網路架構,將網站的內容釋出到最接近使用者的網路 " 邊緣 " 。實現如下三個目的

( 1 )解決因分佈、頻寬、伺服器效能帶來的訪問延遲問題,適用於站點加速、點播、直播等場景。使使用者可就近取得所需內容,解決 Internet 網路擁擠的狀況,提高使用者訪問網站的響應速度和成功率。

( 2 )控制時延無疑是現代資訊科技的重要指標, CDN 的意圖就是儘可能的減少資源在轉發、傳輸、鏈路抖動等情況下順利保障資訊的連貫性。

( 3 ) CDN 就是扮演者護航者和加速者的角色,更快準狠的觸發資訊和觸達每一個使用者,帶來更為極致的使用體驗。

如下圖所示 DNS 在對域名解析時不再向使用者返回源伺服器的 IP ,而是返回了由智 CDN 負載均衡系統選定的某個邊緣節點的 IP 。使用者利用這個 IP 訪問邊緣節點,然後該節點透過其內部 DNS 解析得到源伺服器 IP 併發出請求來獲取使用者所需的頁面,如果請求成功,邊緣節點會將頁面快取下來,下次使用者訪問時可以直接讀取,而不需要每次都訪問源伺服器。

分散式儲存架構知識,一篇講清楚!

Taobao 的 CDN 架構是自研的,用於支援使用者購物,尤其是“雙 11” 光棍節時的海量圖片請求,圖片儲存在後臺的 TFS 叢集中, CDN 系統將這些圖片快取到離使用者最近的邊緣節點。CDN 採用兩級 Cache :L1-Cache 以及 L2-Cache 。使用者訪問淘寶網的圖片時,透過全域性排程系統( Global Load Balancing )排程到某個 L1-Cache 節點。如果 L1-Cache 命中,那麼直接將圖片資料返回使用者;否則,請求 L2-Cache 節點,並將返回的圖片資料快取到 L1-Cache 節點。如果 L2-Cache 命中,直接將圖片資料返回給 L1-Cache 節點;否則,請求源伺服器的圖片伺服器叢集。每臺圖片伺服器是一個執行著 Nginx 的 Web 伺服器,它還會在本地快取圖片,只有當本地快取也不命中時才會請求後端的 TFS 叢集,圖片伺服器叢集和 TFS 叢集部署在同一個資料中心內。

分散式儲存架構知識,一篇講清楚!

對於每個 CDN 節點,其架構如圖 4-11 所示。從圖中可以看出,每個 CDN 節點內部透過 LVS+Haproxy 的方式進行負載均衡。其中, LVS 是四層負載均衡軟體,效能好;Haproxy 是七層負載均衡軟體,能夠支援更加靈活的負載均衡策略。透過有機結合兩者,可以將不同的圖片請求排程到不同的 Squid 伺服器。

分散式儲存架構知識,一篇講清楚!

上圖是 CDN 的單節點架構,它有以下三個特點

(1) Squid 伺服器構成淘寶單節點中的 CDN 中的分散式快取,這個實現比分散式快取簡單很多,因為不需要考慮資料持久化。

(2) 分級快取,由於快取資料有較高的區域性性,在 Squid 伺服器上使用 SSD+SAS+SATA 混合儲存,圖片隨著熱點變化而遷移,最熱門的儲存到 SSD ,中等熱度的儲存到 SAS ,輕熱度的儲存到 SATA 。透過這樣的方式,能夠很好地結合 SSD 的效能和 SAS 、 SATA 磁碟的成本優勢;

(3) 低功耗伺服器定製, CDN 快取服務是 IO 密集型而不是 CPU 密集型的服務,因此,選用 Intel Atom CPU 定製低功耗伺服器,在保證服務效能的前提下大大降低了整體功耗。


五、分散式鍵值系統

分散式鍵值系統是用於儲存關係簡單的半結構化資料,半結構化資料均封裝成由 鍵值對組成的物件,其中 key 為唯一標示符;value 為屬性值,可以為任何型別,如文字、圖片,也可以為空;timestamp 為時間戳,提供物件的多版本支援。分散式鍵值系統以鍵值對儲存,它的結構不固定,每一元組可以有不一樣的欄位,可根據需要增加鍵值對,從而不侷限於固定的結構,適用面更大,可擴充套件性更好。

分散式鍵值系統支援針對單個 鍵值對的增、刪、查、改操作,可以執行在 PC 伺服器叢集上,並實現叢集按需擴充套件,從而處理大規模資料,並透過資料備份保障容錯性,避免了分割資料帶來的複雜性和成本。

總體來說,分散式鍵值系統從儲存資料結構的角度看,分散式鍵值系統與傳統的雜湊表比較類似,不同的是,分散式鍵值系統支援將資料分佈到叢集中的多個儲存節點。分散式鍵值系統可以配置資料的備份數目,可以將一份資料的所有副本儲存到不同的節點上,當有節點發生異常無法正常提供服務時,其餘的節點會繼續提供服務。

1、 Amazon Dynamo

Dynamo 以很簡單的鍵值方式儲存資料,不支援複雜的查詢。Dynamo 中儲存的是資料值的原始形式,不解析資料的具體內容。Dynamo 主要用於 Amazon 的購物車及 S3 雲端儲存服務。在實現過程中解決了如下問題:

問題

採用的技術

資料分佈

改進的雜湊演算法

複製協議

複製寫協議(NRW引數可調)

資料衝突的解決

向量時鐘

臨時故障處理

資料回傳機制

永久故障處理

Merkle雜湊樹

成員資格及錯誤檢測

基於Gossip的成員資格和錯誤檢測協議

Dynamo 採用一致性雜湊將資料分佈到多個儲存節點中,概括來說:給系統中的每個節點分配一個隨機 token ,這些 token 構成一個雜湊環。執行資料存放操作時,先計算主鍵的雜湊值,然後存放到順時針方向的第一個大於或者等於該雜湊值的 token 所在的節點。一致性雜湊的有點在於節點加入 / 刪除只會影響到在雜湊環相鄰的節點,而對其他節點沒影響。

A 、 Dynamo 架構

考慮到節點的異構性,不同節點的處理能力差別很大, Dynamo 使用了改進的一致性雜湊演算法:每個物理節點根據其效能的差異分配多個 token ,每個 token 對應一個虛擬節點,每個虛擬節點的處理能力基本相當,並隨機分佈在雜湊空間中。儲存時,資料按照雜湊值落到某個虛擬節點負責的區域,然後被儲存到該虛擬節點所對應的物理節點。

如下圖,某 Dynamo 叢集中原有 3 個節點,每個節點分配 3 個 token 。存放資料時,首先計算主鍵的雜湊值,並根據雜湊值將資料存放到對應 token 所在的節點。假設增加節點 4 ,節點 token 分配情況發生變化,這就實現了自動負載均衡。

分散式儲存架構知識,一篇講清楚!

為了找到資料所屬的節點,要求每個節點維護一定的叢集資訊用於定位。Dynamo 系統中每個節點維護整個叢集的資訊,客戶端也快取整個叢集的資訊,因此,絕大部分請求能夠一次定位到目標節點。

B 、 Gossip 協議

由於機器或者人為的因素,系統中的節點成員加入或者刪除經常發生,為了保證每個節點快取的都是 Dynamo 叢集中最新的成員資訊,所有節點每隔固定時間(比如 1s )透過 Gossip 協議的方式從其他節點中任意選擇一個與之通訊的節點。如果連線成功,雙方交換各自儲存的叢集資訊。

Gossip 協議用於 P2P 系統中自治的節點協調對整個叢集的認識,比如叢集的節點狀態、負載情況。我們先看看兩個節點 A 和 B 是如何交換對世界的認識的。

( 1 ) A 告訴 B 其管理的所有節點的版本(包括 Down 狀態和 Up 狀態的節點);

( 2 ) B 告訴 A 哪些版本它比較舊了,哪些版本它有最新的,然後把最新的那些節點發給 A (處於 Down 狀態的節點由於版本沒有發生更新所以不會被關注);

( 3 ) A 將 B 中比較舊的節點傳送給 B ,同時將 B 傳送來的最新節點資訊做本地更新;

( 4 ) B 收到 A 發來的最新節點資訊後,對本地快取的比較舊的節點做更新。

由於種子節點的存在,新節點加入可以做得比較簡單。新節點加入時首先與種子節點交換叢集資訊,從而對叢集有了認識。DHT ( Distributed Hash Table ,也稱為一致性雜湊表)環中原有的其他節點也會定期和種子節點交換叢集資訊,從而發現新節點的加入。

叢集不斷變化,可能隨時有機器下線,因此,每個節點還需要定期透過 Gossip 協議同其他節點交換叢集資訊。如果發現某個節點很長時間狀態都沒有更新,比如距離上次更新的時間間隔超過一定的閾值,則認為該節點已經下線了。

2、 Taobao Tiar

Tair 是一個分散式的 key/value 系統。

Tair 有四種引擎:mdb, rdb, kdb 和 ldb 。分別基於四種開源的 key/value 資料庫:memcached, Redis, Kyoto Cabinet 和 leveldb 。Tair 可以讓你更方便地使用這些 KV 資料庫。比如 Redis 沒有提供 sharding 操作,如果有多個 Redis Server ,你需要自己寫程式碼實現 sharding , Tair 幫你封裝了這些。

Tair 有以下優點:

( 1 )統一的 API 。無論底層使用何種引擎,上層的 API 是一樣的。

( 2 ) Tair 將叢集操作封裝起來,解放了開發者。淘寶內部在使用 Tair 時,一般都是雙機房雙叢集容錯,利用 invalid server 保證兩個叢集間的一致性,這些對於開發者都是透明的。

A 、 Tair 使用場景

( 1 )非持久化 (mdb,rdb)

• 資料可以以 key/value 的形式儲存

• 資料可以接受丟失

• 訪問速度要求很高

• 單個資料大小不是很大,一般在 KB 級別

• 資料量很大,並且有較大的增長可能性

• 資料更新不頻繁

( 2 )持久化 (kdb,ldb)

• 資料可以以 key/value 的形式儲存

• 資料需要持久化

• 單個資料大小不是很大,一般在 KB 級別

• 資料量很大,並且有較大的增長可能性

• 資料的讀寫比例較高

B 、 Tair 的架構

Tair 作為一個分散式系統,是由一箇中心控制節點和若干個服務節點組成,

a 、 config server 功能:

( 1 )透過維護和 data server 心跳來獲知叢集中存活節點的資訊;

( 2 )根據存活節點的資訊來構建資料在叢集中的分佈表;

( 3 )根據資料分佈表的查詢服務;

( 4 )排程 data server 之間的資料遷移、複製;

b 、 data server 功能

( 1 )提供儲存引擎;

( 2 )接受 client 的 put/get/remove 等操作;

( 3 )執行資料遷移,複製等;

( 4 )外掛:在接受請求的時候處理一些自定義功能;

( 5 )訪問統計;

c 、 client 功能

( 1 )在應用端提供訪問 tair 叢集的介面;

( 2 )更新並快取資料分佈表和 invalid server 地址等;

( 3 ) local cache ,避免過熱資料訪問影響 tair 叢集服務;

( 4 )流控;

在下圖中,。客戶端首先請求 Config Server 獲取資料所在的 Data Server ,接著往 Data Server 傳送讀寫請求。Tair 允許將資料存放到多臺 Data Server ,以實現異常容錯。

分散式儲存架構知識,一篇講清楚!

C 、資料分佈均衡性

Tair 的分佈採用的是一致性雜湊演算法,對於所有的 key ,分到 Q 個桶中,桶是負載均衡和資料遷移的基本單位, config server 根據一定的策略把每個桶指派到不同的 data server 上,因為資料按照 key 做 hash 演算法,保證了桶分佈的均衡性,從而保證了資料分佈的均衡性。

D 、容錯

當某臺 Data Server 故障不可用時, Config Server 能夠檢測到。每個雜湊桶在 Tair 中儲存多個副本,如果是備副本,那麼 Config Server 會重新為其指定一臺 Data Server ,如果是持久化儲存,還將複製資料到新的 Data Server 上。如果是主副本,那麼 ConfigServer 首先將某個正常的備副本提升為主副本,對外提供服務。接著,再選擇另外一臺 Data Server 增加一個備副本,確保資料的備份數。

E 、資料遷移

增加或減少 data server 的時候, config server 會發現這個情況, config server 負責重新計算一張新的桶在 data server 上的分佈表,將原來由減少的機器服務的桶的訪問重新指派到其他的 data server 中,這個時候就會發生資料的遷移。比如原來由 data server A 負責的桶,在新表中需要由 B 負責,而 B 上並沒有該桶的資料,那麼就將資料遷移到 B 上來,同時 config server 會發現哪些桶的備份數目減少了,然後根據負載均衡情況在負載較低的 data server 上增加這些桶的備份。當系統增加 data server 的時候, config server 根據負載,協調 data server 將他們控制的部分桶遷移到新的 data server 上,遷移完成後調整路由;

資料遷移時 data server 對外提供服務的策略,假設 data server A 要把桶 1,2,3 遷移到 data server B ,因為遷移完成前,客戶端的路由表沒有變化,客戶端對 1,2,3 的訪問請求都會路由到 A ,現在假設 1 還沒遷移, 2 正在遷移, 3 已經遷移完成,那麼如果訪問 1 ,則還是訪問 data server A ,如果訪問 3 ,則 A 會把請求轉發給 B ,並且將 B 的返回結果返回給客戶,如果訪問 2 ,則在 A 上處理,同時如果是對 2 的修改操作,會記錄修改 log ,當桶 2 完成遷移的時候,還有把 log 傳送給 B ,在 B 上應用這些 log ,最終 AB 資料一致才是真正完成遷移。如果 A 是由於當機而引發的遷移,客戶端會收到一張中間臨時狀態的分配表,把當機的 data server 負責的桶臨時指派給有其備份的 data server 來處理,此時服務是可用的,負載可能不均衡,當遷移完成後,又能達到一個新的負載均衡狀態。

3、 ETCD

ETCD etcd 是一個高可用的鍵值儲存系統,主要用於共享配置和服務發現。

(1) 由 CoreOS 開發並維護的,靈感來自於 ZooKeeper 和 Doozer ;

(2) 它使用 Go 語言編寫,並透過 Raft 一致性演算法處理日誌複製以保證強一致。

(3) Google 的容器叢集管理系統 Kubernetes 、開源 PaaS 平臺 Cloud Foundry 和 CoreOS 的 Fleet 都廣泛使用了 etcd ;

(4) 當叢集網路出現動盪,或者當前 master 節點出現異常時, etcd 可以進行 master 節點的選舉工作,同時恢復叢集中損失的資料

A 、 ETCD 的特點

( 1 )簡單:基於 HTTP+JSON 的 API 讓你用 curl 就可以輕鬆使用。

( 2 )安全:可選 SSL 客戶認證機制。

( 3 )快速:每個例項每秒支援一千次寫操作。

( 4 )可信:使用 Raft 演算法充分實現了分散式。

B 、提供的能力

Etcd 主要提供以下能力

(1) 提供儲存以及獲取資料的介面,它透過協議保證 Etcd 叢集中的多個節點資料的強一致性。用於儲存元資訊以及共享配置。

(2) 提供監聽機制,客戶端可以監聽某個 key 或者某些 key 的變更。用於監聽和推送變更。

(3) 提供 key 的過期以及續約機制,客戶端透過定時重新整理來實現續約( v2 和 v3 的實現機制也不一樣)。用於叢集監控以及服務註冊發現。

(4) 提供原子的 CAS ( Compare-and-Swap )和 CAD ( Compare-and-Delete )支援( v2 透過介面引數實現, v3 透過批次事務實現)。用於分散式鎖以及 leader 選舉。

C 、 ETCD 架構

( 1 ) Etcd v2 儲存, Watch 以及過期機制

Etcd v2 是個純記憶體的實現,並未實時將資料寫入到磁碟,持久化機制很簡單,就是將 store 整合序列化成 json 寫入檔案。資料在記憶體中是一個簡單的樹結構。

store 中有一個全域性的 currentIndex ,每次變更, index 會加 1. 然後每個 event 都會關聯到 currentIndex.

當客戶端呼叫 watch 介面(引數中增加 wait 引數)時,如果請求引數中有 waitIndex ,並且 waitIndex 小於 currentIndex ,則從 EventHistroy 表中查詢 index 小於等於 waitIndex ,並且和 watch key 匹配的 event ,如果有資料,則直接返回。如果歷史表中沒有或者請求沒有帶 waitIndex ,則放入 WatchHub 中,每個 key 會關聯一個 watcher 列表。當有變更操作時,變更生成的 event 會放入 EventHistroy 表中,同時通知和該 key 相關的 watcher 。

分散式儲存架構知識,一篇講清楚!

( 2 ) Etcd v3 儲存, Watch 以及過期機制

Etcd v3 將 watch 和 store 拆開實現,我們先分析下 store 的實現。Etcd v3 store 分為兩部分,一部分是記憶體中的索引, kvindex ,是基於 google 開源的一個 golang 的 btree 實現的,另外一部分是後端儲存。

按照它的設計, backend 可以對接多種儲存,當前使用的 boltdb 。boltdb 是一個單機的支援事務的 kv 儲存, Etcd 的事務是基於 boltdb 的事務實現的。Etcd 在 boltdb 中儲存的 key 是 reversion , value 是 Etcd 自己的 key-value 組合,也就是說 Etcd 會在 boltdb 中把每個版本都儲存下,從而實現了多版本機制。

分散式儲存架構知識,一篇講清楚!

4 、產品選型比較( Etcd , Zookeeper , Consul 比較)

這三個產品是經常被人拿來做選型比較的。

(1) Etcd 和 Zookeeper 提供的能力非常相似,都是通用的一致性元資訊儲存,都提供 watch 機制用於變更通知和分發,也都被分散式系統用來作為共享資訊儲存,在軟體生態中所處的位置也幾乎是一樣的,可以互相替代的。二者除了實現細節,語言,一致性協議上的區別,最大的區別在周邊生態圈。Zookeeper 是 apache 下的,用 java 寫的,提供 rpc 介面,最早從 hadoop 專案中孵化出來,在分散式系統中得到廣泛使用( hadoop, solr, kafka, mesos 等)。Etcd 是 coreos 公司旗下的開源產品,比較新,以其簡單好用的 rest 介面以及活躍的社群俘獲了一批使用者,在新的一些叢集中得到使用(比如 kubernetes )。雖然 v3 為了效能也改成二進位制 rpc 介面了,但其易用性上比 Zookeeper 還是好一些。

(2) Consul 的目標則更為具體一些, Etcd 和 Zookeeper 提供的是分散式一致性儲存能力,具體的業務場景需要使用者自己實現,比如服務發現,比如配置變更。而 Consul 則以服務發現和配置變更為主要目標,同時附帶了 kv 儲存。在軟體生態中,越抽象的元件適用範圍越廣,但同時對具體業務場景需求的滿足上肯定有不足之處。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2924604/,如需轉載,請註明出處,否則將追究法律責任。

相關文章