本帖作者对MinIO文章中的观点提出质疑,该文认为POSIX不适用于对象存储。他进行了全面测试,涉及MinIO的s3fs-fuse
与JuiceFS。结果显示,MinIO和JuiceFS性能出色,而s3fs-fuse
表现滞后。在小文件覆盖场景下,JuiceFS FUSE-POSIX方案超越其他解决方案。
最近,我读到MinIO博客上的一篇文章,题为”在对象存储上构建文件系统是个坏主意,原因如下.” 作者以s3fs-fuse
为例,阐述了使用可移植操作系统接口(POSIX)方法访问MinIO数据时遇到的性能挑战,指出其性能远逊于直接访问MinIO。作者将这些性能问题归咎于POSIX的固有缺陷。然而,我们的经验与这一结论有所不同。
POSIX是一项实用且广泛采纳的标准。遵循POSIX开发软件能确保在不同操作系统间的兼容性和可移植性。众多行业的应用程序大多遵循POSIX标准。随着云计算、大数据和人工智能技术的进步,以及数据存储量的日益增长,对如对象存储这般弹性存储解决方案的需求不断增长,尽管MinIO等对象存储提供了多种语言的SDK,但许多传统应用在适应对象存储API方面仍显吃力。为此,各类存储产品纷纷在对象存储之上实现POSIX接口,以满足这一刚性需求。
业内诸多产品,如Ceph、JuiceFS和Weka,均成功在对象存储上实现了POSIX接口。这些方案拥有庞大的用户群体和众多成功案例,且在性能表现上亦颇为出色。
诚然,POSIX的复杂性不容小觑,但相关问题并非无法克服。出于对这些声明的尊重及验证之目的,我搭建了测试环境,采用与MinIO文章中相同的样本数据和测试方法进行了验证。
对比产品及测试目标
为全面评估,我将JuiceFS引入对比之中。
JuiceFS是一个开源的云原生分布式文件系统,它采用对象存储作为数据存储层,并依赖独立的数据库存储元数据。它提供了多种访问方式,包括POSIX API、S3 API、CSI Driver、HDFS API和WebDAV,并具备独特的数据分块、缓存和并发读写机制。JuiceFS本质上是一个文件系统,与s3fs-fuse
等工具截然不同,后者仅是将对象存储转换为POSIX协议。
通过引入JuiceFS进行对比,旨在客观评估在对象存储之上实现POSIX等协议的优劣。
I conducted the following two tests on MinIO, JuiceFS, and s3fs-fuse
:
- 编写一个10GB的文件
- 使用Pandas覆盖小文件
三种方案均采用部署在独立服务器上的MinIO实例作为底层存储。对于测试样本,使用了10GB的文件,即MinIO文章中提到的相同CSV文件。
本文中所有的环境、软件、脚本及样本数据均附带完整的代码和指导,确保您能够复现环境及测试结果。
服务器及测试环境搭建
两台配置相同的云服务器:
- 系统:Ubuntu 22.04 x64
- CPU:8核
- 内存:16GB
- SSD:500GB
- 网络:VPC
每台服务器的信息:
Server | IP | Purpose |
---|---|---|
Server A | 172.16.254.18 | Deploying the MinIO instance |
Server B | 172.16.254.19 | As the test environment |
Server A准备
1. 我在服务器A上使用Docker部署了MinIO,执行了以下命令:
# 创建专用目录并进入该目录。
mkdir minio && cd minio
# 创建配置文件。
mkdir config
touch config/minio
2. 我将以下信息写入到config/minio
文件中:
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=abc123abc
MINIO_VOLUMES="/mnt/data"
3. 我创建了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"
4. 在MinIO的Web控制台中,我预先创建了三个存储桶:
Bucket name | Purpose |
---|---|
test-minio | For testing MinIO |
test-juicefs | For testing JuiceFS |
test-s3fs | For testing s3fs-fuse |
服务器B准备工作
1. 我下载了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版本。
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。
I used the official script to install the latest JuiceFS Community Edition.
# 一键安装脚本
curl -sSL https://d.juicefs.com/install | sh -
# 检查版本。
juicefs version
juicefs version 1.1.0+2023-09-04.08c4ae6
5. 我创建了一个文件系统。JuiceFS 是一个在使用前需要创建的文件系统。除了对象存储外,它还需要一个数据库作为元数据引擎。它支持多种数据库。这里,我使用了常用的Redis作为元数据引擎。
注意:我已在服务器A上安装了Redis,可通过
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
6. 我通过更常用的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也可以部署在服务器A或任何其他可通过互联网访问的服务器上,因为它提供了一个基于网络的S3 API。
测试与结果
以下是我测试和结果的简要总结:
Test | MinIO | S3FS-FUSE | JuiceFS (FUSE) |
JuiceFS (S3 gateway) |
---|---|---|---|---|
Writing a 10 GB file | 0m27.651s | 3m6.380s | 0m28.107s | 0m28.091s |
Overwriting small files with Pandas | 0.83s | 0.78s | 0.46s | 0.96s |
测试1:写入一个10GB文件
此测试旨在评估写入大文件的性能。所用时间越短,性能越好。我使用time
命令来测量写操作的持续时间,提供了三个指标:
real
: 命令从开始到结束的实际时间,包含所有等待时间,如等待I/O操作完成、等待进程切换及资源等待。user
: 用户模式下执行的时间,表示用于执行用户代码的CPU时间,通常代表命令的计算工作量。sys
: 内核模式下执行的时间,表示用于执行内核代码的CPU时间,通常代表与系统调用相关的负载,如文件I/O和进程管理。
MinIO
I ran the following command to perform a copy test:
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv my/test-minio/
直接向MinIO写入10GB文件的结果:
real 0m27.651s
user 0m10.767s
sys 0m5.439s
s3fs-fuse
I ran the following command to perform a copy test:
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv /root/mnt-s3fs/
直接向s3fs-fuse
写入10GB文件的结果:
real 3m6.380s
user 0m0.012s
sys 0m5.459s
注意:尽管
s3fs-fuse
的写入时间为3分6秒,但并未出现MinIO文章中所描述的写入失败情况。
JuiceFS
I tested the performance of JuiceFS for large file writes using both the POSIX and S3 API methods:
# 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写入10GB文件的结果:
real 0m28.107s
user 0m0.292s
sys 0m6.930s
JuiceFS S3 API写入10GB文件的结果:
real 0m28.091s
user 0m13.643s
sys 0m4.142s
大文件写入结果汇总
下图展示了测试结果:

测试结果显示,直接写入MinIO和JuiceFS的性能相当,均在约30秒内完成任务。相比之下,s3fs-fuse
写入10GB文件耗时超过3分钟,约为前两者速度的六分之一。
在处理大文件时,mc
利用Multipart API将文件分块上传至S3接口。相反,s3fs-fuse
仅能以单线程方式向POSIX写入。JuiceFS则自动将大文件分割成块,并在顺序写入过程中并发写入MinIO,确保性能与直接写入MinIO相当。而S3FS首先以单线程方式将数据写入缓存磁盘,随后再分块上传至MinIO,导致写入时间更长。
基于一次写入10GB文件耗时30秒的计算,平均速度为333MB/s,这一速度受限于云服务器SSD的带宽。测试结果表明,无论是MinIO还是JuiceFS均能充分利用本地SSD带宽,且随着服务器云盘和网络带宽的提升,其性能也将得到提升。
测试2:使用Pandas重写小文件
本测试评估了对象存储系统在小文件重写场景下的性能。各软件的测试脚本略有不同,所有脚本代码可在此查阅。
MinIO
I got the test script and ran the test:
# 获取测试脚本。
curl -LO https://gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-minio.py
# 运行测试。
python3 pandas-minio.py
测试结果如下:
Execution time: 0.83 seconds
s3fs-fuse
I got the test script and ran the test:
# 获取测试脚本。
curl -LO gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-s3fs.py
# 运行测试。
python3 pandas-s3fs.py
测试结果如下:
Execution time: 0.78 seconds
JuiceFS POSIX
I got the test script and ran the test:
# 获取测试脚本。
curl -LO gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-juicefs-posix.py
# 运行测试。
python3 pandas-juicefs-posix.py
测试结果如下:
Execution time: 0.43 seconds
JuiceFS S3 API
I got the test script and ran the test:
# 获取测试脚本。
curl -LO https://gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-juicefs-s3api.py
# 运行测试。
python3 pandas-juicefs-s3api.py
测试结果如下:
Execution time: 0.86 seconds
Pandas小文件覆盖概要
下图展示了测试结果:

在此测试中,JuiceFS FUSE-POSIX表现出最快的速度,几乎是其他解决方案的两倍。MinIO、s3fs-fuse
和JuiceFS S3 Gateway性能相近。从小文件覆盖的角度来看,POSIX接口更为高效,性能优于对象存储接口。
问题与分析
问题1:为什么S3FS如此慢?
分析:从测试数据可以看出,在写入相同的10GB文件时,S3FS耗时3分钟,而MinIO和JuiceFS均在约30秒内完成任务。这种显著的性能差异主要源于不同的技术实现。当s3fs-fuse
写入文件时,它首先将文件写入本地临时文件,然后分块上传至对象存储。如果本地磁盘空间不足,它会同步上传。这需要在本地磁盘和S3存储之间复制数据。因此,大文件或大量文件会导致性能下降。
此外,S3FS依赖底层对象存储的元数据管理能力。当处理大量文件时,频繁与对象存储交互以检索元数据对性能影响显著。简而言之,写入S3FS的文件大小和总量越大,相应的性能开销也越大。
问题二:为何JuiceFS更快?
分析:在测试中,JuiceFS和S3FS均通过FUSE进行读写操作。JuiceFS像MinIO一样充分利用了磁盘带宽,却没有遭遇S3FS那样的性能问题。
关键在于它们各自的技术架构。在文件写入过程中,虽然数据都需经过FUSE层处理,但JuiceFS采用高并发、缓存及数据分块技术,有效降低了FUSE层与底层对象存储间的通信开销。这使得JuiceFS能同时处理更多文件的读写请求,缩短等待时间和传输延迟。
另外,JuiceFS采用专用数据库(如Redis)管理元数据。面对大量文件时,独立的元数据引擎能有效减轻负担,加快文件定位速度。
结论
上述测试表明,以对象存储为基础并在其上实现POSIX接口,并不一定会导致性能损失。无论是写入大文件还是小文件,JuiceFS展现出的性能均可与直接向MinIO写入相媲美,且不会因POSIX访问而导致底层对象存储性能下降。此外,在Pandas表格覆盖操作方面,JuiceFS FUSE-POSIX的性能保持稳定,甚至性能接近MinIO的两倍。
测试结果显示,某些软件如s3fs-fuse
在S3 API与POSIX接口间转换时可能遭遇性能下降。尽管它可作为临时访问S3的便捷工具,但对于稳定且高性能的长期使用,需谨慎研究和验证以选择更合适的解决方案。
对于简单的非结构化文件归档,直接使用MinIO或云对象存储是个好选择。然而,在涉及大规模数据存储与处理的场景,如AI模型训练、大数据分析、Kubernetes数据持久化及其他频繁的读写操作中,JuiceFS的独立元数据管理、并发读写能力和缓存机制提供了卓越性能。它是一个值得考虑的高性能文件系统解决方案。
Source:
https://dzone.com/articles/is-posix-really-unsuitable-for-object-stores-a-dat