云原生高性能分布式文件系統(tǒng) JuiceFS 還真有點(diǎn)意思
JuiceFS 是一款面向云原生設(shè)計的高性能分布式文件系統(tǒng),在 Apache 2.0 開源協(xié)議下發(fā)布。提供完備的 POSIX 兼容性,可將幾乎所有對象存儲接入本地作為海量本地磁盤使用,亦可同時在跨平臺、跨地區(qū)的不同主機(jī)上掛載讀寫。
簡介
JuiceFS 采用 「數(shù)據(jù)」與「元數(shù)據(jù)」分離存儲 的架構(gòu),從而實(shí)現(xiàn)文件系統(tǒng)的分布式設(shè)計。文件數(shù)據(jù)本身會被切分保存在對象存儲(例如 Amazon S3),而元數(shù)據(jù)則可以保存在 Redis、MySQL、TiKV、SQLite 等多種數(shù)據(jù)庫中,你可以根據(jù)場景與性能要求進(jìn)行選擇。
JuiceFS 提供了豐富的 API,適用于各種形式數(shù)據(jù)的管理、分析、歸檔、備份,可以在不修改代碼的前提下無縫對接大數(shù)據(jù)、機(jī)器學(xué)習(xí)、人工智能等應(yīng)用平臺,為其提供海量、彈性、低價的高性能存儲。運(yùn)維人員不用再為可用性、災(zāi)難恢復(fù)、監(jiān)控、擴(kuò)容等工作煩惱,專注于業(yè)務(wù)開發(fā),提升研發(fā)效率。同時運(yùn)維細(xì)節(jié)的簡化,對 DevOps 極其友好。
核心特性
- POSIX 兼容:像本地文件系統(tǒng)一樣使用,無縫對接已有應(yīng)用,無業(yè)務(wù)侵入性。
- HDFS 兼容:完整兼容 HDFS API,提供更強(qiáng)的元數(shù)據(jù)性能。
- S3 兼容:提供 S3 網(wǎng)關(guān) 實(shí)現(xiàn) S3 協(xié)議兼容的訪問接口。
- 云原生:通過 Kubernetes CSI 驅(qū)動 輕松地在 Kubernetes 中使用 JuiceFS。
- 分布式設(shè)計:同一文件系統(tǒng)可在上千臺服務(wù)器同時掛載,高性能并發(fā)讀寫,共享數(shù)據(jù)。
- 強(qiáng)一致性:確認(rèn)的文件修改會在所有服務(wù)器上立即可見,保證強(qiáng)一致性。
- 強(qiáng)悍性能:毫秒級延遲,近乎無限的吞吐量(取決于對象存儲規(guī)模),查看性能測試結(jié)果。
- 數(shù)據(jù)安全:支持傳輸中加密(encryption in transit)和靜態(tài)加密(encryption at rest),查看詳情。
- 文件鎖:支持 BSD 鎖(flock)和 POSIX 鎖(fcntl)。
- 數(shù)據(jù)壓縮:支持 LZ4 和 Zstandard 壓縮算法,節(jié)省存儲空間。
應(yīng)用場景
JuiceFS 為海量數(shù)據(jù)存儲設(shè)計,可以作為很多分布式文件系統(tǒng)和網(wǎng)絡(luò)文件系統(tǒng)的替代,特別是以下場景:
- 大數(shù)據(jù)分析:HDFS 兼容;與主流計算引擎(Spark、Presto、Hive 等)無縫銜接;無限擴(kuò)展的存儲空間;運(yùn)維成本幾乎為 0;性能遠(yuǎn)好于直接對接對象存儲。
- 機(jī)器學(xué)習(xí):POSIX 兼容,可以支持所有機(jī)器學(xué)習(xí)、深度學(xué)習(xí)框架;方便的文件共享還能提升團(tuán)隊管理、使用數(shù)據(jù)效率。
- Kubernetes:JuiceFS 支持 Kubernetes CSI;為容器提供解耦的文件存儲,令應(yīng)用服務(wù)可以無狀態(tài)化;方便地在容器間共享數(shù)據(jù)。
- 共享工作區(qū):可以在任意主機(jī)掛載;沒有客戶端并發(fā)讀寫限制;POSIX 兼容已有的數(shù)據(jù)流和腳本操作。
- 數(shù)據(jù)備份:在無限平滑擴(kuò)展的存儲空間備份各種數(shù)據(jù),結(jié)合共享掛載功能,可以將多主機(jī)數(shù)據(jù)匯總至一處,做統(tǒng)一備份。
數(shù)據(jù)隱私
JuiceFS 是開源軟件,你可以在 GitHub 找到完整的源代碼。在使用 JuiceFS 存儲數(shù)據(jù)時,數(shù)據(jù)會按照一定的規(guī)則被拆分成數(shù)據(jù)塊并保存在你自己定義的對象存儲或其它存儲介質(zhì)中,數(shù)據(jù)所對應(yīng)的元數(shù)據(jù)則存儲在你自己定義的數(shù)據(jù)庫中。
架構(gòu)
JuiceFS 整體上主要由三個部分組成。
架構(gòu)
- 客戶端(Client):所有文件讀寫,乃至于碎片合并、回收站文件過期刪除等后臺任務(wù),均在客戶端中發(fā)生。所以客戶端需要同時與對象存儲和元數(shù)據(jù)引擎打交道。客戶端支持眾多接入方式:
- 通過 FUSE,JuiceFS 文件系統(tǒng)能夠以 POSIX 兼容的方式掛載到服務(wù)器,將海量云端存儲直接當(dāng)做本地存儲來使用。
- 通過 Hadoop Java SDK,JuiceFS 文件系統(tǒng)能夠直接替代 HDFS,為 Hadoop 提供低成本的海量存儲。
- 通過 Kubernetes CSI 驅(qū)動,JuiceFS 文件系統(tǒng)能夠直接為 Kubernetes 提供海量存儲。
- 通過 S3 網(wǎng)關(guān),使用 S3 作為存儲層的應(yīng)用可直接接入,同時可使用 AWS CLI、s3cmd、MinIO client 等工具訪問 JuiceFS 文件系統(tǒng)。
- 通過 WebDAV 服務(wù),以 HTTP 協(xié)議,以類似 RESTful API 的方式接入 JuiceFS 并直接操作其中的文件。
- 數(shù)據(jù)存儲(Data Storage):文件將會切分上傳保存在對象存儲服務(wù),既可以使用公有云的對象存儲,也可以接入私有部署的自建對象存儲。JuiceFS 支持幾乎所有的公有云對象存儲,同時也支持 OpenStack Swift、Ceph、MinIO 等私有化的對象存儲。
- 元數(shù)據(jù)引擎(Metadata Engine):用于存儲文件元數(shù)據(jù)(metadata),包含以下內(nèi)容:
常規(guī)文件系統(tǒng)的元數(shù)據(jù):文件名、文件大小、權(quán)限信息、創(chuàng)建修改時間、目錄結(jié)構(gòu)、文件屬性、符號鏈接、文件鎖等。
JuiceFS 獨(dú)有的元數(shù)據(jù):文件的 chunk 及 slice 映射關(guān)系、客戶端 session 等。
JuiceFS 采用多引擎設(shè)計,目前已支持 Redis、TiKV、MySQL/MariaDB、PostgreSQL、SQLite 等作為元數(shù)據(jù)服務(wù)引擎,也將陸續(xù)實(shí)現(xiàn)更多元數(shù)據(jù)存儲引擎。
JuiceFS 如何存儲文件
與傳統(tǒng)文件系統(tǒng)只能使用本地磁盤存儲數(shù)據(jù)和對應(yīng)的元數(shù)據(jù)的模式不同,JuiceFS 會將數(shù)據(jù)格式化以后存儲在對象存儲,同時會將文件的元數(shù)據(jù)存儲在專門的元數(shù)據(jù)服務(wù)中,這樣的架構(gòu)讓 JuiceFS 成為一個強(qiáng)一致性的高性能分布式文件系統(tǒng)。
任何存入 JuiceFS 的文件都會被拆分成一個或多個 「Chunk」(最大 64 MiB)。而每個 Chunk 又由一個或多個 「Slice」 組成。Chunk 的存在是為了對文件做切分,優(yōu)化大文件性能,而 Slice 則是為了進(jìn)一步優(yōu)化各類文件寫操作,二者同為文件系統(tǒng)內(nèi)部的邏輯概念。Slice 的長度不固定,取決于文件寫入的方式。每個 Slice 又會被進(jìn)一步拆分成 「Block」(默認(rèn)大小上限為 4 MiB),成為最終上傳至對象存儲的最小存儲單元。
JuiceFS File
所以我們在對象存儲平臺的文件瀏覽器中找不到存入 JuiceFS 的源文件,存儲桶中只有一個 chunks 目錄和一堆數(shù)字編號的目錄和文件,這正是經(jīng)過 JuiceFS 拆分存儲的數(shù)據(jù)塊。與此同時,文件與 Chunks、Slices、Blocks 的對應(yīng)關(guān)系等元數(shù)據(jù)信息存儲在元數(shù)據(jù)引擎中。正是這樣的分離設(shè)計,讓 JuiceFS 文件系統(tǒng)得以高性能運(yùn)作。
JuiceFS Metadata
JuiceFS 的存儲設(shè)計,還有著以下技術(shù)特點(diǎn):
- 對于任意大小的文件,JuiceFS 都不進(jìn)行合并存儲,這也是為了性能考慮,避免讀放大。
- 提供強(qiáng)一致性保證,但也可以根據(jù)場景需要與緩存功能一起調(diào)優(yōu),比如通過設(shè)置出更激進(jìn)的元數(shù)據(jù)緩存,犧牲一部分一致性,換取更好的性能。。
- 支持并默認(rèn)開啟「回收站」功能,刪除文件后保留一段時間才徹底清理,最大程度避免誤刪文件導(dǎo)致事故。
安裝
JuiceFS 是采用 Go 語言開發(fā)的,所以具有良好的跨平臺能力,支持在幾乎所有主流架構(gòu)的各類操作系統(tǒng)上運(yùn)行,包括且不限于 Linux、macOS、Windows 等。
JuiceFS 客戶端只有一個二進(jìn)制文件,可以下載預(yù)編譯的版本直接解壓使用,也可以用源代碼手動編譯,也可以直接使用一鍵安裝腳本 curl -sSL https://d.juicefs.com/install | sh - 自動下載安裝最新版 JuiceFS 客戶端。
如果你在 Mac 下面使用,需要先安裝 FUSE for macOS,這是因?yàn)?macOS 默認(rèn)不支持 FUSE 接口。
? juicefs --version
juicefs version 1.0.4+2023-04-06.f1c475d
單機(jī)模式
JuiceFS 文件系統(tǒng)由「對象存儲」和「數(shù)據(jù)庫」共同驅(qū)動,除了對象存儲,還支持使用本地磁盤、WebDAV 和 HDFS 等作為底層存儲。這里我們首先使用本地磁盤和 SQLite 數(shù)據(jù)庫快速創(chuàng)建一個單機(jī)文件系統(tǒng)用以了解和體驗(yàn) JuiceFS。
當(dāng)然首先需要安裝 JuiceFS 的客戶端,然后接下來我們就可以使用 juicefs format 命令來創(chuàng)建一個 JuiceFS 文件系統(tǒng)了,該命令的格式為:
juicefs format [command options] META-URL NAME
從命令可以看出格式化文件系統(tǒng)需要提供 3 種信息:
- [command options]:設(shè)定文件系統(tǒng)的存儲介質(zhì),留空則默認(rèn)使用本地磁盤作為存儲介質(zhì),路徑為 $HOME/.juicefs/local、/var/jfs 或 C:/jfs/local。
- META-URL:用來設(shè)置元數(shù)據(jù)存儲,即數(shù)據(jù)庫相關(guān)的信息,通常是數(shù)據(jù)庫的 URL 或文件路徑。
- NAME:是文件系統(tǒng)的名稱。
比如我們這里創(chuàng)建一個名為 ydzsfs 的文件系統(tǒng),則可以使用如下所示的命令:
? juicefs format sqlite3://ydzsfs.db ydzsfs
2023/04/25 15:36:44.287211 juicefs[218656] <INFO>: Meta address: sqlite3://ydzsfs.db [interface.go:401]
2023/04/25 15:36:44.288042 juicefs[218656] <INFO>: Data use file:///home/ubuntu/.juicefs/local/ydzsfs/ [format.go:434]
2023/04/25 15:36:44.400391 juicefs[218656] <INFO>: Volume is formatted as {
"Name": "ydzsfs",
"UUID": "67a050b2-9a40-4852-882c-24c092c03b4a",
"Storage": "file",
"Bucket": "/home/ubuntu/.juicefs/local/",
"BlockSize": 4096,
"Compression": "none",
"TrashDays": 1,
"MetaVersion": 1
} [format.go:471]
從返回的信息中可以看到,該文件系統(tǒng)使用 SQLite 作為元數(shù)據(jù)存儲引擎,數(shù)據(jù)庫文件位于當(dāng)前目錄,文件名為 ydzsfs.db,保存了 ydzsfs 文件系統(tǒng)的所有信息,它構(gòu)建了完善的表結(jié)構(gòu),將用作所有數(shù)據(jù)的元信息的存儲。
SQLite
由于沒有指定任何存儲相關(guān)的選項,客戶端默認(rèn)使用本地磁盤作為存儲介質(zhì),根據(jù)返回的信息, ydzsfs 的存儲路徑為 file:///home/ubuntu/.juicefs/local/ydzsfs/,即當(dāng)前用戶主目錄下的 .juicefs/local/ydzsfs/。
? ls -la ~/.juicefs/local/ydzsfs
total 12
drwxr-xr-x 2 ubuntu ubuntu 4096 Apr 25 15:36 .
drwxr-xr-x 3 ubuntu ubuntu 4096 Apr 25 15:36 ..
-rw-r--r-- 1 ubuntu ubuntu 36 Apr 25 15:36 juicefs_uuid
這樣我們就成功創(chuàng)建了一個文件系統(tǒng)了,接下來我們就可以使用 juicefs mount 命令來掛載文件系統(tǒng)了,該命令的一般格式為:
juicefs mount [command options] META-URL MOUNTPOINT
與創(chuàng)建文件系統(tǒng)的命令類似,掛載文件系統(tǒng)需要提供以下信息:
- [command options]:用來指定文件系統(tǒng)相關(guān)的選項,例如:-d 可以實(shí)現(xiàn)后臺掛載。
- META-URL:用來設(shè)置元數(shù)據(jù)存儲,即數(shù)據(jù)庫相關(guān)的信息,通常是數(shù)據(jù)庫的 URL 或文件路徑。
- MOUNTPOINT:指定文件系統(tǒng)的掛載點(diǎn)。
由于 SQLite 是單文件數(shù)據(jù)庫,掛載時要注意數(shù)據(jù)庫文件的的路徑,JuiceFS 同時支持相對路徑和絕對路徑。比如我們這里可以使用以下命令將 ydzsfs 文件系統(tǒng)掛載到 ./jfs 文件夾:
? juicefs mount sqlite3://ydzsfs.db ./jfs
2023/04/25 15:39:52.365555 juicefs[220965] <INFO>: Meta address: sqlite3://ydzsfs.db [interface.go:401]
2023/04/25 15:39:52.366833 juicefs[220965] <INFO>: Data use file:///home/ubuntu/.juicefs/local/ydzsfs/ [mount.go:431]
2023/04/25 15:39:52.367117 juicefs[220965] <INFO>: Disk cache (/home/ubuntu/.juicefs/cache/67a050b2-9a40-4852-882c-24c092c03b4a/): capacity (102400 MB), free ratio (10%), max pending pages (15) [disk_cache.go:94]
2023/04/25 15:39:52.378120 juicefs[220965] <INFO>: Create session 1 OK with version: 1.0.4+2023-04-06.f1c475d [base.go:289]
2023/04/25 15:39:52.378749 juicefs[220965] <INFO>: Prometheus metrics listening on 127.0.0.1:9567 [mount.go:161]
2023/04/25 15:39:52.378819 juicefs[220965] <INFO>: Mounting volume ydzsfs at ./jfs ... [mount_unix.go:181]
2023/04/25 15:39:52.378851 juicefs[220965] <WARNING>: setpriority: permission denied [fuse.go:427]
2023/04/25 15:39:52.868233 juicefs[220965] <INFO>: OK, ydzsfs is ready at ./jfs [mount_unix.go:45]
默認(rèn)情況下,客戶端會在前臺掛載文件系統(tǒng),程序會一直運(yùn)行在當(dāng)前終端進(jìn)程中,使用 Ctrl + C 組合鍵或關(guān)閉終端窗口,文件系統(tǒng)會被卸載。
為了讓文件系統(tǒng)可以在后臺保持掛載,你可以在掛載時指定 -d 或 --background 選項,即讓客戶端在守護(hù)進(jìn)程中掛載文件系統(tǒng):
? juicefs mount sqlite3://ydzsfs.db ~/jfs -d
2023/04/25 15:41:15.438132 juicefs[222009] <INFO>: Meta address: sqlite3://ydzsfs.db [interface.go:401]
2023/04/25 15:41:15.439334 juicefs[222009] <INFO>: Data use file:///home/ubuntu/.juicefs/local/ydzsfs/ [mount.go:431]
2023/04/25 15:41:15.439513 juicefs[222009] <INFO>: Disk cache (/home/ubuntu/.juicefs/cache/67a050b2-9a40-4852-882c-24c092c03b4a/): capacity (102400 MB), free ratio (10%), max pending pages (15) [disk_cache.go:94]
2023/04/25 15:41:15.941069 juicefs[222009] <INFO>: OK, ydzsfs is ready at /home/ubuntu/jfs [mount_unix.go:45]
接下來,任何存入掛載點(diǎn) ~/jfs 的文件,都會按照 JuiceFS 的文件存儲格式被拆分成特定的「數(shù)據(jù)塊」并存入 $HOME/.juicefs/local/ydzsfs 目錄中,相對應(yīng)的「元數(shù)據(jù)」會全部存儲在 ydzsfs.db 數(shù)據(jù)庫中。
最后執(zhí)行以下命令可以將掛載點(diǎn) ~/jfs 卸載:
? juicefs umount ~/jfs
當(dāng)然,在你能夠確保數(shù)據(jù)安全的前提下,也可以在卸載命令中添加 --force 或 -f 參數(shù),強(qiáng)制卸載文件系統(tǒng)。
使用對象存儲
通過前面的基本介紹我們可以對 JuiceFS 的工作方式有一個基本的認(rèn)識,接下來我們?nèi)匀皇褂?SQLite 存儲元數(shù)據(jù),但是把本地存儲換成「對象存儲」,做一個更有實(shí)用價值的方案。
幾乎所有主流的云計算平臺都有提供對象存儲服務(wù),如亞馬遜 S3、阿里云 OSS 等,JuiceFS 支持幾乎所有的對象存儲服務(wù)。一般來說,創(chuàng)建對象存儲通常只需要 2 個環(huán)節(jié):
- 創(chuàng)建 Bucket 存儲桶,拿到 Endpoint 地址。
- 創(chuàng)建 Access Key ID 和 Access Key Secret,即對象存儲 API 的訪問密鑰。
以騰訊云 COS 為例,創(chuàng)建好的資源大概像下面這樣:
- Bucket Endpoint:https://myjfs-1304979731.cos.ap-shanghai.myqcloud.com。
- Access Key ID:ABCDEFGHIJKLMNopqXYZ。
- Access Key Secret:ZYXwvutsrqpoNMLkJiHgfeDCBA。
我們這里以騰訊云 COS 服務(wù)為例來進(jìn)行演示,首先創(chuàng)建一個 Bucket 存儲桶,命名為 myjfs,然后創(chuàng)建一個子賬號,命名為 juicefs,并為其創(chuàng)建一個 API 密鑰,如下圖所示:
# 使用你自己所使用的對象存儲信息替換下方相關(guān)參數(shù)
? juicefs format --storage cos \
--bucket https://myjfs-1304979731.cos.ap-nanjing.myqcloud.com \
--access-key xxxx \
--secret-key xxx \
sqlite3://myjfs.db myjfs
2023/04/25 15:56:18.198284 juicefs[233378] <INFO>: Meta address: sqlite3://myjfs.db [interface.go:401]
2023/04/25 15:56:18.198941 juicefs[233378] <INFO>: Data use cos://myjfs-1304979731/myjfs/ [format.go:434]
2023/04/25 15:56:18.740526 juicefs[233378] <INFO>: Volume is formatted as {
"Name": "myjfs",
"UUID": "720c4b39-547e-43d8-8b22-02229f443194",
"Storage": "cos",
"Bucket": "https://myjfs-1304979731.cos.ap-nanjing.myqcloud.com",
"AccessKey": "xxxx",
"SecretKey": "removed",
"BlockSize": 4096,
"Compression": "none",
"KeyEncrypted": true,
"TrashDays": 1,
"MetaVersion": 1
} [format.go:471]
在上述命令中,我們指定了對象存儲的相關(guān)配置信息:
- --storage:設(shè)置存儲類型,比如 cos、oss、s3 等。
- --bucket:設(shè)置對象存儲的 Endpoint 地址。
- --access-key:設(shè)置對象存儲 API 訪問密鑰 Access Key ID。
- --secret-key:設(shè)置對象存儲 API 訪問密鑰 Access Key Secret。
創(chuàng)建完成即可進(jìn)行掛載:
? juicefs mount sqlite3://myjfs.db ~/jfs -d
2023/04/25 16:01:40.718645 juicefs[237796] <INFO>: Meta address: sqlite3://myjfs.db [interface.go:401]
2023/04/25 16:01:40.719901 juicefs[237796] <INFO>: Data use cos://myjfs-1304979731/myjfs/ [mount.go:431]
2023/04/25 16:01:40.720136 juicefs[237796] <INFO>: Disk cache (/home/ubuntu/.juicefs/cache/720c4b39-547e-43d8-8b22-02229f443194/): capacity (102400 MB), free ratio (10%), max pending pages (15) [disk_cache.go:94]
2023/04/25 16:01:41.221218 juicefs[237796] <INFO>: OK, myjfs is ready at /home/ubuntu/jfs [mount_unix.go:45]
掛載命令與使用本地存儲時完全一樣,這是因?yàn)閯?chuàng)建文件系統(tǒng)時,對象存儲相關(guān)的信息已經(jīng)寫入了 myjfs.db 數(shù)據(jù)庫,因此客戶端不需要額外提供對象存儲認(rèn)證信息,也沒有本地配置文件。
相比使用本地磁盤,SQLite 和對象存儲的組合實(shí)用價值更高。從應(yīng)用的角度看,這種形式等同于將容量幾乎無限的對象存儲接入到了本地計算機(jī),讓你可以像使用本地磁盤那樣使用云存儲。
進(jìn)一步的,該文件系統(tǒng)的所有數(shù)據(jù)都存儲在云端的對象存儲,因此可以把 myjfs.db 數(shù)據(jù)庫復(fù)制到其他安裝了 JuiceFS 客戶端的計算機(jī)上進(jìn)行掛載和讀寫。也就是說,任何一臺計算機(jī)只要能夠讀取到存儲了元數(shù)據(jù)的數(shù)據(jù)庫,那么它就能夠掛載讀寫該文件系統(tǒng)。
比如現(xiàn)在我們在 ~/jfs 目錄下面任意創(chuàng)建一些文件:
? echo "Hello JuiceFS" > hello.txt
正常創(chuàng)建完成后該文件會按照 JuiceFS 的文件存儲格式被拆分成特定的「數(shù)據(jù)塊」并上傳到對象存儲中去,相對應(yīng)的「元數(shù)據(jù)」會全部存儲在 myjfs.db 數(shù)據(jù)庫中。
對象存儲
很顯然,SQLite 這種單文件數(shù)據(jù)庫很難實(shí)現(xiàn)被多臺計算機(jī)同時訪問。如果把 SQLite 改為 Redis、PostgreSQL、MySQL 等能夠通過網(wǎng)絡(luò)被多臺計算機(jī)同時讀寫訪問的數(shù)據(jù)庫,那么就可以實(shí)現(xiàn) JuiceFS 文件系統(tǒng)的分布式掛載讀寫。
分布式模式
前面我們通過采用「對象存儲」和「SQLite」數(shù)據(jù)庫的組合,實(shí)現(xiàn)了一個可以在任意主機(jī)上掛載的文件系統(tǒng)。得益于對象存儲可以被網(wǎng)絡(luò)上任何有權(quán)限的計算機(jī)訪問的特點(diǎn),我們只需要把 SQLite 數(shù)據(jù)庫文件復(fù)制到任何想要訪問該存儲的計算機(jī),就可以實(shí)現(xiàn)在不同計算機(jī)上訪問同一個 JuiceFS 文件系統(tǒng)。
很顯然,想要依靠在計算機(jī)之間復(fù)制 SQLite 數(shù)據(jù)庫的方式進(jìn)行文件系統(tǒng)共享,雖然可行,但文件的實(shí)時性是得不到保證的。受限于 SQLite 這種單文件數(shù)據(jù)庫無法被多個計算機(jī)同時讀寫訪問的情況,為了能夠讓一個文件系統(tǒng)可以在分布式環(huán)境中被多個計算機(jī)同時掛載讀寫,我們需要采用支持通過網(wǎng)絡(luò)訪問的數(shù)據(jù)庫,比如 Redis、PostgreSQL、MySQL 等。
接下來我們將 SQLite 數(shù)據(jù)庫替換成基于網(wǎng)絡(luò)的數(shù)據(jù)庫,從而實(shí)現(xiàn) JuiceFS 文件系統(tǒng)的分布式掛載讀寫。JuiceFS 目前支持的基于網(wǎng)絡(luò)的數(shù)據(jù)庫有:
- 鍵值數(shù)據(jù)庫:Redis、TiKV。
- 關(guān)系型數(shù)據(jù)庫:PostgreSQL、MySQL、MariaDB。
不同的數(shù)據(jù)庫性能和穩(wěn)定性表現(xiàn)也各不相同,比如 Redis 是內(nèi)存型鍵值數(shù)據(jù)庫,性能極為出色,但可靠性相對較弱。PostgreSQL 是關(guān)系型數(shù)據(jù)庫,相比之下性能沒有內(nèi)存型強(qiáng)悍,但它的可靠性要更強(qiáng)。
我們這里以 Redis 為例來演示分布式模式的使用,我們就直接在 K8s 集群中部署一個簡單的 Redis 服務(wù)來進(jìn)行說明:
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
image: redis/redis-stack-server:6.2.6-v6
imagePullPolicy: IfNotPresent
name: redis
ports:
- containerPort: 6379
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
ports:
- name: redis-port
port: 6379
targetPort: 6379
selector:
app: redis
type: NodePort
直接應(yīng)用該資源清單即可:
? kubectl apply -f redis.yaml
? kubectl get svc redis -n kube-gpt
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis NodePort 10.103.134.144 <none> 6379:32199/TCP 19d
然后接下來我們就可以利用前面的對象存儲和這里的 Redis 來創(chuàng)建一個分布式的 JuiceFS 文件系統(tǒng)了,使用如下所示命令:
? juicefs format --storage cos \
--bucket https://myjfs-1304979731.cos.ap-nanjing.myqcloud.com \
--access-key xxxx \
--secret-key xxxx \
redis://10.103.134.144:6379/1 myjfs
2023/04/25 16:21:41.847487 juicefs[252491] <INFO>: Meta address: redis://10.103.134.144:6379/1 [interface.go:401]
2023/04/25 16:21:41.849176 juicefs[252491] <WARNING>: AOF is not enabled, you may lose data if Redis is not shutdown properly. [info.go:83]
2023/04/25 16:21:41.849459 juicefs[252491] <INFO>: Ping redis: 217.108μs [redis.go:2904]
2023/04/25 16:21:41.850047 juicefs[252491] <INFO>: Data use cos://myjfs-1304979731/myjfs/ [format.go:434]
2023/04/25 16:21:42.263986 juicefs[252491] <INFO>: Volume is formatted as {
"Name": "myjfs",
"UUID": "6fb832cc-06a1-4b18-b9fc-087dbf67a105",
"Storage": "cos",
"Bucket": "https://myjfs-1304979731.cos.ap-nanjing.myqcloud.com",
"AccessKey": "xxxxxxxx",
"SecretKey": "removed",
"BlockSize": 4096,
"Compression": "none",
"KeyEncrypted": true,
"TrashDays": 1,
"MetaVersion": 1
} [format.go:471]
文件系統(tǒng)創(chuàng)建完畢以后,包含對象存儲密鑰等信息會完整的記錄到數(shù)據(jù)庫中,JuiceFS 客戶端只要擁有數(shù)據(jù)庫地址、用戶名和密碼信息,就可以掛載讀寫該文件系統(tǒng),所以 JuiceFS 客戶端不需要本地配置文件。
由于這個文件系統(tǒng)的「數(shù)據(jù)」和「元數(shù)據(jù)」都存儲在基于網(wǎng)絡(luò)的服務(wù)中,因此在任何安裝了 JuiceFS 客戶端的計算機(jī)上都可以同時掛載該文件系統(tǒng)進(jìn)行共享讀寫,例如:
? juicefs mount redis://10.103.134.144:6379/1 ~/jfs -d
2023/04/25 16:25:40.254487 juicefs[255369] <INFO>: Meta address: redis://10.103.134.144:6379/1 [interface.go:401]
2023/04/25 16:25:40.255762 juicefs[255369] <WARNING>: AOF is not enabled, you may lose data if Redis is not shutdown properly. [info.go:83]
2023/04/25 16:25:40.255971 juicefs[255369] <INFO>: Ping redis: 164.248μs [redis.go:2904]
2023/04/25 16:25:40.256553 juicefs[255369] <INFO>: Data use cos://myjfs-1304979731/myjfs/ [mount.go:431]
2023/04/25 16:25:40.256743 juicefs[255369] <INFO>: Disk cache (/home/ubuntu/.juicefs/cache/6fb832cc-06a1-4b18-b9fc-087dbf67a105/): capacity (102400 MB), free ratio (10%), max pending pages (15) [disk_cache.go:94]
2023/04/25 16:25:40.757806 juicefs[255369] <INFO>: OK, myjfs is ready at /home/ubuntu/jfs [mount_unix.go:45]
數(shù)據(jù)強(qiáng)一致性保證
對于多客戶端同時掛載讀寫同一個文件系統(tǒng)的情況,JuiceFS 提供「關(guān)閉再打開(close-to-open)」一致性保證,即當(dāng)兩個及以上客戶端同時讀寫相同的文件時,客戶端 A 的修改在客戶端 B 不一定能立即看到。但是,一旦這個文件在客戶端 A 寫入完成并關(guān)閉,之后在任何一個客戶端重新打開該文件都可以保證能訪問到最新寫入的數(shù)據(jù),不論是否在同一個節(jié)點(diǎn)。
調(diào)大緩存提升性能
由于「對象存儲」是基于網(wǎng)絡(luò)的存儲服務(wù),不可避免會產(chǎn)生訪問延時。為了解決這個問題,JuiceFS 提供并默認(rèn)啟用了緩存機(jī)制,即劃撥一部分本地存儲作為數(shù)據(jù)與對象存儲之間的一個緩沖層,讀取文件時會異步地將數(shù)據(jù)緩存到本地存儲。
緩存機(jī)制讓 JuiceFS 可以高效處理海量數(shù)據(jù)的讀寫任務(wù),默認(rèn)情況下,JuiceFS 會在 $HOME/.juicefs/cache 或 /var/jfsCache 目錄設(shè)置 100GiB 的緩存。在速度更快的 SSD 上設(shè)置更大的緩存空間可以有效提升 JuiceFS 的讀寫性能。
你可以使用 --cache-dir 調(diào)整緩存目錄的位置,使用 --cache-size 調(diào)整緩存空間的大小,例如:
juicefs mount
--background \
--cache-dir /mycache \
--cache-size 512000 \
redis://tom:mypassword@xxxx:6379/1 \
~/jfs
注意:JuiceFS 進(jìn)程需要具有讀寫 --cache-dir 目錄的權(quán)限。
上述命令將緩存目錄設(shè)置在了 /mycache 目錄,并指定緩存空間為 500GiB。
當(dāng)掛載好文件系統(tǒng)以后可以通過 juicefs bench 命令對文件系統(tǒng)進(jìn)行基礎(chǔ)的性能測試和功能驗(yàn)證,確保 JuiceFS 文件系統(tǒng)能夠正常訪問且性能符合預(yù)期。
? juicefs bench ~/jfs
Cleaning kernel cache, may ask for root privilege...
Write big blocks count: 1024 / 1024 [==============================================================] done
Read big blocks count: 1024 / 1024 [==============================================================] done
Write small blocks count: 100 / 100 [==============================================================] done
Read small blocks count: 100 / 100 [==============================================================] done
Stat small files count: 100 / 100 [==============================================================] done
Benchmark finished!
BlockSize: 1 MiB, BigFileSize: 1024 MiB, SmallFileSize: 128 KiB, SmallFileCount: 100, NumThreads: 1
Time used: 16.4 s, CPU: 50.4%, Memory: 432.8 MiB
+------------------+------------------+---------------+
| ITEM | VALUE | COST |
+------------------+------------------+---------------+
| Write big file | 266.43 MiB/s | 3.84 s/file |
| Read big file | 220.25 MiB/s | 4.65 s/file |
| Write small file | 14.6 files/s | 68.50 ms/file |
| Read small file | 1172.6 files/s | 0.85 ms/file |
| Stat file | 4252.0 files/s | 0.24 ms/file |
| FUSE operation | 17835 operations | 1.00 ms/op |
| Update meta | 326 operations | 2.98 ms/op |
| Put object | 356 operations | 214.20 ms/op |
| Get object | 256 operations | 116.36 ms/op |
| Delete object | 0 operations | 0.00 ms/op |
| Write into cache | 356 operations | 2.94 ms/op |
| Read from cache | 100 operations | 0.07 ms/op |
+------------------+------------------+---------------+
運(yùn)行 juicefs bench 命令以后會根據(jù)指定的并發(fā)度(默認(rèn)為 1)往 JuiceFS 文件系統(tǒng)中寫入及讀取 N 個大文件(默認(rèn)為 1)及 N 個小文件(默認(rèn)為 100),并統(tǒng)計讀寫的吞吐和單次操作的延遲,以及訪問元數(shù)據(jù)引擎的延遲。
測試后可以去對象存儲中查看多了很多數(shù)據(jù)了。
juicefs bench
生產(chǎn)環(huán)境部署
為了保證 JuiceFS 文件系統(tǒng)能符合生產(chǎn)環(huán)境的要求,這里我們給出了如下一些生產(chǎn)環(huán)境部署的建議。
- 監(jiān)控指標(biāo)收集與可視化
務(wù)必收集 JuiceFS 客戶端的監(jiān)控指標(biāo)并通過 Grafana 可視化。
- 元數(shù)據(jù)自動備份
元數(shù)據(jù)自動備份是自 JuiceFS v1.0.0 版本開始加入的特性
元數(shù)據(jù)對 JuiceFS 文件系統(tǒng)非常關(guān)鍵,一旦丟失或損壞將可能影響大批文件甚至整個文件系統(tǒng)。因此必須對元數(shù)據(jù)進(jìn)行定期備份。
元數(shù)據(jù)自動備份特性默認(rèn)開啟,備份間隔為 1 小時,備份的元數(shù)據(jù)會經(jīng)過壓縮后存儲至對應(yīng)的對象存儲中(與文件系統(tǒng)的數(shù)據(jù)隔離)。備份由 JuiceFS 客戶端執(zhí)行,備份期間會導(dǎo)致其 CPU 和內(nèi)存使用量上升,默認(rèn)情況下可認(rèn)為會在所有客戶端中隨機(jī)選擇一個執(zhí)行備份操作。
特別注意默認(rèn)情況下當(dāng)文件系統(tǒng)的文件數(shù)達(dá)到一百萬時,元數(shù)據(jù)自動備份功能將會關(guān)閉,需要配置一個更大的備份間隔(--backup-meta 選項)才會再次開啟。備份間隔每個客戶端獨(dú)立配置,設(shè)置 --backup-meta 0 則表示關(guān)閉元數(shù)據(jù)自動備份特性。
注意:備份元數(shù)據(jù)所需的時間取決于具體的元數(shù)據(jù)引擎,不同元數(shù)據(jù)引擎會有不同的性能表現(xiàn)。
- 回收站
回收站是自 JuiceFS v1.0.0 版本開始加入的特性
回收站默認(rèn)開啟,文件被刪除后的保留時間默認(rèn)配置為 1 天,可以有效防止數(shù)據(jù)被誤刪除時造成的數(shù)據(jù)丟失風(fēng)險。
不過回收站開啟以后也可能帶來一些副作用,如果應(yīng)用需要經(jīng)常刪除文件或者頻繁覆蓋寫文件,會導(dǎo)致對象存儲使用量遠(yuǎn)大于文件系統(tǒng)用量。這本質(zhì)上是因?yàn)?JuiceFS 客戶端會將對象存儲上被刪除的文件或者覆蓋寫時產(chǎn)生的需要垃圾回收的數(shù)據(jù)塊持續(xù)保留一段時間。因此,在部署 JuiceFS 至生產(chǎn)環(huán)境時就應(yīng)該考慮好合適的回收站配置,回收站保留時間可以通過以下方式配置(如果將 --trash-days 設(shè)置為 0 則表示關(guān)閉回收站特性):
- 新建文件系統(tǒng):通過 juicefs format 的 --trash-days <value> 選項設(shè)置。
- 已有文件系統(tǒng):通過 juicefs config 的 --trash-days <value> 選項修改。
- 客戶端后臺任務(wù)
同一個 JuiceFS 文件系統(tǒng)的所有客戶端在運(yùn)行過程中共享一個后臺任務(wù)集,每個任務(wù)定時執(zhí)行,且具體執(zhí)行的客戶端隨機(jī)選擇。具體的后臺任務(wù)包括:
- 清理待刪除的文件和對象
- 清理回收站中的過期文件和碎片
- 清理長時間未響應(yīng)的客戶端會話
- 自動備份元數(shù)據(jù)
由于這些任務(wù)執(zhí)行時會占用一定資源,因此可以為業(yè)務(wù)較繁重的客戶端配置 --no-bgjob 選項來禁止其參與后臺任務(wù)。
注意:請保證至少有一個 JuiceFS 客戶端可以執(zhí)行后臺任務(wù)
- 客戶端日志滾動
當(dāng)后臺運(yùn)行 JuiceFS 掛載點(diǎn)時,客戶端默認(rèn)會將日志輸出到本地文件中。取決于掛載文件系統(tǒng)時的運(yùn)行用戶,本地日志文件的路徑稍有區(qū)別。root 用戶對應(yīng)的日志文件路徑是 /var/log/juicefs.log,非 root 用戶的日志文件路徑是 $HOME/.juicefs/juicefs.log。
本地日志文件默認(rèn)不會滾動,生產(chǎn)環(huán)境中為了確保日志文件不占用過多磁盤空間需要手動配置。以下是一個日志滾動的示例配置:
# /etc/logrotate.d/juicefs
/var/log/juicefs.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
}
通過 logrotate -d /etc/logrotate.d/juicefs 命令可以驗(yàn)證配置文件的正確性。