BlueStore——先进的用户态文件系统《一》
目錄
為什么需要 BlueStore
IO 放大
對象遍歷
其他
BlueStore 介紹
邏輯架構
設計思想
總結
引言
分布式存儲系統通過將數據分散到多臺機器上來充分利用多臺機器的資源提高系統的存儲能力,每臺機器上的數據存放都需要本地的單機存儲系統,它是整個分布式存儲系統的基礎,為其提供保障。設計高性能、高可靠的分布式存儲系統離不開高效、一致、穩定、可靠的本地存儲系統。
Ceph 是目前業內比較普遍使用的開源分布式存儲系統,實現有多種類型的本地存儲系統;在較早的版本當中,Ceph?默認使用 FileStore 作為后端存儲,但是由于 FileStore 存在一些缺陷,重新設計開發了 BlueStore,并在L版本之后作為默認的后端存儲。BlueStore 的一些設計思想對于設計滿足分布式存儲系統需求的本地存儲系統具有參考意義,因此我們將對 BlueStore 的一些原理進行剖析,供讀者進行參考和探討。在這一章中,我們將要了解 BlueStore 的誕生背景,以及它的一些設計思想。
?
?
為什么需要 BlueStore
前面提到,BlueStore 的誕生背景是由于 FileStore 存在的一些缺陷,這些缺陷具體是什么?
?
IO 放大
FileStore 底層使用POSIX規范的文件系統接口,例如 xfs、ext4、btrfs,然而這類文件系統本身不支持數據或元數據的事務操作接口(btrfs 提供事務鉤子的接口,但是測試過程中發現會導致系統宕機),而 Ceph?對于數據寫入要求十分嚴格,需要滿足事務的特性(ACID);為此 FileStore 實現了 FileJournal 功能,所有的事務都需要先寫到 FileJournal 中,之后才會寫入對應的文件中,以此來保證事務的原子性,但是這導致了數據 “雙寫” 的問題,造成至少一半磁盤帶寬的浪費。此外 xfs、ext4、btrfs 這類文件系統本身存在一定的 IO 放大(即一次讀寫請求實際在低層磁盤發生的 IO 次數),再加上 FileStore 的日志雙寫,放大倍數成倍增加。
下圖中的數據表示了以 block 大小為單位對不同文件系統進行讀寫,在不同場景下的讀寫放大及空間放大情況。我們以 ext4 文件系統說明下個參數的含義。在對文件進行 Overwrite 時,即將數據覆蓋寫入到文件中,除了寫入數據外,還涉及到日志的寫入(其中日志寫入兩次,一次記錄更改的 inode,一次為 commit 記錄,具體可參考)、文件 inode 的更改,每次寫的最小單位是block,因此最終相當于寫入次數以及空間放大了四倍;而在進行 Append 寫入時,由于需要新分配空間,因此相對于 Overwrite 增加了 bitmap 的更改以及 superblock 的更改( superblock 記錄總的空間分配情況),寫放大和空間放大均為六倍。讀文件時,在沒有命中任何緩存的情況下,需要讀大量元數據,例如:目錄、文件 inode、superblock 等,最終讀放大為六倍;而如果是在順序讀的情況下,像 superblock、bitmap、目錄等這些元數據都緩存在內存中,只需讀取文件 inode 和文件數據。?
同理,其他文件系統由于不同的結構和設計原理,其 IO 放大和空間放大系數也各不相同。下面這個表展示了不同文件系統在讀寫文件時產生的讀、寫和空間放大程度。
?
?
對象遍歷
Ceph?的數據被劃分為 object 存放,object 以 32 位的 hash 值進行標識,ceph 在進行 scrubbing、backfill 或者 recovery 時都需要根據 hash 值遍歷這些 object;POSIX 文件系統不提供有序的文件遍歷接口,為此 FileStore 根據文件的數量和 hash 的前綴將 object 劃分到不同的子目錄,其原則如下:
- 當目錄下的文件個數 >100 個時,拆分子目錄;目錄名以文件名的 hash 前綴為依據(拆分一級目錄時,以 hash 第一位為拆分依據,二級目錄以第二位 hash 為拆分依據,依次類推)。
- 當所有子目錄下的文件個數 <50 個時,將合并到上級目錄。
因此 FileStore 在使用過程中需要不斷合并拆分目錄結構;這種方式將文件按照前綴放到不同目錄,但對于同一目錄中的文件依然無法很好排序,因此需要將目錄中的所有文件讀到內存進行排序,這樣在一定程度上增加了 CPU 開銷。
?
其他
- FileStore 由于設計的較早,無法支持當前較新的存儲技術,例如使用 spdk 技術讀寫 NVMe 盤。
- 數據和元數據分離不徹底。
- 流控機制不完整導致 IOPS 和帶寬抖動(FileStore 自身無法控制本地文件系統的刷盤行為)。
- 頻繁 syncfs 系統調用導致 CPU 利用率居高不下。
sync() causes all buffered modifications to file metadata and ?data ?to?be written to the underlying filesystems.
syncfs() ?is like sync(), but synchronizes just the filesystem containing file referred to by the open file descriptor fd.
sync() 將導致所有對文件元數據和數據的緩沖修改寫入底層文件系統。
syncfs() 類似于 sync(),但只同步包含打開文件描述符 fd 引用的文件的文件系統。
?
?
BlueStore 介紹
首先看下 BlueStore 設計之初的一些需求:
- 對全 SSD 及全 NVMe SSD 閃存適配
- 繞過本地文件系統層,直接管理裸設備,縮短 IO 路徑
- 嚴格分離元數據和數據,提高索引效率
- 使用 KV 索引,解決文件系統目錄結構遍歷效率低的問題
- 支持多種設備類型
- 解決日志“雙寫”問題
- 期望帶來至少 2 倍的寫性能提升和同等讀性能
- 增加數據校驗及數據壓縮等功能
?
邏輯架構
BlueStore 的邏輯架構如上圖所示,模塊的劃分都還比較清晰,我們來看下各模塊的作用:
RocksDB:RocksDB?是 FaceBook 基于 leveldb 開發的一款 kv 數據庫,BlueStore 將元數據全部存放至 RocksDB 中,這些元數據包括存儲預寫式日志、數據對象元數據、Ceph 的 omap 數據信息、以及分配器的元數據 。
BlueRocksEnv:這是 RocksDB 與 BlueFS 交互的接口;RocksDB 提供了文件操作的接口 EnvWrapper,用戶可以通過繼承實現該接口來自定義底層的讀寫操作,BlueRocksEnv 就是繼承自 EnvWrapper 實現對 BlueFS 的讀寫。
BlueFS:BlueFS 是 BlueStore 針對 RocksDB 開發的輕量級文件系統,用于存放 RocksDB 產生的 .sst 和 .log 等文件。
BlockDecive:BlueStore 拋棄了傳統的 ext4、xfs 文件系統,使用直接管理裸盤的方式;BlueStore 支持同時使用多種不同類型的設備,在邏輯上 BlueStore 將存儲空間劃分為三層:慢速(Slow)空間、高速(DB)空間、超高速(WAL)空間,不同的空間可以指定使用不同的設備類型,當然也可使用同一塊設備,具體我們會在后面的文章進行說明。
Allocator:負責裸設備的空間管理,只在內存做標記,目前支持 StupidAllocator 和 BitmapAllocator 兩種分配器,Stupid 基于 extent 的方式實現 。
?
?
設計思想
在設計分布式文件系統的本地存儲時,我們必須考慮數據的一致性和可靠性。在數據寫入的過程中,由于可能存在異常掉電、進程崩潰等突發情況,導致數據還未全部寫入成功便結束。雖然硬盤本身可以保證在扇區級別寫入的原子性,但是一般文件系統的一個寫請求通常包含多個扇區的數據和元數據更新,無法做到原子寫。
常用的解決辦法是引入日志系統,數據寫入磁盤之前先寫到日志系統,然后再將數據落盤;日志寫入成功后,即便寫數據時出現異常,也可以通過日志回放重新寫入這部分數據;如果寫日志的過程中出現異常,則直接放棄這部分日志,視為寫入失敗即可,以此保證原子寫入。但是這種方式導致每份數據都需要在磁盤上寫入兩次,嚴重降低了數據的寫入效率。
另一種方式則是采用 ROW(Redirect on write)的方式,即數據需要覆蓋寫入時,將數據寫到新的位置,然后更新元數據索引,這種方式由于不存在覆蓋寫,只需保證元數據更新的原子性即可。對于對齊的覆蓋寫入時,這種方式沒有問題,但是如果是非對齊的覆蓋寫呢?
我們舉個例子:某文件的邏輯空間 [0,4096) 區間的數據在磁盤上的物理映射地址為 [0, 4096),磁盤的塊(即磁盤讀寫的最小單元)大小為 4096 ;如果要覆蓋寫文件 [0,4096) 區間的數據,那使用 ROW 的方式沒有問題,重新再磁盤上分配一個新的塊寫入,然后更新元數據中的映射關系即可;但是如果寫文件 [512,4096) 區域,也就是非對齊的覆蓋寫時,新分配的塊中只有部分數據,舊的物理空間中仍有部分數據有效,這樣元數據中需要維護兩份索引,而且在讀取文件的該塊數據時,需要從多塊磁盤塊中讀取數據,如果多次進行非對齊覆蓋寫,這種問題將更嚴重。
解決這種問題辦法是使用 RMW(Read Modify Write)的方法,即在發生非對齊覆蓋寫時,先讀取舊的數據,更新的數據合并后,對齊寫入到磁盤中,從而減少元數據、提高讀性能,但這種方式也存在一種缺點,寫數據時需要先讀數據,存在一定的性能損耗。
分析完 ROW 的方式后,讀者是否會有疑問,每次寫入都放到新的位置,那么文件在磁盤中的物理連續性豈不是無法保證?的確,在傳統的文件系統設計時,都是面向 HDD 盤,這種類型的盤在讀寫時會有磁頭尋道的時間,對于非連續的物理空間讀寫,性能極差,在設計時會盡可能考慮數據存放的連續性,因此很少會采用 ROW 的方式。但是隨著 SSD 盤的逐漸普及,隨機讀寫的性能不再成為主要的性能關注點,越來越多的存儲系統開始采用全閃存的磁盤陣列,相信 ROW 的方式會成為更加主流的方式。
?
?
總結
BlueStore 的設計考慮了 FileStore 中存在的一些硬傷,拋棄了傳統的文件系統直接管理裸設備,縮短了 IO 路徑,同時采用 ROW 的方式,避免了日志雙寫的問題,在寫入性能上有了極大的提高。
通過分析 BlueStore 的基本結構、考慮的問題以及設計思想,我們對于 BlueStore 有了大概的了解;BlueStore 在設計時有考慮到未來存儲的應用環境,是一種比較先進的本地文件系統,但也不可避免存在一些缺陷,例如較為復雜的元數據結構和 IO 邏輯,在大量小 IO 下可能存在的 double write 問題,較大的元數據內存占用等(當然有些問題在 Ceph?的使用場景下可能不存在,但是我們如果希望借鑒 BlueStore 來設計本地文件系統就不得不考慮這些問題)。
在后續的文章中,我們將繼續深入剖析各個模塊的設計原理和流程,也會對 BlueStore 測試過程中發現的一些問題展開討論。
?
參考資料
https://ceph.com/community/new-luminous-bluestore/
Jayashree Mohan, Rohan Kadekodi, Vijay Chidambaram. Analyzing IO Amplification in Linux File Systems. arXiv:1707.08514v1 [cs.OS] 26 Jul 2017 .
謝型果等. Ceph設計原理與實現[M]. 北京:機械工業出版社,2017.12.
?
原文鏈接:知乎鏈接
總結
以上是生活随笔為你收集整理的BlueStore——先进的用户态文件系统《一》的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 九种 0-1 背包问题详解
- 下一篇: Google Spanner:谷歌的全球