分散式塊儲存系統Ursa的設計與實現

美團點評技術團隊發表於2016-03-21

引言

雲硬碟對IaaS雲端計算平臺有至關重要的作用,幾乎已成為必備元件,如亞馬遜的EBS(Elastic Block Store)、阿里雲的盤古、OpenStack中的Cinder等。雲硬碟可為雲端計算平臺帶來許多優良特性,如更高的資料可靠性和可用性、靈活的資料快照功能、更好的虛擬機器動態遷移支援、更短的主機故障恢復時間等等。隨著萬兆乙太網逐漸普及,雲硬碟的各項優勢得到加強和凸顯,其必要性變得十分強烈。

雲硬碟的底層通常是分散式塊儲存系統,目前開源領域有一些此類專案,如Ceph RBD、Sheepdog。另外MooseFS和GlusterFS雖然叫做檔案系統,但由於其特性與塊儲存系統接近,也能用於支援雲硬碟。我們在測評中發現,這些開源專案均存在一些問題,使得它們都難以直接應用在大規模的生產系統當中。例如Ceph RBD的效率較低(CPU使用過高);Sheepdog在壓力測試中出現了資料丟失的現象;MooseFS的POSIX語義支援、基於FUSE的架構、不完全開源的2.0版本等問題給它自身帶來了許多的侷限性;GlusterFS與Ceph同屬紅帽收購的開源儲存系統,主要用於scale-out檔案儲存場景,在雲端計算領域使用不多。此外,這些儲存系統都難以充發揮用萬兆網路卡和SSD的效能潛力,難以在未來承擔重任。

由於以上原因,美團雲研發了全新的分散式塊儲存系統Ursa,通過簡單穩固的系統架構、高效的程式碼實現以及對各種非典型場景的仔細考慮,實現了高可靠、高可用、高效能、低開銷、可擴充套件、易運維、易維護等等目標。Ursa的名字源於DotA中的熊戰士,他具有極高的攻擊速度、攻擊力和生命值,分別隱喻儲存系統中的IOPS、吞吐率和穩定性。

分散式塊儲存相關專案與技術

2.1 Ceph

(主要參考:https://www.ustack.com/blog/ceph_infra/

Ceph專案起源於其創始人Sage Weil在加州大學Santa Cruz分校攻讀博士期間的研究課題。專案的起始時間為2004年。在2006年的OSDI學術會議上,Sage發表了關於Ceph的論文,並提供了專案的下載連結,由此開始廣為人知。2010年Ceph客戶端部分程式碼正式進入Linux kernel 2.6.34。

Ceph同時提供物件、塊和檔案這三個層次的分散式儲存服務,其中只有塊層儲存與我們相關。由於塊儲存在IaaS雲端計算系統中佔有重要地位,Ceph在近些年的關注度得到顯著提高。許多雲端計算系統例項基於Ceph提供塊儲存服務,如UnitedStack、Mirantis OpenStack等。

Ceph效能測試

  • 測試版本:0.81
  • 作業系統:CentOS 6.x
  • 測試工具:fio
  • 伺服器配置:
    • CPU: Intel Xeon E5-2650v2 @ 2.6GHz
    • RAM: 96GB
    • NIC: 10 GbE
    • HDD: 6 NL SAS, 7200 RPM
    • RAID Controller: Dell H710p (LSI 2208 with 1GB NVRAM)
  • 伺服器數量:4,其中一個為兼職客戶端

注意:由於客戶端位於一個儲存伺服器上,所以有1/4的吞吐率不經過網路卡。

測試結果如下:

  • 讀IOPS:16 407(此時客戶端CPU佔用率超過500%,5臺伺服器CPU總使用率接近500%)
  • 寫IOPS:941
  • 順序讀吞吐率:218 859 KB/s
  • 順序寫吞吐率:67 242 KB/s
  • 順序讀延遲:1.6ms (664 IOPS)
  • 順序寫延遲:4.4ms (225 IOPS)
  • 網路ping值:0.1324ms
  • 本地硬碟順序讀寫延遲:0.03332ms (29 126 IOPS)

從測試來看,Ceph的讀吞吐率正常,然而寫吞吐率不足讀的1/3,效能偏低;讀寫延遲比顯著大於網路延遲與磁碟I/O延遲之和;CPU佔用率過高。

2.2 Sheepdog

(主要參考:http://peterylh.blog.163.com/blog/static/12033201221594937257/

Sheepdog是由日本NTT實驗室的Morita Kazutaka專為虛擬化平臺創立的分散式塊儲存開源專案, 於2009年開源[1]。從2011年9月開始, 一些淘寶的工程師加入了Sheepdog專案,以及相關開源專案比如Corosync、Accord的開發。Sheepdog主要由兩部分組成:叢集管理和儲存服務,其中叢集管理目前使用Corosync或者Zookper來完成,儲存服務是全新實現的。

Sheepdog採用無中心節點的全對稱架構,基於一致性雜湊實現從ObjectID到儲存節點的定位:每個節點劃分成多個虛擬節點,虛擬節點和ObjectID一樣,採用64位整數唯一標識,每個虛擬節點負責一段包含節點ID在內的ObjectID區間。DataObject副本存在ObjectID對應的虛擬節點,及在後續的幾個節點上。Sheepdog無單點故障問題,儲存容量和效能均可線性擴充套件,新增節點通過簡單配置即可加入叢集,並且Sheepdog自動實現負載均衡,節點故障時可自動發現並進行副本修復,還直接支援QEMU/KVM。

Sheepdog的服務程式既承擔資料服務的職責,同時也是客戶端(QEMU)訪問資料的gateway。QEMU的Sheepdog driver將對volume的請求轉換成為對object的請求,然後通過UNIX domain socket或者TCP socket連線一個Sheepdog服務程式,並將訪問請求發給該程式來完成後續步驟。Sheepdog的服務程式還可以開啟資料快取功能,以減少網路I/O。Sheepdog的I/O路徑是“clientgatewayobject manager(s)”,讀操作可以在任意副本完成,更新操作並行的發往所有副本, 當所有副本都更新成功之後,gateway才告訴客戶端更新操作成功。

Sheepdog的資料可靠性問題

我們對Sheepdog開展了可靠性、可用性測試。在測試中有共3臺伺服器,每臺配有6個機械硬碟,配置好Sheepdog之後,每臺伺服器啟動10個VM,每個VM內無限迴圈執行fio分別執行小塊隨機讀、寫和大塊順序讀、寫的測試。

在執行壓力測試一週後,對叢集中的全部資料進行一致性檢測(collie cluster check),發現有些資料塊副本與另外2個不一致(“fixed replica …”),有些資料塊的3個各不相同(“no majority of …”):

2.3 MooseFS

(主要參考:http://peterylh.blog.163.com/blog/static/12033201251791139592/

MooseFS是容錯的分散式檔案系統,通過FUSE支援標準POSIX檔案系統介面。 MooseFS的架構類似於GFS,由四個部分組成:

  • 管理伺服器Master:類似於GFS的Master,主要有兩個功能:(1)儲存檔案和目錄後設資料,檔案後設資料包括檔案大小、屬性、對應的Chunk等;(2)管理叢集成員關係和Chunk後設資料資訊,包括Chunk儲存、版本、Lease等。
  • 後設資料備份伺服器Metalogger Server:根據後設資料檔案和log實時備份Master後設資料。
  • 儲存伺服器Chunk Server:負責儲存Chunk,提供Chunk讀寫能力。Chunk檔案預設為64MB大小。
  • 客戶端Client:以FUSE方式掛到本地檔案系統,實現標準檔案系統介面。

MooseFS本地不會快取Chunk資訊, 每次讀寫操作都會訪問Master, Master的壓力較大。此外MooseFS寫操作流程較長且開銷較高。MooseFS支援快照,但是以整個Chunk為單位進行CoW(Copy-on-Write),可能造成響應時間惡化,補救辦法是以犧牲系統規模為代價,降低Chunk大小。

MooseFS基於FUSE提供POSIX語義支援,已有應用可以不經修改直接遷移到MooseFS之上,這給應用帶來極大的便利。然而FUSE也帶來了一些負面作用,比如POSIX語義對於塊儲存來說並不需要,FUSE會帶來額外開銷等等。

2.4 GFS/HDFS

(主要參考:http://www.nosqlnotes.net/archives/119

HDFS基本可以認為是GFS的一個簡化開源實現,二者因此有很多相似之處。首先,GFS和HDFS都採用單一主控機+多臺工作機的模式,由一臺主控機(Master)儲存系統全部後設資料,並實現資料的分佈、複製、備份決策,主控機還實現了後設資料的checkpoint和操作日誌記錄及回放功能。工作機儲存資料,並根據主控機的指令進行資料儲存、資料遷移和資料計算等。其次,GFS和HDFS都通過資料分塊和複製(多副本,一般是3)來提供更高的可靠性和更高的效能。當其中一個副本不可用時,系統都提供副本自動複製功能。同時,針對資料讀多於寫的特點,讀服務被分配到多個副本所在機器,提供了系統的整體效能。最後,GFS和HDFS都提供了一個樹結構的檔案系統,實現了類似與Linux下的檔案複製、改名、移動、建立、刪除操作以及簡單的許可權管理等。

然而,GFS和HDFS在關鍵點的設計上差異很大,HDFS為了規避GFS的複雜度進行了很多簡化。例如HDFS不支援併發追加和叢集快照,早期HDFS的NameNode(即Master)沒原生HA功能。總之,HDFS基本可以認為是GFS的簡化版,由於時間及應用場景等各方面的原因對GFS的功能做了一定的簡化,大大降低了複雜度。

2.5 HLFS

(主要參考:http://peterylh.blog.163.com/blog/static/120332012226104116710/

HLFS(HDFS Log-structured File System)是一個開源分散式塊儲存系統,其最大特色是結合了LFS和HDFS。HDFS提供了可靠、隨時可擴充套件的檔案服務,而HLFS通過Log-structured技術彌補了HDFS不能隨機更新的缺憾。在HLFS中,虛擬磁碟對應一個檔案, 檔案長度能夠超過TB級別,客戶端支援Linux和Xen,其中Linux基於NBD實現,Xen基於blktap2實現,客戶端通過類POSIX介面libHLFS與服務端通訊。HLFS主要特性包括多副本、動態擴容、故障透明處理和快照。

HLFS效能較低。首先,非原地更新必然導致資料塊在物理上非連續存放,因此讀I/O比較隨機,順序讀效能下降。其次,雖然從單個檔案角度看來,寫I/O是順序的,但是在HDFS的Chunk Server服務了多個HLFS檔案,因此從它的角度來看,I/O仍然是隨機的。第三,寫延遲問題,HDFS面向大檔案設計,小檔案寫延時不夠優化。第四,垃圾回收的影響,垃圾回收需要讀取和寫入大量資料,對正常寫操作造成較大影響。此外,按照目前實現,相同段上的垃圾回收和讀寫請求不能併發,垃圾回收演算法對正常操作的干擾較大。

2.6 iSCSI、FCoE、AoE、NBD

iSCSI、FCoE、AoE、NBD等都是用來支援通過網路訪問塊裝置的協議,它們都採用C/S架構,無法直接支援分散式塊儲存系統。

Ursa的設計與實現

分散式塊儲存系統給虛擬機器提供的是虛擬硬碟服務,因而有如下設計目標:

  • 大檔案儲存:虛擬硬碟實際通常GB級別以上,小於1GB是罕見情況
  • 需要支援隨機讀寫訪問,不需支援追加寫,需要支援resize
  • 通常情況下,檔案由一個程式獨佔讀寫訪問;資料塊可被共享只讀訪問
  • 高可靠,高可用:任意兩個伺服器同時出現故障不影響資料的可靠性和可用性
  • 能發揮出新型硬體的效能優勢,如萬兆網路、SSD
  • 由於應用需求未知,同時需要優化吞吐率和IOPS
  • 高效率:降低資源消耗,就降低了成本

除了上述源於虛擬硬碟的直接需求意外,分散式塊儲存還需要支援下列功能:

  • 快照:可給一個檔案在不同時刻建立多個獨立的快照
  • 克隆:可將一個檔案或快照在邏輯上覆製成獨立的多份
  • 精簡配置(thin-provisioning):只有儲存資料的部分才真正佔用空間

3.1 系統架構

分散式儲存系統總體架構可以分為有master(後設資料伺服器)和無master兩大類。有master架構在技術上較為簡單清晰,但存在單點失效以及潛在的效能瓶頸問題;無master架構可以消除單點失效和效能瓶頸問題,然而在技術上卻較為複雜,並且在資料佈局方面具有較多侷限性。塊儲存系統對master的壓力不大,同時master的單點故障問題可採用一些現有成熟技術解決,因而美團EBS的總體架構使用有master的型別。這一架構與GFS、HDFS、MooseFS等系統的架構屬於同一型別。

如圖1所示,美團EBS系統包括M、S和C三個部分,分別代表Master、Chunk Server和Client。Master中記錄的後設資料包括3種:(1)關於volume的資訊,如型別、大小、建立時間、包含哪些資料chunk等等;(2)關於chunk的資訊,如大小、建立時間、所在位置等;(3)關於Chunk Server的資訊,如IP地址、埠、資料儲存量、I/O負載、空間剩餘量等。這3種資訊當中,關於volume的資訊是持久化儲存的,其餘兩種均為暫存資訊,通過Chunk Server上報。

美團

在後設資料中,關於volume的資訊非常重要,必須持久化儲存;關於chunk的資訊和Chunk Server的資訊是時變的,並且是由Chunk Server上報的,因而沒必要持久化儲存。根據這樣的分析,我們將關於volume的資訊儲存在MySQL當中,其他後設資料儲存在Redis當中,餘下的叢集管理功能由Manager完成。Master == Manager + MySQL + Redis,其中MySQL使用雙機主從配置,Redis使用官方提供的標準cluster功能。

3.2 CAP取捨

C、A、P分別代表Consistency、Availability和Partition-tolerance。分散式系統很難同時在這三個方面做到很高的保障,通常要在仔細分析應用需求的基礎之上對CAP做出取捨。

塊儲存系統主要用於提供雲硬碟服務,每塊雲硬碟通常只會掛載到1臺VM之上,不存在多機器併發讀寫的情況,因而其典型應用場景對一致性的需求較低。針對這一特性,我們可以在設計上舍C而取AP。

對於多機並行訪問雲硬碟的使用模式,若資料是隻讀的則無需額外處理;若資料有寫有讀,甚至是多寫多讀,則需要在上層引入分散式鎖,來確保資料一致性和完整性。這種使用模式在SAN領域並不少見,其典型應用場景是多機同時掛載一個網路硬碟,並通過叢集檔案系統(而不是常見的單機檔案系統)來協調訪問儲存空間。叢集檔案系統內部會使用分散式鎖來確保資料操作的正確性,所以我們舍C的設計決策不會影響多機並行訪問的使用模式。

3.3 併發模型

併發(不是並行!)模型的選擇和設計無法作為實現細節隱藏在區域性,它會影響到程式程式碼的各個部分,從底層到上層。基本的併發模型只有這樣幾種:事件驅動、多執行緒、多程式以及較為小眾的多協程。

事件驅動模型是一種更接近硬體工作模式的併發模型,具有更高的執行效率,是高效能網路服務的普遍選擇。為能充分發揮萬兆網路和SSD的效能潛力,我們必須利用多核心並行服務,因而需要選用多執行緒或者多程式模型。由於多程式模型更加簡單,程式天然是故障傳播的屏障,這兩方面都十分有利於提高軟體的健壯性;並且我們也很容易對業務進行橫向拆分,做到互相沒有依賴,也不需要互動,所以我們選擇了多程式模型,與事件驅動一起構成混合模型。

協程在現實中的應用並不多,很多語言/開發生態甚至不支援協程,然而協程在一些特定領域其實具有更好的適用性。比如,QEMU/KVM在磁碟I/O方面的併發執行完全是由協程負責的,即便某些block driver只提供了事件驅動的介面(如Ceph RBD),QEMU/KVM也會自動把它們轉化封裝成多協程模式。實踐表明,在併發I/O領域,多協程模型可以同時在效能和易用性方面取得非常好的效果,所以我們做了跟QEMU/KVM類似的選擇——在底層將事件驅動模型轉換成了多協程模型,最終形成了“多程式+多協程+事件驅動”的混合併發模型。

3.4 儲存結構

如圖所示,Ursa中的儲存結構與GFS/HDFS相似,儲存卷由64MB(可配置)大小的chunk組成。Ursa系統中的資料複製、故障檢測與修復均在chunk層次進行。系統中,每3個(可配置)chunk組成一組,互為備份。每2個chunk組構成一個stripe組,實現條帶化交錯讀寫,提高單客戶端順序讀寫效能。Ursa在I/O棧上層新增Cache模組,可將最常用的資料快取在客戶端本地的SSD介質當中,當訪問命中快取時可大大提高效能。

美團

3.5 寫入策略

最常見的寫入策略有兩種:(1)客戶端直接寫多個副本到各個Chunk Server,如圖(a)所示,Sheepdog採用此種辦法;(2)客戶端寫第一個副本,並將寫請求依次傳遞下去,如圖(b)所示。這兩種方法各有利弊:前者通常具有較小的寫入延遲,但吞吐率最高只能達到網路頻寬的1/3;後者的吞吐率可以達到100%網路頻寬,卻具有較高的寫入延遲。

美團

由於Ursa可能用於支援各種型別的應用,必須同時面向吞吐率和頻寬進行優化,所以我們設計採用了一種分叉式的寫入策略:如圖(c)所示,客戶端使用WRITE_REPLICATE請求求將資料寫到第一個副本,稱為primary,然後由primary負責將資料分別寫到其他副本。這樣Ursa可以在吞吐率和延遲兩方面取得較好的均衡。為確保資料可靠性,寫操作會等所有副本的寫操作都完成之後才能返回。

3.6 無狀態服務

Chunk Server內部幾乎不儲存狀態,通常情況下各個請求之間是完全獨立執行的,並且重啟Chunk Server不會影響後續請求的執行。這樣的Chunk Server不但具有更高的魯棒性,而且具有更高的擴充套件性。許多其他網路服務、協議的設計都遵循了無狀態的原則。

3.7 模組

如下圖所示,Ursa中的I/O功能模組的組織採用decorator模式,即所有模組都實現了IStore抽象介面,其中負責直接與Chunk Server通訊的模組屬於decorator模式中的concrete component,其餘模組均為concrete decorator。所有的decorator都儲存數量不等的指向其他模組的指標(IStore指標)。

美團

在執行時,Ursa的I/O棧層次結構的物件圖如下所示。

iostack

3.8 產品介面

ui

效能實測

如下圖所示,測試環境由萬兆乙太網、1臺Client和3臺Chunk Server組成,chunk檔案存在tmpfs上,即所有寫操作不落盤,寫到記憶體為止。選擇tmpfs主要是為了避免硬碟的I/O速度的侷限性,以便測試Ursa在極限情況下的表現。

test_env

測試環境的網路延遲如下:

美團

在上述環境中,用fio分別測試了讀寫操作的吞吐率、IOPS以及I/O延遲,測試引數與結果如下:

benchmarks

從測試結果可以看出:
(1). Ursa在吞吐率測試中可以輕易接近網路卡理論頻寬;
(2). Ursa的IOPS效能可以達到SSD的水準;
(3). Ursa的讀延遲接近ping值,寫操作需要寫3個副本,延遲比讀高68%。

作為對比,我們在測試Ceph的過程中監測到服務端CPU佔用情況如下:

ceph-osd-cpu

此時機器上5個儲存服務程式ceph-osd共佔用123.7%的CPU資源,提供了4 101的讀IOPS服務;而Ursa的服務程式只消耗了43%的CPU資源,提供了61 340讀IOPS服務,執行效率比Ceph高43倍。在客戶端方面,Ceph消耗了500%+的CPU資源,得到了16 407讀IOPS;而Ursa只消耗了96%的CPU資源,得到了61 340讀IOPS,執行效率比Ceph高21倍

總結與展望

Ursa從零開始動手開發到內部上線只經歷了9個月的時間,雖然基本功能、效能都已達到預期,但仍有許多需要進一步開發的地方。一個重要的方向是對SSD的支援。雖然將HDD簡單替換為SSD,不修改Ursa的任何程式碼、配置就可以執行,並取得效能上的顯著改善,然而SSD在效能、成本、壽命等方面與HDD差異巨大,Ursa必須做出針對性的優化才能使SSD揚長避短。另一個重要方向是對大量VM同時啟動的更好的支援。如果同時有上百臺相同的VM從Ursa啟動(即系統盤放在Ursa上),會在短時間內有大量讀請求訪問相同的資料集(啟動檔案),形成區域性熱點,此時相關的Chunk Server服務能力會出現不足,導致啟動變慢。由於各個VM所需的啟動資料基本相同,我們可以採用“一傳十,十傳百”的方式組織一個應用層組播樹overlay網路來進行資料分發,這樣可以從容應對熱點資料訪問問題。隨著一步步的完善,相信Ursa將在雲平臺的運營當中起到越來越重要的作用。

相關文章