云原生高性能分布式文件系統(tǒng) JuiceFS 還真有點(diǎn)意思
JuiceFS 是一款面向云原生設(shè)計(jì)的高性能分布式文件系統(tǒng),在 Apache 2.0 開源協(xié)議下發(fā)布。提供完備的 POSIX 兼容性,可將幾乎所有對(duì)象存儲(chǔ)接入本地作為海量本地磁盤使用,亦可同時(shí)在跨平臺(tái)、跨地區(qū)的不同主機(jī)上掛載讀寫。
簡介
JuiceFS 采用 「數(shù)據(jù)」與「元數(shù)據(jù)」分離存儲(chǔ) 的架構(gòu),從而實(shí)現(xiàn)文件系統(tǒng)的分布式設(shè)計(jì)。文件數(shù)據(jù)本身會(huì)被切分保存在對(duì)象存儲(chǔ)(例如 Amazon S3),而元數(shù)據(jù)則可以保存在 Redis、MySQL、TiKV、SQLite 等多種數(shù)據(jù)庫中,你可以根據(jù)場景與性能要求進(jìn)行選擇。
JuiceFS 提供了豐富的 API,適用于各種形式數(shù)據(jù)的管理、分析、歸檔、備份,可以在不修改代碼的前提下無縫對(duì)接大數(shù)據(jù)、機(jī)器學(xué)習(xí)、人工智能等應(yīng)用平臺(tái),為其提供海量、彈性、低價(jià)的高性能存儲(chǔ)。運(yùn)維人員不用再為可用性、災(zāi)難恢復(fù)、監(jiān)控、擴(kuò)容等工作煩惱,專注于業(yè)務(wù)開發(fā),提升研發(fā)效率。同時(shí)運(yùn)維細(xì)節(jié)的簡化,對(duì) DevOps 極其友好。
核心特性
- POSIX 兼容:像本地文件系統(tǒng)一樣使用,無縫對(duì)接已有應(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ū)動(dòng) 輕松地在 Kubernetes 中使用 JuiceFS。
- 分布式設(shè)計(jì):同一文件系統(tǒng)可在上千臺(tái)服務(wù)器同時(shí)掛載,高性能并發(fā)讀寫,共享數(shù)據(jù)。
- 強(qiáng)一致性:確認(rèn)的文件修改會(huì)在所有服務(wù)器上立即可見,保證強(qiáng)一致性。
- 強(qiáng)悍性能:毫秒級(jí)延遲,近乎無限的吞吐量(取決于對(duì)象存儲(chǔ)規(guī)模),查看性能測試結(jié)果。
- 數(shù)據(jù)安全:支持傳輸中加密(encryption in transit)和靜態(tài)加密(encryption at rest),查看詳情。
- 文件鎖:支持 BSD 鎖(flock)和 POSIX 鎖(fcntl)。
- 數(shù)據(jù)壓縮:支持 LZ4 和 Zstandard 壓縮算法,節(jié)省存儲(chǔ)空間。
應(yīng)用場景
JuiceFS 為海量數(shù)據(jù)存儲(chǔ)設(shè)計(jì),可以作為很多分布式文件系統(tǒng)和網(wǎng)絡(luò)文件系統(tǒng)的替代,特別是以下場景:
- 大數(shù)據(jù)分析:HDFS 兼容;與主流計(jì)算引擎(Spark、Presto、Hive 等)無縫銜接;無限擴(kuò)展的存儲(chǔ)空間;運(yùn)維成本幾乎為 0;性能遠(yuǎn)好于直接對(duì)接對(duì)象存儲(chǔ)。
- 機(jī)器學(xué)習(xí):POSIX 兼容,可以支持所有機(jī)器學(xué)習(xí)、深度學(xué)習(xí)框架;方便的文件共享還能提升團(tuán)隊(duì)管理、使用數(shù)據(jù)效率。
- Kubernetes:JuiceFS 支持 Kubernetes CSI;為容器提供解耦的文件存儲(chǔ),令應(yīng)用服務(wù)可以無狀態(tài)化;方便地在容器間共享數(shù)據(jù)。
- 共享工作區(qū):可以在任意主機(jī)掛載;沒有客戶端并發(fā)讀寫限制;POSIX 兼容已有的數(shù)據(jù)流和腳本操作。
- 數(shù)據(jù)備份:在無限平滑擴(kuò)展的存儲(chǔ)空間備份各種數(shù)據(jù),結(jié)合共享掛載功能,可以將多主機(jī)數(shù)據(jù)匯總至一處,做統(tǒng)一備份。
數(shù)據(jù)隱私
JuiceFS 是開源軟件,你可以在 GitHub 找到完整的源代碼。在使用 JuiceFS 存儲(chǔ)數(shù)據(jù)時(shí),數(shù)據(jù)會(huì)按照一定的規(guī)則被拆分成數(shù)據(jù)塊并保存在你自己定義的對(duì)象存儲(chǔ)或其它存儲(chǔ)介質(zhì)中,數(shù)據(jù)所對(duì)應(yīng)的元數(shù)據(jù)則存儲(chǔ)在你自己定義的數(shù)據(jù)庫中。
架構(gòu)
JuiceFS 整體上主要由三個(gè)部分組成。
架構(gòu)
- 客戶端(Client):所有文件讀寫,乃至于碎片合并、回收站文件過期刪除等后臺(tái)任務(wù),均在客戶端中發(fā)生。所以客戶端需要同時(shí)與對(duì)象存儲(chǔ)和元數(shù)據(jù)引擎打交道??蛻舳酥С直姸嘟尤敕绞剑?/li>
- 通過 FUSE,JuiceFS 文件系統(tǒng)能夠以 POSIX 兼容的方式掛載到服務(wù)器,將海量云端存儲(chǔ)直接當(dāng)做本地存儲(chǔ)來使用。
- 通過 Hadoop Java SDK,JuiceFS 文件系統(tǒng)能夠直接替代 HDFS,為 Hadoop 提供低成本的海量存儲(chǔ)。
- 通過 Kubernetes CSI 驅(qū)動(dòng),JuiceFS 文件系統(tǒng)能夠直接為 Kubernetes 提供海量存儲(chǔ)。
- 通過 S3 網(wǎng)關(guān),使用 S3 作為存儲(chǔ)層的應(yīng)用可直接接入,同時(shí)可使用 AWS CLI、s3cmd、MinIO client 等工具訪問 JuiceFS 文件系統(tǒng)。
- 通過 WebDAV 服務(wù),以 HTTP 協(xié)議,以類似 RESTful API 的方式接入 JuiceFS 并直接操作其中的文件。
- 數(shù)據(jù)存儲(chǔ)(Data Storage):文件將會(huì)切分上傳保存在對(duì)象存儲(chǔ)服務(wù),既可以使用公有云的對(duì)象存儲(chǔ),也可以接入私有部署的自建對(duì)象存儲(chǔ)。JuiceFS 支持幾乎所有的公有云對(duì)象存儲(chǔ),同時(shí)也支持 OpenStack Swift、Ceph、MinIO 等私有化的對(duì)象存儲(chǔ)。
- 元數(shù)據(jù)引擎(Metadata Engine):用于存儲(chǔ)文件元數(shù)據(jù)(metadata),包含以下內(nèi)容:
常規(guī)文件系統(tǒng)的元數(shù)據(jù):文件名、文件大小、權(quán)限信息、創(chuàng)建修改時(shí)間、目錄結(jié)構(gòu)、文件屬性、符號(hào)鏈接、文件鎖等。
JuiceFS 獨(dú)有的元數(shù)據(jù):文件的 chunk 及 slice 映射關(guān)系、客戶端 session 等。
JuiceFS 采用多引擎設(shè)計(jì),目前已支持 Redis、TiKV、MySQL/MariaDB、PostgreSQL、SQLite 等作為元數(shù)據(jù)服務(wù)引擎,也將陸續(xù)實(shí)現(xiàn)更多元數(shù)據(jù)存儲(chǔ)引擎。
JuiceFS 如何存儲(chǔ)文件
與傳統(tǒng)文件系統(tǒng)只能使用本地磁盤存儲(chǔ)數(shù)據(jù)和對(duì)應(yīng)的元數(shù)據(jù)的模式不同,JuiceFS 會(huì)將數(shù)據(jù)格式化以后存儲(chǔ)在對(duì)象存儲(chǔ),同時(shí)會(huì)將文件的元數(shù)據(jù)存儲(chǔ)在專門的元數(shù)據(jù)服務(wù)中,這樣的架構(gòu)讓 JuiceFS 成為一個(gè)強(qiáng)一致性的高性能分布式文件系統(tǒng)。
任何存入 JuiceFS 的文件都會(huì)被拆分成一個(gè)或多個(gè) 「Chunk」(最大 64 MiB)。而每個(gè) Chunk 又由一個(gè)或多個(gè) 「Slice」 組成。Chunk 的存在是為了對(duì)文件做切分,優(yōu)化大文件性能,而 Slice 則是為了進(jìn)一步優(yōu)化各類文件寫操作,二者同為文件系統(tǒng)內(nèi)部的邏輯概念。Slice 的長度不固定,取決于文件寫入的方式。每個(gè) Slice 又會(huì)被進(jìn)一步拆分成 「Block」(默認(rèn)大小上限為 4 MiB),成為最終上傳至對(duì)象存儲(chǔ)的最小存儲(chǔ)單元。
JuiceFS File
所以我們在對(duì)象存儲(chǔ)平臺(tái)的文件瀏覽器中找不到存入 JuiceFS 的源文件,存儲(chǔ)桶中只有一個(gè) chunks 目錄和一堆數(shù)字編號(hào)的目錄和文件,這正是經(jīng)過 JuiceFS 拆分存儲(chǔ)的數(shù)據(jù)塊。與此同時(shí),文件與 Chunks、Slices、Blocks 的對(duì)應(yīng)關(guān)系等元數(shù)據(jù)信息存儲(chǔ)在元數(shù)據(jù)引擎中。正是這樣的分離設(shè)計(jì),讓 JuiceFS 文件系統(tǒng)得以高性能運(yùn)作。
JuiceFS Metadata
JuiceFS 的存儲(chǔ)設(shè)計(jì),還有著以下技術(shù)特點(diǎn):
- 對(duì)于任意大小的文件,JuiceFS 都不進(jìn)行合并存儲(chǔ),這也是為了性能考慮,避免讀放大。
- 提供強(qiáng)一致性保證,但也可以根據(jù)場景需要與緩存功能一起調(diào)優(yōu),比如通過設(shè)置出更激進(jìn)的元數(shù)據(jù)緩存,犧牲一部分一致性,換取更好的性能。。
- 支持并默認(rèn)開啟「回收站」功能,刪除文件后保留一段時(shí)間才徹底清理,最大程度避免誤刪文件導(dǎo)致事故。
安裝
JuiceFS 是采用 Go 語言開發(fā)的,所以具有良好的跨平臺(tái)能力,支持在幾乎所有主流架構(gòu)的各類操作系統(tǒng)上運(yùn)行,包括且不限于 Linux、macOS、Windows 等。
JuiceFS 客戶端只有一個(gè)二進(jìn)制文件,可以下載預(yù)編譯的版本直接解壓使用,也可以用源代碼手動(dòng)編譯,也可以直接使用一鍵安裝腳本 curl -sSL https://d.juicefs.com/install | sh - 自動(dòng)下載安裝最新版 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)由「對(duì)象存儲(chǔ)」和「數(shù)據(jù)庫」共同驅(qū)動(dòng),除了對(duì)象存儲(chǔ),還支持使用本地磁盤、WebDAV 和 HDFS 等作為底層存儲(chǔ)。這里我們首先使用本地磁盤和 SQLite 數(shù)據(jù)庫快速創(chuàng)建一個(gè)單機(jī)文件系統(tǒng)用以了解和體驗(yàn) JuiceFS。
當(dāng)然首先需要安裝 JuiceFS 的客戶端,然后接下來我們就可以使用 juicefs format 命令來創(chuàng)建一個(gè) JuiceFS 文件系統(tǒng)了,該命令的格式為:
juicefs format [command options] META-URL NAME
從命令可以看出格式化文件系統(tǒng)需要提供 3 種信息:
- [command options]:設(shè)定文件系統(tǒng)的存儲(chǔ)介質(zhì),留空則默認(rèn)使用本地磁盤作為存儲(chǔ)介質(zhì),路徑為 $HOME/.juicefs/local、/var/jfs 或 C:/jfs/local。
- META-URL:用來設(shè)置元數(shù)據(jù)存儲(chǔ),即數(shù)據(jù)庫相關(guān)的信息,通常是數(shù)據(jù)庫的 URL 或文件路徑。
- NAME:是文件系統(tǒng)的名稱。
比如我們這里創(chuàng)建一個(gè)名為 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ù)存儲(chǔ)引擎,數(shù)據(jù)庫文件位于當(dāng)前目錄,文件名為 ydzsfs.db,保存了 ydzsfs 文件系統(tǒng)的所有信息,它構(gòu)建了完善的表結(jié)構(gòu),將用作所有數(shù)據(jù)的元信息的存儲(chǔ)。
SQLite
由于沒有指定任何存儲(chǔ)相關(guān)的選項(xiàng),客戶端默認(rèn)使用本地磁盤作為存儲(chǔ)介質(zhì),根據(jù)返回的信息, ydzsfs 的存儲(chǔ)路徑為 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)建了一個(gè)文件系統(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)的選項(xiàng),例如:-d 可以實(shí)現(xiàn)后臺(tái)掛載。
- META-URL:用來設(shè)置元數(shù)據(jù)存儲(chǔ),即數(shù)據(jù)庫相關(guān)的信息,通常是數(shù)據(jù)庫的 URL 或文件路徑。
- MOUNTPOINT:指定文件系統(tǒng)的掛載點(diǎn)。
由于 SQLite 是單文件數(shù)據(jù)庫,掛載時(shí)要注意數(shù)據(jù)庫文件的的路徑,JuiceFS 同時(shí)支持相對(duì)路徑和絕對(duì)路徑。比如我們這里可以使用以下命令將 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)情況下,客戶端會(huì)在前臺(tái)掛載文件系統(tǒng),程序會(huì)一直運(yùn)行在當(dāng)前終端進(jìn)程中,使用 Ctrl + C 組合鍵或關(guān)閉終端窗口,文件系統(tǒng)會(huì)被卸載。
為了讓文件系統(tǒng)可以在后臺(tái)保持掛載,你可以在掛載時(shí)指定 -d 或 --background 選項(xiàng),即讓客戶端在守護(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 的文件,都會(huì)按照 JuiceFS 的文件存儲(chǔ)格式被拆分成特定的「數(shù)據(jù)塊」并存入 $HOME/.juicefs/local/ydzsfs 目錄中,相對(duì)應(yīng)的「元數(shù)據(jù)」會(huì)全部存儲(chǔ)在 ydzsfs.db 數(shù)據(jù)庫中。
最后執(zhí)行以下命令可以將掛載點(diǎn) ~/jfs 卸載:
? juicefs umount ~/jfs
當(dāng)然,在你能夠確保數(shù)據(jù)安全的前提下,也可以在卸載命令中添加 --force 或 -f 參數(shù),強(qiáng)制卸載文件系統(tǒng)。
使用對(duì)象存儲(chǔ)
通過前面的基本介紹我們可以對(duì) JuiceFS 的工作方式有一個(gè)基本的認(rèn)識(shí),接下來我們?nèi)匀皇褂?SQLite 存儲(chǔ)元數(shù)據(jù),但是把本地存儲(chǔ)換成「對(duì)象存儲(chǔ)」,做一個(gè)更有實(shí)用價(jià)值的方案。
幾乎所有主流的云計(jì)算平臺(tái)都有提供對(duì)象存儲(chǔ)服務(wù),如亞馬遜 S3、阿里云 OSS 等,JuiceFS 支持幾乎所有的對(duì)象存儲(chǔ)服務(wù)。一般來說,創(chuàng)建對(duì)象存儲(chǔ)通常只需要 2 個(gè)環(huán)節(jié):
- 創(chuàng)建 Bucket 存儲(chǔ)桶,拿到 Endpoint 地址。
- 創(chuàng)建 Access Key ID 和 Access Key Secret,即對(duì)象存儲(chǔ) 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)建一個(gè) Bucket 存儲(chǔ)桶,命名為 myjfs,然后創(chuàng)建一個(gè)子賬號(hào),命名為 juicefs,并為其創(chuàng)建一個(gè) API 密鑰,如下圖所示:
# 使用你自己所使用的對(duì)象存儲(chǔ)信息替換下方相關(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]
在上述命令中,我們指定了對(duì)象存儲(chǔ)的相關(guān)配置信息:
- --storage:設(shè)置存儲(chǔ)類型,比如 cos、oss、s3 等。
- --bucket:設(shè)置對(duì)象存儲(chǔ)的 Endpoint 地址。
- --access-key:設(shè)置對(duì)象存儲(chǔ) API 訪問密鑰 Access Key ID。
- --secret-key:設(shè)置對(duì)象存儲(chǔ) 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]
掛載命令與使用本地存儲(chǔ)時(shí)完全一樣,這是因?yàn)閯?chuàng)建文件系統(tǒng)時(shí),對(duì)象存儲(chǔ)相關(guān)的信息已經(jīng)寫入了 myjfs.db 數(shù)據(jù)庫,因此客戶端不需要額外提供對(duì)象存儲(chǔ)認(rèn)證信息,也沒有本地配置文件。
相比使用本地磁盤,SQLite 和對(duì)象存儲(chǔ)的組合實(shí)用價(jià)值更高。從應(yīng)用的角度看,這種形式等同于將容量幾乎無限的對(duì)象存儲(chǔ)接入到了本地計(jì)算機(jī),讓你可以像使用本地磁盤那樣使用云存儲(chǔ)。
進(jìn)一步的,該文件系統(tǒng)的所有數(shù)據(jù)都存儲(chǔ)在云端的對(duì)象存儲(chǔ),因此可以把 myjfs.db 數(shù)據(jù)庫復(fù)制到其他安裝了 JuiceFS 客戶端的計(jì)算機(jī)上進(jìn)行掛載和讀寫。也就是說,任何一臺(tái)計(jì)算機(jī)只要能夠讀取到存儲(chǔ)了元數(shù)據(jù)的數(shù)據(jù)庫,那么它就能夠掛載讀寫該文件系統(tǒng)。
比如現(xiàn)在我們在 ~/jfs 目錄下面任意創(chuàng)建一些文件:
? echo "Hello JuiceFS" > hello.txt
正常創(chuàng)建完成后該文件會(huì)按照 JuiceFS 的文件存儲(chǔ)格式被拆分成特定的「數(shù)據(jù)塊」并上傳到對(duì)象存儲(chǔ)中去,相對(duì)應(yīng)的「元數(shù)據(jù)」會(huì)全部存儲(chǔ)在 myjfs.db 數(shù)據(jù)庫中。
對(duì)象存儲(chǔ)
很顯然,SQLite 這種單文件數(shù)據(jù)庫很難實(shí)現(xiàn)被多臺(tái)計(jì)算機(jī)同時(shí)訪問。如果把 SQLite 改為 Redis、PostgreSQL、MySQL 等能夠通過網(wǎng)絡(luò)被多臺(tái)計(jì)算機(jī)同時(shí)讀寫訪問的數(shù)據(jù)庫,那么就可以實(shí)現(xiàn) JuiceFS 文件系統(tǒng)的分布式掛載讀寫。
分布式模式
前面我們通過采用「對(duì)象存儲(chǔ)」和「SQLite」數(shù)據(jù)庫的組合,實(shí)現(xiàn)了一個(gè)可以在任意主機(jī)上掛載的文件系統(tǒng)。得益于對(duì)象存儲(chǔ)可以被網(wǎng)絡(luò)上任何有權(quán)限的計(jì)算機(jī)訪問的特點(diǎn),我們只需要把 SQLite 數(shù)據(jù)庫文件復(fù)制到任何想要訪問該存儲(chǔ)的計(jì)算機(jī),就可以實(shí)現(xiàn)在不同計(jì)算機(jī)上訪問同一個(gè) JuiceFS 文件系統(tǒng)。
很顯然,想要依靠在計(jì)算機(jī)之間復(fù)制 SQLite 數(shù)據(jù)庫的方式進(jìn)行文件系統(tǒng)共享,雖然可行,但文件的實(shí)時(shí)性是得不到保證的。受限于 SQLite 這種單文件數(shù)據(jù)庫無法被多個(gè)計(jì)算機(jī)同時(shí)讀寫訪問的情況,為了能夠讓一個(gè)文件系統(tǒng)可以在分布式環(huán)境中被多個(gè)計(jì)算機(jī)同時(shí)掛載讀寫,我們需要采用支持通過網(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ù)庫,性能極為出色,但可靠性相對(duì)較弱。PostgreSQL 是關(guān)系型數(shù)據(jù)庫,相比之下性能沒有內(nèi)存型強(qiáng)悍,但它的可靠性要更強(qiáng)。
我們這里以 Redis 為例來演示分布式模式的使用,我們就直接在 K8s 集群中部署一個(gè)簡單的 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
然后接下來我們就可以利用前面的對(duì)象存儲(chǔ)和這里的 Redis 來創(chuàng)建一個(gè)分布式的 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)建完畢以后,包含對(duì)象存儲(chǔ)密鑰等信息會(huì)完整的記錄到數(shù)據(jù)庫中,JuiceFS 客戶端只要擁有數(shù)據(jù)庫地址、用戶名和密碼信息,就可以掛載讀寫該文件系統(tǒng),所以 JuiceFS 客戶端不需要本地配置文件。
由于這個(gè)文件系統(tǒng)的「數(shù)據(jù)」和「元數(shù)據(jù)」都存儲(chǔ)在基于網(wǎng)絡(luò)的服務(wù)中,因此在任何安裝了 JuiceFS 客戶端的計(jì)算機(jī)上都可以同時(shí)掛載該文件系統(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)一致性保證
對(duì)于多客戶端同時(shí)掛載讀寫同一個(gè)文件系統(tǒng)的情況,JuiceFS 提供「關(guān)閉再打開(close-to-open)」一致性保證,即當(dāng)兩個(gè)及以上客戶端同時(shí)讀寫相同的文件時(shí),客戶端 A 的修改在客戶端 B 不一定能立即看到。但是,一旦這個(gè)文件在客戶端 A 寫入完成并關(guān)閉,之后在任何一個(gè)客戶端重新打開該文件都可以保證能訪問到最新寫入的數(shù)據(jù),不論是否在同一個(gè)節(jié)點(diǎn)。
調(diào)大緩存提升性能
由于「對(duì)象存儲(chǔ)」是基于網(wǎng)絡(luò)的存儲(chǔ)服務(wù),不可避免會(huì)產(chǎn)生訪問延時(shí)。為了解決這個(gè)問題,JuiceFS 提供并默認(rèn)啟用了緩存機(jī)制,即劃撥一部分本地存儲(chǔ)作為數(shù)據(jù)與對(duì)象存儲(chǔ)之間的一個(gè)緩沖層,讀取文件時(shí)會(huì)異步地將數(shù)據(jù)緩存到本地存儲(chǔ)。
緩存機(jī)制讓 JuiceFS 可以高效處理海量數(shù)據(jù)的讀寫任務(wù),默認(rèn)情況下,JuiceFS 會(huì)在 $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 命令對(duì)文件系統(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 命令以后會(huì)根據(jù)指定的并發(fā)度(默認(rèn)為 1)往 JuiceFS 文件系統(tǒng)中寫入及讀取 N 個(gè)大文件(默認(rèn)為 1)及 N 個(gè)小文件(默認(rèn)為 100),并統(tǒng)計(jì)讀寫的吞吐和單次操作的延遲,以及訪問元數(shù)據(jù)引擎的延遲。
測試后可以去對(duì)象存儲(chǔ)中查看多了很多數(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ù)自動(dòng)備份
元數(shù)據(jù)自動(dòng)備份是自 JuiceFS v1.0.0 版本開始加入的特性
元數(shù)據(jù)對(duì) JuiceFS 文件系統(tǒng)非常關(guān)鍵,一旦丟失或損壞將可能影響大批文件甚至整個(gè)文件系統(tǒng)。因此必須對(duì)元數(shù)據(jù)進(jìn)行定期備份。
元數(shù)據(jù)自動(dòng)備份特性默認(rèn)開啟,備份間隔為 1 小時(shí),備份的元數(shù)據(jù)會(huì)經(jīng)過壓縮后存儲(chǔ)至對(duì)應(yīng)的對(duì)象存儲(chǔ)中(與文件系統(tǒng)的數(shù)據(jù)隔離)。備份由 JuiceFS 客戶端執(zhí)行,備份期間會(huì)導(dǎo)致其 CPU 和內(nèi)存使用量上升,默認(rèn)情況下可認(rèn)為會(huì)在所有客戶端中隨機(jī)選擇一個(gè)執(zhí)行備份操作。
特別注意默認(rèn)情況下當(dāng)文件系統(tǒng)的文件數(shù)達(dá)到一百萬時(shí),元數(shù)據(jù)自動(dòng)備份功能將會(huì)關(guān)閉,需要配置一個(gè)更大的備份間隔(--backup-meta 選項(xiàng))才會(huì)再次開啟。備份間隔每個(gè)客戶端獨(dú)立配置,設(shè)置 --backup-meta 0 則表示關(guān)閉元數(shù)據(jù)自動(dòng)備份特性。
注意:備份元數(shù)據(jù)所需的時(shí)間取決于具體的元數(shù)據(jù)引擎,不同元數(shù)據(jù)引擎會(huì)有不同的性能表現(xiàn)。
- 回收站
回收站是自 JuiceFS v1.0.0 版本開始加入的特性
回收站默認(rèn)開啟,文件被刪除后的保留時(shí)間默認(rèn)配置為 1 天,可以有效防止數(shù)據(jù)被誤刪除時(shí)造成的數(shù)據(jù)丟失風(fēng)險(xiǎn)。
不過回收站開啟以后也可能帶來一些副作用,如果應(yīng)用需要經(jīng)常刪除文件或者頻繁覆蓋寫文件,會(huì)導(dǎo)致對(duì)象存儲(chǔ)使用量遠(yuǎn)大于文件系統(tǒng)用量。這本質(zhì)上是因?yàn)?JuiceFS 客戶端會(huì)將對(duì)象存儲(chǔ)上被刪除的文件或者覆蓋寫時(shí)產(chǎn)生的需要垃圾回收的數(shù)據(jù)塊持續(xù)保留一段時(shí)間。因此,在部署 JuiceFS 至生產(chǎn)環(huán)境時(shí)就應(yīng)該考慮好合適的回收站配置,回收站保留時(shí)間可以通過以下方式配置(如果將 --trash-days 設(shè)置為 0 則表示關(guān)閉回收站特性):
- 新建文件系統(tǒng):通過 juicefs format 的 --trash-days <value> 選項(xiàng)設(shè)置。
- 已有文件系統(tǒng):通過 juicefs config 的 --trash-days <value> 選項(xiàng)修改。
- 客戶端后臺(tái)任務(wù)
同一個(gè) JuiceFS 文件系統(tǒng)的所有客戶端在運(yùn)行過程中共享一個(gè)后臺(tái)任務(wù)集,每個(gè)任務(wù)定時(shí)執(zhí)行,且具體執(zhí)行的客戶端隨機(jī)選擇。具體的后臺(tái)任務(wù)包括:
- 清理待刪除的文件和對(duì)象
- 清理回收站中的過期文件和碎片
- 清理長時(shí)間未響應(yīng)的客戶端會(huì)話
- 自動(dòng)備份元數(shù)據(jù)
由于這些任務(wù)執(zhí)行時(shí)會(huì)占用一定資源,因此可以為業(yè)務(wù)較繁重的客戶端配置 --no-bgjob 選項(xiàng)來禁止其參與后臺(tái)任務(wù)。
注意:請(qǐng)保證至少有一個(gè) JuiceFS 客戶端可以執(zhí)行后臺(tái)任務(wù)
- 客戶端日志滾動(dòng)
當(dāng)后臺(tái)運(yùn)行 JuiceFS 掛載點(diǎn)時(shí),客戶端默認(rèn)會(huì)將日志輸出到本地文件中。取決于掛載文件系統(tǒng)時(shí)的運(yùn)行用戶,本地日志文件的路徑稍有區(qū)別。root 用戶對(duì)應(yīng)的日志文件路徑是 /var/log/juicefs.log,非 root 用戶的日志文件路徑是 $HOME/.juicefs/juicefs.log。
本地日志文件默認(rèn)不會(huì)滾動(dòng),生產(chǎn)環(huán)境中為了確保日志文件不占用過多磁盤空間需要手動(dòng)配置。以下是一個(gè)日志滾動(dòng)的示例配置:
# /etc/logrotate.d/juicefs
/var/log/juicefs.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
}
通過 logrotate -d /etc/logrotate.d/juicefs 命令可以驗(yàn)證配置文件的正確性。