POSIX真的不适合对象存储吗?基于数据的事实解答

本帖作者对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

大文件写入结果汇总

下图展示了测试结果:

Large file write results (lower is better)

测试结果显示,直接写入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小文件覆盖概要

下图展示了测试结果:

Pandas overwrite results (lower is better)

在此测试中,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