最近,留意到 MinIO 官方部落格的一篇題為「在物件儲存上實現 POSIX 存取介面是壞主意」的文章,作者以 S3FS-FUSE 為例分享了通過 POSIX 方式存取 MinIO 中的資料時碰到了效能方面的困難,效能遠不如直接存取 MinIO。在對結果進行分析時,作者認為是 POSIX 本身存在的缺陷導致的效能問題。這個結論與我們既有經驗有一定出入。
我們知道 POSIX 是一個有用而且廣泛應用的標準,遵循它而開發的程式可以保證不同作業系統之間的相容性和可移植性。各行各業中常用的業務系統和應用程式,大多遵循 POSIX 標準。
隨著雲端計算、巨量資料、人工智慧等技術的發展和資料儲存量的攀升,在地化應用也逐漸產生對物件儲存等彈性儲存的需求,MinIO 等物件儲存雖然提供了各種語言的 SDK,但許多傳統應用很難甚至無法修改程式碼去適配物件儲存的存取介面,這促使很多儲存產品在物件儲存的基礎上去實現 POSIX 介面來滿足這樣的剛性需求。
業內在物件儲存上實現 POSIX 介面的產品有很多,比如 Ceph、JuiceFS、Weka 等,它們都有廣泛的使用者群和大量的成功案例,在效能方面也都有不錯的表現。
誠然,我們認可 POSIX 存在較大的複雜性,需要付出很大的努力才能解決好相關的問題,但這些問題並不是無法解決。抱著尊重和求證的態度,我搭建了測試環境,採用相同的樣本和測試方法,進行了一番驗證。
為了得到更為全面的測試結果,我將 JuiceFS 引入了對比。
JuiceFS 是開源的雲原生分散式檔案系統,它採用物件儲存作為資料儲存層,採用獨立的資料庫儲存後設資料。提供了包括 POSIX API、S3 API、CSI Driver、HDFS API、WebDAV 在內的多種存取方式,具有獨特的資料分塊、快取和並行讀寫機制。JuiceFS 是檔案系統,與 s3fs-fuse 等只提供簡單的從物件儲存到 POSIX 協定轉換的工具有著本質的不同。
通過將 JuiceFS 引入對比,可以更為客觀地求證以物件儲存為底層實現 POSIX 等協定的利弊。
在本文中,我會對 MinIO、JuiceFS 和 s3fs-fuse 進行以下兩項測試:
10GB 大檔案的寫入測試
Pandas 小檔案覆蓋寫測試
在底層儲存方面,它們均使用部署在獨立伺服器上的 MinIO 範例;在測試樣本方面,10GB 檔案會採用那篇文章中使用的 csv 檔案。
本文所提及的環境、軟體、指令碼、樣本資料等均提供完整的程式碼和說明,確保讀者可以復現環境和測試結果。
兩臺設定相同的雲伺服器:
每臺伺服器的資訊如下:
Server | IP | For |
---|---|---|
Server A | 172.16.254.18 | MinIO Instance |
Server B | 172.16.254.19 | Test Environment |
1.我在 Server A 上通過 Docker 部署了 MinIO,命令如下:
# 建立並進入專用目錄
mkdir minio && cd minio
# 建立組態檔
mkdir config
touch config/minio
config/minio
檔案中寫入以下資訊:
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=abc123abc
MINIO_VOLUMES="/mnt/data"
2.建立 MinIO 容器:
sudo docker run -d --name minio \
-p 9000:9000 \
-p 9090:9090 \
-v /mnt/minio-data:/mnt/data \
-v ./config/minio:/etc/config.env \
-e "MINIO_CONFIG_ENV_FILE=/etc/config.env" \
--restart unless-stopped \
minio/minio server --console-address ":9090"
3.在 MinIO 的 Web Console 中預先建立三個 buckets:
Bucket Name | 目的 |
---|---|
test-minio | 用於測試 MinIO |
test-juicefs | 用於測試 JuiceFS |
test-s3fs | 用於測試 s3fs-fuse |
下載 10GB 測試樣本檔案
curl -LO https://data.cityofnewyork.us/api/views/t29m-gskq/rows.csv?accessType=DOWNLOAD
2.安裝 mc 使用者端
mc 是 MinIO 專案開發的命令列檔案管理器,可以在 Linux 命令列讀寫本地以及 S3 相容的物件儲存。mc 的 cp 命令可以實時顯示資料拷貝的進度和速度,便於觀察各項測試。
注:為了保持測試的公平性,三種方案均採用 mc 進行寫測試。
# 下載 mc
wget https://dl.min.io/client/mc/release/linux-amd64/mc
# 檢查版本
mc -v
mc version RELEASE.2023-09-20T15-22-31Z (commit-id=38b8665e9e8649f98e6162bdb5163172e6ecc187)
Runtime: go1.21.1 linux/amd64
# 安裝 mc
sudo install mc /usr/bin
# 為 MinIO 新增別名
mc alias set my http://172.16.254.18:9000 admin abc123abc
3.安裝 s3fs-fuse
sudo apt install s3fs
# 檢查版本
s3fs --version
Amazon Simple Storage Service File System V1.93 (commit:unknown) with OpenSSL
# 設定物件儲存存取金鑰
echo admin:abc123abc > ~/.passwd-s3fs
# 修改金鑰檔案許可權
chmod 600 ~/.passwd-s3fs
# 建立掛載目錄
mkdir mnt-s3fs
# 掛載物件儲存
s3fs test-s3fs:/ /root/mnt-s3fs -o url=http://172.16.254.18:9000 -o use_path_request_style
4.安裝 JuiceFS
這裡使用官方提供的指令碼安裝最新的 JuiceFS 社群版
# 一鍵安裝指令碼
curl -sSL https://d.juicefs.com/install | sh -
# 檢查版本
juicefs version
juicefs version 1.1.0+2023-09-04.08c4ae6
JuiceFS 是檔案系統,需要先建立才能使用。除了物件儲存,還需要一個資料庫作為後設資料引擎,支援多種資料庫,這裡使用較常用的 Redis 作為後設資料引擎。
注:我在這裡將 Redis 安裝在 Server A,通過 172.16.254.18:6379 進行存取,無密碼,安裝過程略,詳情參考 Redis 官方檔案。
# 建立檔案系統
juicefs format --storage minio \
--bucket http://172.16.254.18:9000/test-juicefs \
--access-key admin \
--secret-key abc123abc \
--trash-days 0 \
redis://172.16.254.18/1 \
myjfs
5.另外,我會同時以較為常用的 POSIX 和 S3 API 兩種方式存取 JuiceFS 並分別測試它們的效能。
# 建立掛載目錄
mkdir ~/mnt-juicefs
# 以 POSIX 方式掛載檔案系統
juicefs mount redis://172.16.254.18/1 /root/mnt-juicefs
# 以 S3 API 方式存取檔案系統
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=abc123abc
juicefs gateway redis://172.16.254.18/1 0.0.0.0:9000
# 在 mc 中為 JuiceFS S3 API 新增別名
mc alias set juicefs http://172.16.254.18:9000 admin abc123abc
注:JuiceFS Gateway 也可以部署在 Server A 或其他任何可聯網伺服器上,因為它開放的是基於網路存取的 S3 API。
這項測試用來評估寫大檔案的效能,耗時越短效能越好。這裡會使用 time 命令統計寫入耗時,結果會包含三個指標:
real:從命令開始到結束的實際時間。它包括了所有的等待時間,例如等待 I/O 操作完成、等待程序切換、等待資源等。
user:在使用者態(使用者模式)執行的時間,也就是 CPU 用於執行使用者程式碼的時間。它通常表示命令的計算工作量。
sys:在核心態(系統模式)執行的時間,也就是 CPU 用於執行核心程式碼的時間。它通常表示命令與系統呼叫(如檔案 I/O、程序管理等)相關的工作量。
# 執行拷貝測試
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv my/test-minio/
MinIO 直寫 10 GB 檔案的測試結果:
real 0m27.651s
user 0m10.767s
sys 0m5.439s
# 執行拷貝測試
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv /root/mnt-s3fs/
s3fs-fuse 寫 10 GB 檔案的測試結果:
real 3m6.380s
user 0m0.012s
sys 0m5.459s
注:雖然寫入耗時 3 分零 6 秒,但並沒有出現那篇文章所謂寫入失敗的情況。
分別測試 JuiceFS 的 POSIX 和 S3 API 的大檔案寫效能:
# POSIX 寫測試
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv /root/mnt-juicefs/
# S3 API 寫測試
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv juicefs/myjfs/
JuiceFS POSIX 寫 10 GB 檔案的測試結果:
real 0m28.107s
user 0m0.292s
sys 0m6.930s
JuiceFS S3 API 寫 10GB 檔案的測試結果:
real 0m28.091s
user 0m13.643s
sys 0m4.142s
從測試結果來看,直接寫 MinIO 和 JuiceFS 的效能相當,均可在 30s 內完成,而 s3fs-fuse 寫入 10GB 檔案耗時 3 分鐘以上,平均比前兩者慢了 6 倍左右。
在寫入大檔案時,mc 會使用 Multipart API 來將檔案分塊上傳到 S3 介面,而只能單執行緒寫入到 POSIX。JuiceFS 在大檔案的順序寫也會自動將檔案分塊並並行寫入到 MinIO 中,因此與直接寫 MinIO 效能相當。而 S3FS 預設先是單執行緒寫入到快取盤,然後再分塊寫入到 MinIO 中,這會耗費更多寫入時間。
按照寫 10GB 檔案耗時 30 秒計算,平均速度為 333 MB/s,這是雲伺服器 SSD 的頻寬限制,測試結果表明,MinIO 和 JuiceFS 都能打滿本地 SSD 的頻寬,它們的效能會隨著伺服器雲盤和網路頻寬的提升而提升。
這項測試主要用來評估物件儲存在小檔案覆蓋寫方面的效能,各個軟體的測試指令碼略有不同,你可以在這裡找到所有指令碼程式碼。
# 獲取測試指令碼
curl -LO https://gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-minio.py
# 執行測試
python3 pandas-minio.py
測試結果:
Execution time: 0.83 seconds
# 獲取測試指令碼
curl -LO gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-s3fs.py
# 執行測試
python3 pandas-s3fs.py
測試結果:
Execution time: 0.78 seconds
# 獲取測試指令碼
curl -LO gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-juicefs-posix.py
# 執行測試
python3 pandas-juicefs-posix.py
測試結果:
Execution time: 0.43 seconds
# 獲取測試指令碼
curl -LO https://gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-juicefs-s3api.py
# 執行測試
python3 pandas-juicefs-s3api.py
測試結果:
Execution time: 0.86 seconds
在這項測試中,JuiceFS FUSE-POSIX 的速度最快,幾乎是其他方案的 2 倍。MinIO、s3fs-fuse、JuiceFS S3 Gateway 的速度相當。從小檔案覆蓋寫的角度來看,POSIX 介面效率更高,比物件儲存介面有更好的效能表現。
MinIO | S3FS-FUSE | JuiceFS (FUSE) | JuiceFS (s3 gateway) | |
---|---|---|---|---|
10GB 大檔案寫 | 0m27.651s | 3m6.380s | 0m28.107s | 0m28.091s |
Pandas 小檔案覆蓋寫 | 0.83s | 0.78s | 0.46s | 0.96s |
問題一:S3FS 為什麼這麼慢?
從測試資料可以清楚地看到,寫入同樣的 10GB 大檔案,S3FS 需要 3 分鐘,而 MinIO 和 JuiceFS 只需要 30 秒左右,速度相差近 6 倍,這主要是由於不同的技術實現導致的。
s3fs-fuse 在寫入檔案時,會優先寫入本地臨時檔案,然後以分片方式上傳物件儲存。如果本地磁碟空間不足,則會以同步的方式上傳。因為它需要在本地磁碟和 S3 儲存之間進行資料複製,在處理大檔案或大量檔案時就會導致效能下降。
再者,S3FS 依賴底層物件儲存的後設資料管理能力,當需要讀寫大量檔案時,頻繁地與物件儲存互動獲取後設資料也會對效能產生很大的影響。
簡單來說,寫入 S3FS 的檔案體積和總量越大,相應的效能開銷也會成比例地放大。
問題二:JuiceFS 為什麼更快?
同樣是通過 FUSE 進行讀寫,為什麼 JuiceFS 可以與 MinIO 一樣打滿磁碟頻寬,而沒有像 S3FS 那樣出現效能問題呢?這同樣也是由技術架構決定的。
在寫入檔案時,資料雖然也經由 FUSE 層處理,但 JuiceFS 通過高並行、快取、資料分塊等技術降低了與底層物件儲存之間的通訊開銷,一次性處理更多檔案的讀寫請求,從而減少了等待時間和傳輸延遲。
另外,JuiceFS 採用獨立的資料庫(在本文中使用了 Redis)管理後設資料,當檔案量特別大時,獨立的後設資料引擎能有效釋放壓力,可以更快地定位檔案位置。
以上資料表明,把物件儲存作為底層,在其上實現 POSIX 介面不一定會損失效能,不論是寫大檔案還是小檔案,JuiceFS 的效能與直接寫 MinIO 是相當的,並沒有因為存取 POSIX 而損失底層物件儲存的效能。而在 Pandas 表格覆蓋寫方面,JuiceFS FUSE-POSIX 的效能不降反升,超過 MinIO 近兩倍。
從測試結果不難發現,某些軟體(例如 s3fs-fuse)將 S3 API 與 POSIX 介面相互轉換可能會導致物件儲存的效能損失,但它不失為一款還算方便的臨時存取 S3 的小工具,但要想長期穩定的高效能使用,需要通過更為審慎的調研和驗證來選擇其他更適的方案。
簡單的非結構化檔案歸檔儲存,直接使用 MinIO 或雲上物件儲存是不錯的選擇。而對於需要進行大規模資料儲存和處理,如 AI 模型訓練、巨量資料分析和 Kubernetes 資料持久化等頻繁讀寫的場景,JuiceFS 的獨立後設資料管理、並行讀寫和快取機制會帶來更好的效能表現,是更值得嘗試的高效能檔案系統解決方案。
希望這篇內容能夠對你有一些幫助,如果有其他疑問歡迎加入 JuiceFS 社群與大家共同交流。