JuiceFS 元數據引擎選型指南
- 2022 年 10 月 10 日
- 筆記
文件系統是我們常見的存儲形式,內部主要由數據和元數據兩部分組成。其中數據是文件的具體內容,通常會直接展現給用戶;而元數據是描述數據的數據,用來記錄文件屬性、目錄結構、數據存儲位置等。一般來說,元數據有非常鮮明的特點,即佔用空間較小,但訪問非常頻繁。
當今的分佈式文件系統中,有的(如 S3FS)會將元數據和數據統一管理,以簡化系統設計,不過這樣的弊端是某些元數據操作會讓用戶感受到明顯的卡頓,如 ls
大目錄,重命名大文件等。更多的文件系統會選擇將這兩者分開管理,並根據元數據的特點進行針對性優化。JuiceFS 採用的就是這種設計,其架構圖如下:
其中,元數據引擎需要是能夠支持事務操作的數據庫,而數據引擎一般是用對象存儲。目前為止,JuiceFS 已經支持 10 種以上元數據引擎和 30 種以上數據引擎。
用戶在使用 JuiceFS 時可以自由地選擇成熟組件來充當這兩個引擎,以應對豐富多變的企業環境和數據存儲需求。然而對於新用戶來說,當面對更多選擇時,也帶來了一個問題:在我的場景中究竟選擇哪一款數據庫作為元數據引擎比較合適?這篇文章將從產品設計角度,為大家介紹 JuiceFS 可使用的元數據引擎類型,以及他們的優劣勢。
01-JuiceFS 元數據引擎類型
JuiceFS 現在支持的元數據引擎總共有有三大類。
第一個是 Redis。Redis 是 JuiceFS 開源後最早支持的元數據引擎。首先 Redis 速度夠快,這是元數據引擎需要具備的重要能力之一;其次,Redis 受眾面廣,大部分用戶對 Redis 都有實踐經驗。JuiceFS 對兼容 Redis 協議的數據庫也都實現了支持,比如 KeyDB、Amazon MemoryDB 等。
然而,Redis 的可靠性和擴展性容易受限,在一些數據安全性要求較高或規模較大的場景中表現乏善可陳,因此我們又開發支持了另外兩類引擎。
第二個是 SQL 類。如 MySQL、MariaDB、PostgreSQL 等,它們的特點是流行度較高,且通常具有不錯的可靠性與擴展性。另外,還支持了嵌入式數據庫 SQLite。
最後一個是 TKV(Transactional Key-Value Database)類。它們的原生接口比較簡單,因此在 JuiceFS 中的定製性更好,相較於 SQL 類一般也能有更高的性能。目前這一類支持的有 TiKV、etcd 和嵌入式的 BadgerDB 等,對 FoundationDB 的支持也在緊鑼密鼓地開發中。
以上是根據 JuiceFS 在對接數據庫時的協議接口進行的分類。每個大類裏面有各種不同的數據庫,每種數據庫又有其自身的特點,以下根據這些特點對用戶常用的幾個選項進行比較。
元數據引擎比較
Redis | MySQL/PostgreSQL | TiKV | etcd | SQLite/BadgerDB | |
---|---|---|---|---|---|
性能 | 高 | 低 | 中 | 低 | 中 |
擴展性 | 低 | 中 | 高 | 低 | 低 |
可靠性 | 低 | 高 | 高 | 高 | 中 |
可用性 | 中 | 高 | 高 | 高 | 低 |
流行度 | 高 | 高 | 中 | 高 | 中 |
如上文中提到的,Redis 的最大優勢是性能高,因為它是全內存的數據庫。其他幾方面它就表現平平。
從擴展性上說,通常單機 Redis 可以支持 1 億文件左右,超過 1 億時,Redis 單進程的內存使用量會比較大,管理性能上也會有所下降。開源版 Redis 支持以集群模式來擴展其可管理的數據總量,但由於集群模式下 Redis 並不支持分佈式事務,因此作為 JuiceFS 元數據引擎時,每個 JuiceFS volume 能用的 Redis 進程還是只有一個,單 volume 的擴展性相較於單機 Redis 並沒有太大提升。
從可靠性來看,Redis 默認每秒將數據刷盤,在異常時可能導致小部分數據丟失。通過將配置 appendfsync 改為 always,可以讓 Redis 在每個寫請求後都刷盤,這樣數據可靠性能提高,但是性能卻會下降。
從可用性來說,部署 Redis 哨兵監控節點和備用節點,可以在主 Redis 節點掛掉後選擇一個備份節點來重新提供服務,一定程度上提高可用性。然而,Redis 本身並不支持分佈式的一致性協議,其備用節點採用的是異步備份,所以雖然新的節點起來了,但是中間可能會有數據差,導致新起來的數據並不是那麼的完整。
MySQL 和 PostgreSQL 的整體表現比較類似。它們都是經過大量用戶多年時間驗證過的數據庫產品,可靠性和可用性都不錯,流行度也很高。只是相較於其餘元數據引擎,它們的性能一般。
TiKV 原本是 PingCAP TiDB 的底層存儲,現在已經分離出來,成為一個獨立的 KV 數據庫組件。從我們的測試結果來看,它用來作為 JuiceFS 的元數據引擎是一個非常出色的選擇。其本身就有不弱於 MySQL 的數據可靠性和服務可用性,而且在性能與擴展性上表現更好。只是在流行度上,它和 MySQL 還有差距。從我們與用戶交流來看,如果他們已經是 TiKV 或 TiDB 的用戶,那最後通常都會偏向使用 TiKV 來做 JuiceFS 的元數據引擎。但如果他們之前對 TiKV 並不熟悉,那要再接受這樣一個新的組件就會慎重許多。
etcd 是另一個 TKV 類的數據庫。支持 etcd 的原因是因為它在容器化場景中流行度非常高,基本上 k8s 都是用 etcd 來管理它的配置。使用 etcd 作為 JuiceFS 的元數據引擎,並不是一個特別適配的場景。一方面是它的性能一般,另一方面是它有容量限制(默認 2G,最大 8G),之後就難以擴容。但是它的可靠性和可用性都非常高,而且容器化場景中也很容易部署,因此如果用戶只需要一個規模在百萬文件級別的文件系統,etcd 依然是一個不錯的選擇。
最後是 SQLite 和 BadgerDB,它們分別屬於 SQL 類和 TKV 類,但使用起來體驗卻非常類似,因為它們都是單機版的嵌入式數據庫。這類數據庫的特點是性能中等,但擴展性和可用性都比較差,因為其數據其實就存放在本地系統中。它們的優勢在於非常易用,只需要 JuiceFS 自己的二進制文件,不需要任何額外組件。用戶在某些特定場景或者進行一些簡單功能測試時,可以使用這兩個數據庫。
02- 典型引擎的性能測試結果
我們做過一些典型引擎的性能測試,並將其結果記錄在這個文檔中。其中一份從源碼接口處測試的最直接結果大致為:Redis > TiKV(3 副本)> MySQL(本地)~= etcd(3 副本),具體如下:
Redis-Always | Redis-Everysec | TiKV | MySQL | etcd | |
---|---|---|---|---|---|
mkdir | 600 | 471 (0.8) | 1614 (2.7) | 2121 (3.5) | 2203 (3.7) |
mvdir | 878 | 756 (0.9) | 1854 (2.1) | 3372 (3.8) | 3000 (3.4) |
rmdir | 785 | 673 (0.9) | 2097 (2.7) | 3065 (3.9) | 3634 (4.6) |
readdir_10 | 302 | 303 (1.0) | 1232 (4.1) | 1011 (3.3) | 2171 (7.2) |
readdir_1k | 1668 | 1838 (1.1) | 6682 (4.0) | 16824 (10.1) | 17470 (10.5) |
mknod | 584 | 498 (0.9) | 1561 (2.7) | 2117 (3.6) | 2232 (3.8) |
create | 591 | 468 (0.8) | 1565 (2.6) | 2120 (3.6) | 2206 (3.7) |
rename | 860 | 736 (0.9) | 1799 (2.1) | 3391 (3.9) | 2941 (3.4) |
unlink | 709 | 580 (0.8) | 1881 (2.7) | 3052 (4.3) | 3080 (4.3) |
lookup | 99 | 97 (1.0) | 731 (7.4) | 423 (4.3) | 1286 (13.0) |
getattr | 91 | 89 (1.0) | 371 (4.1) | 343 (3.8) | 661 (7.3) |
setattr | 501 | 357 (0.7) | 1358 (2.7) | 1258 (2.5) | 1480 (3.0) |
access | 90 | 89 (1.0) | 370 (4.1) | 348 (3.9) | 646 (7.2) |
setxattr | 404 | 270 (0.7) | 1116 (2.8) | 1152 (2.9) | 757 (1.9) |
getxattr | 91 | 89 (1.0) | 365 (4.0) | 298 (3.3) | 655 (7.2) |
removexattr | 219 | 95 (0.4) | 1554 (7.1) | 882 (4.0) | 1461 (6.7) |
listxattr_1 | 88 | 88 (1.0) | 374 (4.2) | 312 (3.5) | 658 (7.5) |
listxattr_10 | 94 | 91 (1.0) | 390 (4.1) | 397 (4.2) | 694 (7.4) |
link | 605 | 461 (0.8) | 1627 (2.7) | 2436 (4.0) | 2237 (3.7) |
symlink | 602 | 465 (0.8) | 1633 (2.7) | 2394 (4.0) | 2244 (3.7) |
write | 613 | 371 (0.6) | 1905 (3.1) | 2565 (4.2) | 2350 (3.8) |
read_1 | 0 | 0 (0.0) | 0 (0.0) | 0 (0.0) | 0 (0.0) |
read_10 | 0 | 0 (0.0) | 0 (0.0) | 0 (0.0) | 0 (0.0) |
- 上表中記錄的是每一個操作的耗時,數值越小越好;括號內數字是該指標對比 Redis-always 的倍數,數值也是越小越好
- Always 和 Everysec 是 Redis 配置項 appendfsync 的可選值,分別表示每個請求都刷盤和每秒刷一次盤
- 可以看到,Redis 在使用 everysec 的時候,性能更好,但與 always 相差的並不大;這是因為測試用的 AWS 機器上的本地 SSD 盤本身 IOPS 性能就比較高
- TiKV 和 etcd 都使用了三副本,而 MySQL 是單機部署的。即使這樣,TiKV 的性能表現還是高於 MySQL,而 etcd 與 MySQL 接近。
值得一提的是,上文中的測試使用的都是默認配置,並沒有對各個元數據引擎去做特定的調優。用戶在使用時可以根據自己的需求和實踐經驗進行配置調整,可能會有不一樣的結果。
另一份測試是通過 JuiceFS 自帶的 bench 工具跑的,其運行的是操作系統讀寫文件的接口,具體結果如下:
Redis-Always | Redis-Everysec | TiKV | MySQL | etcd | |
---|---|---|---|---|---|
Write big file | 565.07 MiB/s | 556.92 MiB/s | 553.58 MiB/s | 557.93 MiB/s | 542.93 MiB/s |
Read big file | 664.82 MiB/s | 652.18 MiB/s | 679.07 MiB/s | 673.55 MiB/s | 672.91 MiB/s |
Write small file | 102.30 files/s | 105.80 files/s | 95.00 files/s | 87.20 files/s | 95.75 files/s |
Read small file | 2200.30 files/s | 1894.45 files/s | 1394.90 files/s | 1360.85 files/s | 1017.30 files/s |
Stat file | 11607.40 files/s | 15032.90 files/s | 3283.20 files/s | 5470.05 files/s | 2827.80 files/s |
FUSE operation | 0.41 ms/op | 0.42 ms/op | 0.45 ms/op | 0.46 ms/op | 0.42 ms/op |
Update meta | 3.63 ms/op | 3.19 ms/op | 7.04 ms/op | 8.91 ms/op | 4.46 ms/op |
從上表可以看到,讀寫大文件時使用不同的元數據引擎最後性能是差不多的。這是因為此時性能瓶頸主要在對象存儲的數據讀寫上,元數據引擎之間雖然時延有點差異,但是放到整個業務讀寫的消耗上,這點差異幾乎可以忽略不計。當然,如果對象存儲變得非常快(比如都用本地全閃部署),那麼元數據引擎的性能差異可能又會體現出來。另外,對於一些純元數據操作(比如 ls,創建空文件等),不同元數據引擎的性能差別也會表現的比較明顯。
03-引擎選型的考慮要素
根據上文介紹的各引擎特點,用戶可以根據自己的情況去選擇合適的引擎。以下簡單分享下我們在做推薦時會建議用戶考慮的幾個要素。
評估需求:比如想使用 Redis,需要先評估能否接受少量的數據丟失,短期的服務中斷等。如果是存儲一些臨時數據或者中間數據的場景,那麼用 Redis 確實是不錯的選擇,因為它性能夠好,即使有少量的數據丟失,也不會造成很大的影響。但如果是要存儲一些關鍵數據, Redis 就不適用了。另外還得評估預期數據的規模,如果在 1 億文件左右, Redis 可以承受;如果預期會有 10 億文件,那麼顯然單機 Redis 是難以承載的。
評估硬件:比如能否連通外網,是使用託管的雲服務,還是在自己機房內私有部署。如果是私有部署,需要評估是否有足夠的硬件資源去部署一些相關的組件。無論是用哪一種元數據引擎,基本上都要求有高速的 SSD 盤去運行,不然會對其性能有比較大的影響。
評估運維能力,這是很多人會忽視的,但是在我們來看這應該是最關鍵的因素之一。對於存儲系統來說,穩定性往往才是其上生產後的第一重點。用戶在選擇元數據引擎的時候,應該先想想自己對它是不是熟悉,在出現問題時,能否快速定位解決;團隊內是否有足夠的經驗或精力去把控好這個組件。通常來說,我們會建議用戶在開始時選擇一個自己熟悉的數據庫是比較合適的。如果運維人員不足,那麼選擇 JuiceFS 公有雲服務也確實是個省心的選項。
最後,分享下社區在使用元數據引擎方面的一些統計數據。
- 目前為止, Redis 的使用者依然佔了一半以上,其次是 TiKV 和 MySQL,這兩類的使用者的數量佔比在逐步增長。
- 在運行的 Redis 集群的最大文件數大概是在 1.5 億,而且運行情況是比較穩定的,上文提到的推薦的 1 億文件是建議值,並不是說無法超過 1 億。
- 整體數量規模 Top3,都是使用的 TiKV 而且都超過了 10 億文件數量。現在最大的文件系統的文件數量是超了 70 億文件,總容量超過了 15 PiB,這也從側面證明了 TiKV 在作為元數據引擎時的擴展能力。我們自己內部測過使用 TiKV 作為元數據引擎存儲 100 億文件,系統仍能穩定地運行。所以如果你的整個集群預期的規模會非常大,那麼TiKV 確實是一個很好的選擇。
04- 元數引擎遷移
文章的最後,為大家介紹元數據引擎遷移。 隨着用戶業務的發展,企業對元數據引擎的需求會發生變化,當用戶發現現有的元數據引擎不合適了,可以考慮將元數據遷移到另一個引擎中。 我們為用戶提供了完整的遷移方法,具體可以參考這個文檔。
這個遷移方法有一定的限制,首先只能遷移到空數據庫,暫時無法將兩個文件系統直接合在一起;其次,需要停寫,因為數據量會比較大的情況下,很難在線將元數據完整的遷移過來。要做到這點需要加許多限制,從實測來看速度會非常慢。因此,把整個文件系統停掉再去做遷移是最穩妥的。如果說實在需要有一定的服務提供,可以保留只讀掛載,用戶讀數據並不會影響整個元數據引擎遷移的動作。
雖然社區提供了全套的遷移方法,但是還是需要提醒用戶,盡量提前對數據量的增長做好規劃,盡量不做遷移或儘早遷移。當要遷移的數據規模很大時,耗時也會變長,期間出問題的概率也會變大。
如有幫助的話歡迎關注我們項目 Juicedata/JuiceFS 喲! (0ᴗ0✿)