《POSIX对于对象存储真的不合适吗?- CodesCode》
POSIX真的不适合用于对象存储吗?通过对MinIO、s3fs-fuse和JuiceFS的数据驱动分析来探讨
本篇文章的作者对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协议的优势和劣势。
我在MinIO、JuiceFS和s3fs-fuse
上进行了以下两个测试:
- 写入一个10GB的文件
- 用Pandas覆盖小文件
这三个解决方案都使用了一个在不同服务器上部署的MinIO实例作为底层存储。测试样本使用了一个10GB大小的文件,这个文件与MinIO文章中提到的CSV文件相同。
本文中的所有环境、软件、脚本和样本数据都附有完整的代码和说明,以确保您可以重现环境和测试结果。
服务器和测试环境设置
两个配置相同的云服务器:
- 系统:Ubuntu 22.04 x64
- CPU:8核
- 内存:16GB
- SSD:500GB
- 网络:VPC
每台服务器的信息如下:
服务器 | IP地址 | 目的 |
---|---|---|
服务器A | 172.16.254.18 | 部署MinIO实例 |
服务器B | 172.16.254.19 | 作为测试环境 |
准备服务器A
1. 使用以下命令在服务器A上使用Docker部署MinIO:
# 创建一个专用目录并进入其中
mkdir minio && cd minio
# 创建一个配置文件
mkdir config
touch config/minio
“`html
2. 我把以下信息写入了config/minio
文件:
MINIO_ROOT_USER=adminMINIO_ROOT_PASSWORD=abc123abcMINIO_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控制台上,我预先创建了三个存储桶:
存储桶名称 | 用途 |
---|---|
test-minio | 用于测试MinIO |
test-juicefs | 用于测试JuiceFS |
test-s3fs | 用于测试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 -vmc 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 --versionAmazon 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 versionjuicefs 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=adminexport MINIO_ROOT_PASSWORD=abc123abcjuicefs 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网关也可以部署在服务器A或任何其他可访问互联网的服务器上,因为它公开了基于网络的S3 API。
测试和结果
这是我测试和结果的简要总结:
测试 | MinIO | S3FS-FUSE | JuiceFS(FUSE) | JuiceFS(S3网关) |
---|---|---|---|---|
写入一个10 GB文件 | 0m27.651s | 3m6.380s | 0m28.107s | 0m28.091s |
使用Pandas覆盖小文件 | 0.83秒 | 0.78秒 | 0.46秒 | 0.96秒 |
测试1:写入一个10 GB文件
此测试旨在评估写入大文件的性能。时间越短,性能越好。我使用time
命令测量写入操作的持续时间,并提供了三个指标:
real
:命令开始到结束的实际时间。包括所有等待时间,例如等待I/O操作完成、等待进程切换和等待资源。user
:在用户模式下执行的时间,表示用于执行用户代码的CPU时间。通常表示命令的计算工作量。sys
:在内核模式下执行的时间,表示用于执行内核代码的CPU时间。通常表示与系统调用相关的工作量,例如文件I/O和进程管理。
MinIO
我运行了以下命令执行复制测试:
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv my/test-minio/
将一个10 GB文件直接写入MinIO的结果:
real 0m27.651suser 0m10.767ssys 0m5.439s
s3fs-fuse
我运行了以下命令执行复制测试:
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv /root/mnt-s3fs/
将一个10 GB文件直接写入s3fs-fuse
的结果:
real 3m6.380suser 0m0.012ssys 0m5.459s
注意:尽管
s3fs-fuse
的写入时间为3分6秒,但没有像MinIO的文章中描述的写入失败。
JuiceFS
我使用POSIX和S3 API方法测试了JuiceFS的大文件写入性能:
# 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.107suser 0m0.292ssys 0m6.930s
果汁文件系统(JuiceFS)S3 API写入10 GB文件的结果:
实际时间 0m28.091秒;用户时间 0m13.643秒;系统时间 0m4.142秒
大文件写入结果总结
以下图表展示了测试结果:
测试结果显示,直接写入到MinIO和JuiceFS的性能相当,完成任务所需的时间约为30秒。相比之下,s3fs-fuse
写入一个10 GB文件需要超过3分钟,大约比前两者慢六倍。
在写入大文件时,mc
使用分块API将文件分块上传到S3接口。相反,s3fs-fuse
只能在单个线程中向POSIX写入。JuiceFS还会自动将大文件分块并在顺序写入时并行写入MinIO,确保与直接MinIO写入相当的性能。而S3FS首先将文件写入缓存盘的单个线程,然后分块上传到MinIO,导致写入时间较长。
根据写入10 GB文件所需的30秒计算,平均速度为333 MB/s。这受限于云服务器SSD的带宽。这些测试结果表明,MinIO和JuiceFS都能最大程度利用本地SSD带宽,并随着服务器云盘和网络带宽的改进而提高性能。
测试二:使用Pandas覆盖小文件
这个测试评估了对象存储系统在小文件覆盖场景中的性能。每个软件的测试脚本略有不同。你可以在这里找到所有的脚本代码。
MinIO
我获取了测试脚本并运行了测试:
# 获取测试脚本curl -LO https://gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-minio.py# 运行测试python3 pandas-minio.py
结果如下:
执行时间:0.83秒
s3fs-fuse
我获取了测试脚本并运行了测试:
# 获取测试脚本curl -LO gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-s3fs.py# 运行测试python3 pandas-s3fs.py
测试结果如下:
执行时间:0.78秒
JuiceFS POSIX
我获取了测试脚本并运行了测试:
# 获取测试脚本curl -LO gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-juicefs-posix.py# 运行测试python3 pandas-juicefs-posix.py
测试结果如下:
执行时间:0.43秒
JuiceFS S3 API
我获取了测试脚本并运行了测试:
# 获取测试脚本curl -LO https://gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-juicefs-s3api.py# 运行测试python3 pandas-juicefs-s3api.py
测试结果如下:
执行时间:0.86秒
Pandas小文件覆盖的总结
下图展示了测试结果:
在这个测试中,JuiceFS FUSE-POSIX显示了最快的速度,几乎比其他解决方案快了两倍。MinIO、s3fs-fuse和JuiceFS S3 Gateway的性能类似。从小文件覆盖的角度来看,POSIX接口证明比对象存储接口更高效,提供了更好的性能。
问题和分析
问题1:为什么S3FS这么慢?
分析:从测试数据可以清楚地看出,当写入相同的10GB文件时,S3FS花费了3分钟,而MinIO和JuiceFS分别在大约30秒内完成了任务。这种显著的性能差异主要是由不同的技术实现造成的。当s3fs-fuse写入文件时,它首先将文件写入本地临时文件,然后将其分块上传到对象存储中。如果本地磁盘空间不足,它将进行同步上传。它需要在本地磁盘和S3存储之间复制数据。因此,大文件或大量文件会导致性能下降。
此外,S3FS依靠底层对象存储的元数据管理能力。当它处理大量文件时,频繁与对象存储进行元数据检索的交互对性能有重大影响。简单来说,文件大小和写入S3FS的文件总数越大,性能开销比例就越大。
问题2:为什么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的独立元数据管理、并发读写能力和缓存机制提供了卓越的性能。这是一个值得考虑的高性能文件系统解决方案。
Leave a Reply