面向雲數據庫,超低延遲文件系統PolarFS誕生了

摘要: 如同Oracle存在與之匹配的OCFS2,POLARDB做爲存儲與計算分離結構的一款數據庫,PolarFS承擔着發揮POLARDB特性相當重要的角色。PolarFS是一款具備超低延遲和高可用能力的分佈式文件系統,其採用了輕量的用戶空間網絡和I/O棧構建,而棄用了對應的內核棧,目的是充分發揮RDMA和NVMe SSD等新興硬件的潛力,極大地下降分佈式非易失數據訪問的端到端延遲。node

隨着國內首款Cloud Native自研數據庫POLARDB精彩亮相ICDE 2018的同時,做爲其核心支撐和使能平臺的PolarFS文件系統的相關論文"PolarFS: An Ultra-low Latency and Failure Resilient Distributed File System for Shared Storage Cloud Database"也被數據庫頂級會議VLDB 2018錄用。8月,阿里雲數據庫團隊亮相於巴西里約召開的VLDB 2018,對整個業界起到了很是積極的影響。算法

VLDB(Very Large Data Base)和另外兩大數據庫會議SIGMOD、ICDE構成了數據庫領域的三個頂級會議。VLDB國際會議於1975在美國的弗雷明漢馬 (Framingham MA) 成立,是數據庫研究人員,供應商,參與者,應用開發者,以及用戶一年一度的頂級國際論壇。數據庫

VLDB主要由四個主題構成,分別爲:Core Database Technology (核心數據庫技術),Infrastructure for Information Systems (基礎設施信息系統),Industrial Applications and Experience (工業應用與經驗) 以及 Experiments and Analyses(實驗和分析)。後端

從09年至今的數據分析來看,VLDB的論文接受率整體是比較低,其中,核心數據庫主題中的論文接受率大概爲16.7%;基礎設施信息系統方面的論文接受率大約爲17.9%;工業應用與經驗的論文接收比例近視爲18%;而實驗和分析部分的爲19%左右。因而可知,論文被VLDB接收不是件容易的事情,必須是創新性很高,貢獻很大的論文才有機會被錄用。緩存

本文着重介紹PolarFS的系統設計與實現。安全

背景
如同Oracle存在與之匹配的OCFS2,POLARDB做爲存儲與計算分離結構的一款數據庫,PolarFS承擔着發揮POLARDB特性相當重要的角色。PolarFS是一款具備超低延遲和高可用能力的分佈式文件系統,其採用了輕量的用戶空間網絡和I/O棧構建,而棄用了對應的內核棧,目的是充分發揮RDMA和NVMe SSD等新興硬件的潛力,極大地下降分佈式非易失數據訪問的端到端延遲。目前,PolarFS的3副本跨節點寫入的訪問總延遲已經很是接近單機本地PCIe SSD的延遲水平,成功地使得POLARDB在分佈式多副本架構下仍然可以發揮出極致的性能。服務器

設計初衷
針對數據庫設計分佈式文件系統會帶來如下幾點好處:網絡

計算節點和存儲節點可使用不一樣的服務器硬件,並能獨立地進行定製。例如,計算節點不須要考慮存儲容量和內存容量的比例,其嚴重依賴於應用場景而且難以預測。數據結構

多個節點上的存儲資源可以造成單一的存儲池,這能下降存儲空間碎化、節點間負載不均衡和空間浪費的風險,存儲容量和系統吞吐量也能容易地進行水平擴展。多線程

數據庫應用的持久狀態可下移至分佈式文件系統,由分佈式存儲提供較高的數據可用性和可靠性。所以數據庫的高可用處理可被簡化,也利於數據庫實例在計算節點上靈活快速地遷移。

此外,雲數據庫服務也會所以帶來額外的收益:

雲數據庫能夠採用虛擬計算環境如KVM等部署形態,其更安全、更易擴展和更易升級管理。

一些關鍵的數據庫特性,如一寫多讀實例、數據庫快照等能夠經過分佈式文件系統的數據共享、檢查點等技術而得以加強。

圖片描述

系統結構
系統組件

PolarFS系統內部主要分爲兩層管理:

存儲資源的虛擬化管理,其負責爲每一個數據庫實例提供一個邏輯存儲空間。

文件系統元數據的管理,其負責在該邏輯存儲空間上實現文件管理,並負責文件併發訪問的同步和互斥。

PolarFS的系統結構如圖所示:

圖片描述

libpfs是一個用戶空間文件系統庫,負責數據庫的I/O接入。
PolarSwitch運行在計算節點上,用於轉發數據庫的I/O請求。
ChunkServer部署在存儲節點上,用於處理I/O請求和節點內的存儲資源分佈。
PolarCtrl是系統的控制平面,它包含了一組實現爲微服務的管理者,相應地Agent代理被部署到全部的計算和存儲節點上。
在進一步介紹各部分以前,咱們先來了解下PolarFS存儲資源的組織方法:

PolarFS的存儲資源管理單元分爲3層:Volume、Chunk、Block。

Volume

Volume是爲每一個數據庫提供的獨立邏輯存儲空間,其上創建了具體文件系統供此數據庫使用,其大小爲10GB至100TB,可充分適用於典型雲數據庫實例的容量要求。

在Volume上存放了具體文件系統實例的元數據。文件系統元數據包括inode、directory entry和空閒資源塊等對象。因爲POLARDB採用的是共享文件存儲架構,咱們在文件層面實現了文件系統元數據一致性,在每一個文件系統中除DB創建的數據文件以外,咱們還有用於元數據更新的Journal文件和一個Paxos文件。咱們將文件系統元數據的更新首先記錄在Journal文件中,並基於Paxos文件以disk paxos算法實現多個實例對Journal文件的互斥寫訪問。

Chunk

每一個Volume內部被劃分爲多個Chunk,Chunk是數據分佈的最小粒度,每一個Chunk只存放於存儲節點的單個NVMe SSD盤上,其目的是利於數據高可靠和高可用的管理。典型的Chunk大小爲10GB,這遠大於其餘相似的系統,例如GFS的64MB。

這樣作的優點是可以有效地減小Volume的第一級映射元數據量的大小(例如,100TB的Volume只包含10K個映射項)。一方面,全局元數據的存放和管理會更容易;另外一方面,這使得元數據能夠方便地緩存在內存中,從而有效避免關鍵I/O路徑上的額外元數據訪問開銷。

但這樣作的潛在問題是,當上層數據庫應用出現區域級熱點訪問時,Chunk內熱點沒法進一步打散,可是因爲咱們的每一個存儲節點提供的Chunk數量每每遠大於節點數量(節點:Chunk在1:1000量級),PolarFS可支持Chunk的在線遷移,而且服務於大量數據庫實例,所以能夠將不一樣實例的熱點以及同一實例跨Chunk的熱點分佈到不一樣節點以得到總體的負載均衡。

Block

在ChunkServer內,Chunk會被進一步劃分爲多個Block,其典型大小爲64KB。Blocks動態映射到Chunk 中來實現按需分配。Chunk至Block的映射信息由ChunkServer自行管理和保存,除數據Block以外,每一個Chunk還包含一些額外Block用來實現Write Ahead Log。咱們也將本地映射元數據所有緩存在ChunkServer的內存中,使得用戶數據的I/O訪問可以全速推動。

下面咱們詳細介紹PolarFS的各個系統組件。

libpfs

libpfs是一個輕量級的用戶空間庫,PolarFS採用了編譯到數據庫的形態,替換標準的文件系統接口,這使得所有的I/O路徑都在用戶空間中,數據處理在用戶空間完成,儘量減小數據的拷貝。這樣作的目的是避免傳統文件系統從內核空間至用戶空間的消息傳遞開銷,尤爲數據拷貝的開銷。這對於低延遲硬件的性能發揮尤其重要。

其提供了類Posix的文件系統接口(見下表),於是付出很小的修改代價便可完成數據庫的用戶空間化。

圖片描述

PolarSwitch

PolarSwitch是部署在計算節點的Daemon,它負責I/O請求映射到具體的後端節點。數據庫經過libpfs將I/O請求發送給PolarSwitch,每一個請求包含了數據庫實例所在的Volume ID、起始偏移和長度。PolarSwitch將其劃分爲對應的一到多個Chunk,並將請求發往Chunk所屬的ChunkServer完成訪問。

ChunkServer

ChunkServer部署在後端存儲節點上。一個存儲節點能夠有多個ChunkServer。每一個ChunkServer綁定到一個CPU核,並管理一個獨立的NVMe SSD盤,所以ChunkServer之間沒有資源爭搶。

ChunkServer負責Chunk內的資源映射和讀寫。每一個Chunk都包括一個WAL,對Chunk的修改會先進Log再修改,保證數據的原子性和持久性。ChunkServer使用了3DXPoint SSD和普通NVMe SSD混合型WAL buffer,Log會優先存放到更快的3DXPoint SSD中。

ChunkServer會複製寫請求到對應的Chunk副本(其餘ChunkServer)上,咱們經過本身定義的Parallel Raft一致性協議來保證Chunk副本之間在各種故障情況下數據正確同步和保障已Commit數據不丟失。

PolarCtrl

PolarCtrl是PolarFS集羣的控制核心。其主要職責包括:

監控ChunkServer的健康情況,肯定哪些ChunkServer有權屬於PolarFS集羣;
Volume建立及Chunk的佈局管理(即Chunk分配到哪些ChunkServer);
Volume至Chunk的元數據信息維護;
向PolarSwitch推送元信息緩存更新;
監控Volume和Chunk的I/O性能;
週期性地發起副本內和副本間的CRC數據校驗。
PolarCtrl使用了一個關係數據庫雲服務用於管理上述metadata。

中心統控,局部自治的分佈式管理
分佈式系統的設計有兩種範式:中心化和去中心化。中心化的系統包括GFS和HDFS,其包含單中心點,負責維護元數據和集羣成員管理。這樣的系統實現相對簡單,但從可用性和擴展性的角度而言,單中心可能會成爲全系統的瓶頸。去中心化的系統如Dynamo徹底相反,節點間是對等關係,元數據被切分並冗餘放置在全部的節點上。去中心化的系統被認爲更可靠,但設計和實現會更復雜。

PolarFS在這兩種設計方式上作了必定權衡,採用了中心統控,局部自治的方式:PolarCtrl是一箇中心化的master,其負責管理任務,如資源管理和處理控制平面的請求如建立Volume。ChunkServer負責Chunk內部映射的管理,以及Chunk間的數據複製。當ChunkServer彼此交互時,經過ParallelRaft一致性協議來處理故障並自動發起Leader選舉,這個過程無需PolarCtrl參與。

PolarCtrl服務因爲不直接處理高併發的I/O流,其狀態更新頻率相對較低,於是可採用典型的多節點高可用架構來提供PolarCtrl服務的持續性,當PolarCtrl因崩潰恢復出現的短暫故障間隙,因爲PolarSwitch的緩存以及ChunkServer數據平面的局部元數據管理和自主leader選舉的緣故,PolarFS可以儘可能保證絕大部分數據I/O仍能正常服務。

I/O 流程
下面咱們經過一個I/O的處理來講明各組件的互動過程。

圖片描述

PolarFS執行寫I/O請求的過程如上圖所示:

POLARDB經過libpfs發送一個寫請求,經由ring buffer發送到PolarSwitch。
PolarSwitch根據本地緩存的元數據,將該請求發送至對應Chunk的主節點。
新寫請求到達後,主節點上的RDMA NIC將寫請求放到一個提早分好的buffer中,並將該請求項加到請求隊列。一個I/O輪詢線程不斷輪詢這個請求隊列,一旦發現新請求到來,它就當即開始處理。
請求經過SPDK寫到硬盤的日誌block,並經過RDMA發向副本節點。這些操做都是異步調用,數據傳輸是併發進行的。
當副本請求到達副本節點,副本節點的RDMA NIC一樣會將其放到預分buffer中並加入到複製隊列。
副本節點上的I/O輪詢線程被觸發,請求經過SPDK異步地寫入Chunk的日誌。
當副本節點的寫請求成功回調後,會經過RDMA向主節點發送一個應答響應。
主節點收到一個複製組中大多數節點的成功返回後,主節點經過SPDK將寫請求應用到數據塊上。
隨後,主節點經過RDMA向PolarSwitch返回。
PolarSwitch標記請求成功並通知上層的POLARDB。
數據副本一致性模型
ParallelRaft協議設計動機

一個產品級別的分佈式存儲系統須要確保全部提交的修改在各類邊界狀況下均不丟失。PolarFS在Chunk層面引入一致性協議來保證文件系統數據的可靠性和一致性。設計之初,從工程實現的成熟度考慮,咱們選擇了Raft算法,但對於咱們構建的超低延遲的高併發存儲系統而言,很快就遇到了一些坑。

Raft爲了簡單性和協議的可理解性,採用了高度串行化的設計。日誌在leader和follower上都不容許有空洞,其意味着全部log項會按照順序被follower確認、被leader提交併apply到全部副本上。所以當有大量併發寫請求執行時,會按順序依次提交。處於隊列尾部的請求,必需等待全部以前的請求已被持久化到硬盤並返回後纔會被提交和返回,這增長了平均延遲也下降了吞吐量。咱們發現當併發I/O深度從8升到32時,I/O吞吐量會下降一半。

Raft並不十分適用於多鏈接的在高併發環境。實際中leader和follower使用多條鏈接來傳送日誌很常見。當一個連接阻塞或者變慢,log項到達follower的順序就會變亂,也便是說,一些次序靠後的log項會比次序靠前的log項先到。可是,Raft的follower必需按次序接收log項,這就意味着這些log項即便被記錄到硬盤也只能等到前面全部缺失的log項到達後才能返回。而且假如大多數follower都因一些缺失的項被阻塞時,leader也會出現卡頓。咱們但願有一個更好的協議能夠適應這樣的情形。

因爲PolarFS之上運行的是Database事務處理系統,它們在數據庫邏輯層面的並行控制算法使得事務能夠交錯或亂序執行的同時還能生成可串行化的結果。這些應用自然就須要容忍標準存儲語義可能出現的I/O亂序完成狀況,並由應用自身進一步保證數據一致性。所以咱們能夠利用這一特色,在PolarFS中依照存儲語義放開Raft一致性協議的某些約束,從而得到一種更適合高I/O併發能力發揮的一致性協議。

咱們在Raft的基礎上,提供了一種改進型的一致性協議ParallelRaft。ParallelRaft的結構與Raft一致,只是放開了其嚴格有序化的約束。

亂序日誌複製

Raft經過兩個方面保障串行化:

當leader發送一個log項給follower,follower須要返回ack來確認該log項已經被收到且記錄,同時也隱式地代表全部以前的log項均已收到且保存完畢。
當leader提交一個log項並廣播至全部follower,它也同時確認了全部以前的log項都已被提交了。ParallelRaft打破了這兩個限制,並讓這些步驟可亂序執行。
所以,ParallelRaft與Raft最根本的不一樣在於,當某個entry提交成功時,並不意味着以前的全部entry都已成功提交。所以咱們須要保證:

在這種狀況下,單個存儲的狀態不會違反存儲語義的正確性;
全部已提交的entry在各類邊界狀況下均不會丟失;
有了這兩點,結合數據庫或其餘應用廣泛存在的對存儲I/O亂序完成的默認容忍能力,就能夠保證它們在PolarFS上的正常運轉,並得到PolarFS提供的數據可靠性。

ParallelRaft的亂序執行遵循以下原則:

當寫入的Log項彼此的存儲範圍沒有交疊,那麼就認爲Log項無衝突能夠亂序執行;
不然,衝突的Log項將按照寫入次序依次完成。
容易知道,依照此原則完成的I/O不會違反傳統存儲語義的正確性。
接下來咱們來看log的ack-commit-apply環節是如何所以獲得優化而且保持一致性的。

亂序確認(ack):當收到來自leader的一個log項後,Raft follower會在它及其全部以前的log項都持久化後,才發送ack。ParallelRaft則不一樣,任何log entry成功持久化後均能當即返回,這樣就優化了系統的平均延遲。
亂序提交(commit):Raft leader串行提交log項,一個log項只有以前的全部項提交以後才能提交。而ParallelRaft的leader在一個log項的多數副本已經確認以後便可提交。這符合存儲系統的語義,例如,NVMe SSD驅動並不檢查讀寫命令的LBA來保證並行命令的次序,對命令的完成次序也沒有任何保證。
亂序應用(apply):對於Raft,全部log項都按嚴格的次序apply,所以全部副本的數據文件都是一致的。可是,ParallelRaft因爲亂序的確認和提交,各副本的log均可能在不一樣位置出現空洞,這裏的挑戰是,如何保證前面log項有缺失時,安全地apply一個log項?
ParallelRaft引入了一種新型的數據結構look behind buffer來解決apply中的問題。

ParallelRaft的每一個log項都附帶有一個look behind buffer。look behind buffer存放了前N個log項修改的LBA摘要信息。
look behind buffer的做用就像log空洞上架設的橋樑,N表示橋樑的寬度,也就是容許單個空洞的最大長度,N的具體取值可根據網絡連續缺失log項的機率大小,靜態地調整爲合適的值,以保證log橋樑的連續性。
經過look behind buffer,follower可以知道一個log項是否衝突,也就是說是否有缺失的前序log項修改了範圍重疊的LBAs。沒有衝突的log項能被安全apply。若有衝突,它們會被加到一個pending list,待以前缺失的衝突log項apply以後,纔會接着apply。
經過上述的異步ack、異步commit和異步apply,PolarFS的chunk log entry的寫入和提交避免了次序形成的額外等待時間,從而有效縮減了高併發3副本寫的平均時延。

ParallelRaft協議正確性

咱們在ParallelRaft的設計中,確保了Raft協議關鍵特性不丟失,從而保障了新協議的正確性。

ParallelRaft協議的設計繼承了原有Raft協議的Election Safety、Leader Append-Only及Log Matching特性。
衝突log會以嚴格的次序提交,所以協議的State Machine Safety特性可以最終得以保證。
咱們在Leader選舉階段額外引入了一個Merge階段,填補Leader中log的空洞,可以有效保障協議的Leader Completeness特性。
PolarFS中與POLARDB緊密相關的設計
文件系統多副本高速寫入——數據庫單實例的超高TPS,數據高可靠

PolarFS設計中採用了以下技術以充分發揮I/O性能:

PolarFS採用了綁定CPU的單線程有限狀態機的方式處理I/O,避免了多線程I/O pipeline方式的上下文切換開銷。
PolarFS優化了內存的分配,採用MemoryPool減小內存對象構造和析構的開銷,採用巨頁來下降分頁和TLB更新的開銷。
PolarFS經過中心加局部自治的結構,全部元數據均緩存在系統各部件的內存中,基本徹底避免了額外的元數據I/O。
PolarFS採用了全用戶空間I/O棧,包括RDMA和SPDK,避免了內核網絡棧和存儲棧的開銷。
在相同硬件環境下的對比測試,PolarFS中數據塊3副本寫入性能接近於單副本本地SSD的延遲性能。從而在保障數據可靠性的同時,極大地提高POLARDB的單實例TPS性能。

下圖是咱們採用Sysbench對不一樣負載進行的初步測試比較。

POLARDB on PolarFS
Alibaba MySQL Cloud Service RDS
圖片描述

用例負載:OLTP,只讀、只寫(update : delete : insert = 2:1:1)、讀寫混合(read : write = 7:2)。數據庫測試集數據量爲500GB。

能夠發現POLARDB在PolarFS下取得了較好的性能,PolarFS同時支持了POLARDB的高TPS和數據的高可靠性。

文件系統共享訪問——寫多讀的數據庫QPS強擴展,數據庫實例的Failover

PolarFS是共享訪問的分佈式文件系統,每一個文件系統實例都有相應的Journal文件和與之對應的Paxos文件。Journal文件記錄了metadata的修改歷史,是共享實例之間元數據同步的中心。Journal文件邏輯上是一個固定大小的循環buffer。PolarFS會根據水位來回收journal。Paxos文件基於Disk Paxos實現了分佈式互斥鎖。

因爲journal對於PolarFS很是關鍵,它們的修改必需被Paxos互斥鎖保護。若是一個節點但願在journal中追加項,其必需使用DiskPaxos算法來獲取Paxos文件中的鎖。一般,鎖的使用者會在記錄持久化後立刻釋放鎖。可是一些故障狀況下使用者不釋放鎖。爲此在Paxos互斥鎖上分配有一個租約lease。其餘競爭者能夠重啓競爭過程。當PolarFS當節點開始同步其餘節點修改的元數據時,它從上次掃描的位置掃描到journal末尾,將新entry更新到memory cache中。

下圖展現了文件系統元數據更新和同步的過程。

圖片描述

節點1分配塊201至文件316後,請求互斥鎖,並得到。
Node 1開始記錄事務至journal中。最後寫入項標記爲pending tail。當全部的項記錄以後,pending tail變成journal的有效tail。
Node1更新superblock,記錄修改的元數據。與此同時,node2嘗試獲取node1擁有的互斥鎖,Node2會失敗重試。
Node2在Node1釋放lock後拿到鎖,但journal中node1追加的新項決定了node2的本地元數據是過期的。
Node2掃描新項後釋放lock。而後node2回滾未記錄的事務並更新本地metadata。最後Node2進行事務重試。
Node3開始自動同步元數據,它只須要load增量項並在它本地重放便可。
PolarFS的上述共享機制很是適合POLARDB一寫多讀的典型應用擴展模式。一寫多讀模式下沒有鎖爭用開銷,只讀實例能夠經過原子I/O無鎖獲取Journal信息,從而使得POLARDB能夠提供近線性的QPS性能擴展。

因爲PolarFS支持了基本的多寫一致性保障,當可寫實例出現故障時,POLARDB可以方便地將只讀實例升級爲可寫實例,而沒必要擔憂底層存儲產生不一致問題,於是方便地提供了數據庫實例Failover的功能。

文件系統級快照——POLARDB的瞬時邏輯備份

對於百TB級超大數據庫實例的備份而言,數據庫快照是必須支持的功能。

PolarFS採用了自有的專利快照技術,可以基於位於底層的多個ChunkServer的局部快照,構建Volume上的統一的文件系統即時映像。POLARDB利用自身數據庫的日誌,可以基於此文件系統映像快速構建出此具體時點的數據庫快照,從而有效支持數據庫備份和數據分析的需求。

圖片描述

能夠發現,POLARDB的高性能、強擴展、輕運維等具有競爭優點的優異特性,與PolarFS的緊密協做息息相關,PolarFS發揮了強大的使能做用。

結論
PolarFS是一個專爲雲數據庫而設計的分佈式文件系統,其可以支持跨節點高可靠性同時提供極致的性能。PolarFS採用了新興硬件和先進的優化技術,例如OS-bypass和zero-copy,使得PolarFS中數據塊3副本寫入性能接近於單副本本地SSD的延遲性能。PolarFS在用戶空間實現了POSIX兼容接口,使得POLARDB等數據庫服務可以儘可能少地修改便可得到PolarFS帶來的高性能的優點。

能夠看到,面向數據庫的專有文件系統,是保障將來數據庫技術領先的一個不可或缺的關鍵一環。數據庫內核技術的進展及其專有文件系統的使能,是一個相輔相成的演進過程,兩者的結合也會隨着當今系統技術的進步而越發緊密。

將來咱們將探索NVM和FPGA等新硬件,以期經過文件系統與數據庫的深度結合來進一步優化POLARDB數據庫的性能。

原文連接

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索