跳转至

S3 Files vs 开源方案实测:s3fs-fuse 和 fsspec 性能对比与选型

Lab 信息

  • 难度: ⭐⭐ 中级
  • 预估时间: 45 分钟
  • 预估费用: $2-3(S3 Files + EC2 t3.small 数小时)
  • Region: us-east-1
  • 最后验证: 2026-04-09

背景

上一篇文章 中,我们对比了三种 AWS 托管的 S3 挂载方案:S3 Files、File Gateway、Mountpoint CSI。但很多团队的第一反应不是找 AWS 托管服务,而是直接用开源工具:

  1. s3fs-fuse — 老牌 FUSE 挂载方案,把 S3 桶挂载为本地目录,任何程序都能直接读写
  2. fsspec/s3fs — Python 库,不是文件系统挂载,而是 Pythonic 的 S3 文件接口,pandas/dask 生态标配

这两个开源工具和 S3 Files 到底差多少?什么场景选哪个?本文用同一台 EC2、同一个 S3 桶做实测对比。

前置条件

  • AWS 账号(EC2、S3、S3 Files 权限)
  • AWS CLI v2.34.26+(S3 Files 需要 aws s3files 子命令)
  • EC2 实例(带 IAM Role,或配置好 AWS 凭证)

核心概念

三者定位对比

维度 S3 Files s3fs-fuse fsspec/s3fs
类型 AWS 托管 NFS 文件系统 FUSE 用户态文件系统 Python 库
底层 Amazon EFS + NFS v4.2 FUSE + S3 API (libcurl) aiobotocore + S3 API
安装 mount -t s3files apt install s3fs pip install s3fs
非 Python 程序可用 ✅ 任何程序 ✅ 任何程序 ❌ 仅 Python
缓存 托管高性能存储层 本地磁盘 + 内存元数据 内存 readahead buffer
POSIX 权限 ✅ 完整 ✅ 大子集 ❌ 无
写入模型 完整读写,~60s 批量写回 S3 完整读写,close 时立即上传 S3 API PUT(close 时上传)
同步 双向自动 单向(写即同步) 无同步概念(直接 API)
多客户端协调 ✅ NFS 锁 ❌ 无协调 ❌ 无协调
文件锁 ✅ NFS advisory lock ❌ 不支持 ❌ 不支持
重命名 ✅ 原生 ⚠️ server-side copy(非原子) ⚠️ server-side copy(非原子)
额外基础设施 无(AWS 托管)
月成本 高性能存储 $0.30/GB + 访问费 仅 S3 标准费用 仅 S3 标准费用
数据科学集成 ✅ pandas/dask/xarray
适用平台 Linux(EC2/Lambda/EKS/ECS) Linux/macOS/FreeBSD 任何 Python 环境

缓存机制差异

三者的缓存策略完全不同,直接决定了读性能:

S3 Files

  • 高性能存储层(AWS 托管,基于 EFS)
  • 小文件(< 128KB)自动缓存到高性能存储,亚毫秒延迟
  • 大文件(≥ 1MB)直接从 S3 流式读,不占用高性能存储
  • 缓存自动管理(30 天未访问自动过期)

s3fs-fuse

  • -o use_cache=/tmp/s3cache:本地磁盘缓存,文件下载后缓存到本地
  • 内存元数据缓存(stat_cache_expire)
  • 需要手动管理缓存空间
  • 缓存命中时性能接近本地磁盘

fsspec/s3fs

  • 默认 readahead 缓存(内存中的预读 buffer)
  • default_block_size=50MB
  • 可配置 none(无缓存)或 all(全文件缓存)
  • 目录 listing 有 TTL 缓存(listings_expiry_time
  • 不持久化缓存到磁盘

动手实践

Step 1: 准备环境

# 创建测试桶
aws s3api create-bucket --bucket YOUR-BUCKET --region us-east-1
aws s3api put-bucket-versioning --bucket YOUR-BUCKET \
  --versioning-configuration Status=Enabled --region us-east-1

# EC2 安装软件
sudo apt install -y s3fs          # s3fs-fuse
pip3 install s3fs                 # fsspec/s3fs (Python)

# 安装 S3 Files 所需的 efs-utils
curl -s https://amazon-efs-utils.aws.com/efs-utils-installer.sh | sudo bash -s -- --install

# 创建挂载点
sudo mkdir -p /mnt/s3files /mnt/s3fuse

Step 2: 创建 S3 Files 文件系统并挂载

# 创建文件系统
aws s3files create-file-system \
  --bucket arn:aws:s3:::YOUR-BUCKET \
  --role-arn YOUR-FS-ROLE-ARN \
  --region us-east-1

# 创建 Mount Target(需等文件系统 available)
aws s3files create-mount-target \
  --file-system-id fs-xxx \
  --subnet-id subnet-xxx \
  --security-groups sg-xxx \
  --region us-east-1

# 挂载
sudo mount -t s3files fs-xxx:/ /mnt/s3files

完整的 S3 Files 部署步骤请参考 S3 Files 实测文章

Step 3: 挂载 s3fs-fuse

# 使用 IAM role 挂载(EC2 Instance Profile)
sudo mkdir -p /tmp/s3cache
sudo s3fs YOUR-BUCKET /mnt/s3fuse \
  -o iam_role=YOUR-ROLE-NAME \
  -o url=https://s3.us-east-1.amazonaws.com \
  -o use_cache=/tmp/s3cache \
  -o endpoint=us-east-1

踩坑:s3fs-fuse 的 iam_role=auto 在 IMDSv2 下可能失败

在使用 IMDSv2 的 EC2 实例上,-o iam_role=auto 无法自动发现 IAM 角色名,挂载会静默失败(日志显示 could not load IAM role name from meta data)。解决方法是显式指定角色名:-o iam_role=MyRoleName

Step 4: 小文件性能对比 (1KB)

写入测试(5 次取中位数)

# 清除 OS 页缓存后测量
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null

# S3 Files
dd if=/dev/urandom of=/mnt/s3files/test.bin bs=1024 count=1

# s3fs-fuse
dd if=/dev/urandom of=/mnt/s3fuse/test.bin bs=1024 count=1

fsspec/s3fs 写入

import s3fs, time, os
fs = s3fs.S3FileSystem()
data = os.urandom(1024)

start = time.perf_counter()
with fs.open('YOUR-BUCKET/test.bin', 'wb') as f:
    f.write(data)
ms = (time.perf_counter() - start) * 1000

实测结果

方案 写延迟 (中位数) 读延迟 (中位数)
S3 Files 17ms 11ms
s3fs-fuse (cold) 307ms 61ms
s3fs-fuse (disk cache) 33ms
fsspec/s3fs 75ms 57ms

S3 Files 小文件读写全面碾压开源方案。s3fs-fuse 的写延迟高达 307ms,因为每次 close() 都要完成一次完整的 S3 PUT 请求。S3 Files 的写入先落到高性能存储层(本地 NFS),延迟极低。

Step 5: 大文件性能对比 (10MB)

实测结果

方案 写延迟 (中位数) 读延迟 (中位数)
S3 Files 133ms 53ms
s3fs-fuse (cold) 723ms 149ms
s3fs-fuse (disk cache) 96ms
fsspec/s3fs 303ms 188ms

大文件场景 S3 Files 仍然最快。s3fs-fuse 的写入需要在 close() 时将整个 10MB 通过 S3 Multipart Upload 上传,延迟最高。

Step 6: 缓存命中读延迟

测试方法:先读一次文件预热缓存,再连续读 5 次(不清除缓存)。

方案 缓存命中读延迟 (中位数)
S3 Files 4ms
s3fs-fuse (disk cache) 14ms
fsspec/s3fs (内存 cache) 58ms

S3 Files 的高性能存储层缓存效果最好(4ms 接近本地 NFS 延迟)。s3fs-fuse 的本地磁盘缓存也不错(14ms)。fsspec/s3fs 的"缓存命中"仍需 58ms,因为它的 readahead 缓存在 Python 进程内存中,每次 cat() 调用仍有 HTTP 协议开销。

Step 7: 写回 S3 同步延迟

这是 S3 Files 和 s3fs-fuse 的最大差异之一。

测试方法:写入文件后,轮询 S3 桶直到对象出现。

方案 写回 S3 延迟
S3 Files 63 秒
s3fs-fuse ~1 秒
fsspec/s3fs 即时(直接 S3 API)

S3 Files 的 63 秒写回延迟

S3 Files 设计为"最多等待 60 秒聚合变更后批量同步"。这意味着通过 NFS 写入的文件,需要约 60 秒后才能通过 S3 API 看到。如果你的工作流要求"写入后立即通过 S3 API 读取",这个延迟需要特别注意。

s3fs-fuse 没有这个问题:close() 时就执行 S3 PUT,数据立即可见。

Step 8: 并发读写

测试方法:同时读取 10 个 1KB 小文件。

方案 10 并发读总延迟
S3 Files 24ms
fsspec/s3fs (线程池) 198ms
s3fs-fuse (cold) 541ms

S3 Files 的 NFS 内核级实现在并发场景下优势巨大。s3fs-fuse 的 FUSE 用户态上下文切换开销在并发时被放大。

Step 9: POSIX 兼容性

操作 S3 Files s3fs-fuse fsspec/s3fs
chmod ❌ 不支持
chown ❌ 不支持
rename ✅(server-side copy) ⚠️ mv() 方法
symlink ❌ 不支持
文件锁 ✅ NFS lock
hard link

S3 Files 和 s3fs-fuse 都支持基本 POSIX 操作,但实现方式不同:

  • S3 Files 的权限存储为 file-permissions: 0100755 格式的 S3 对象元数据
  • s3fs-fuse 使用 x-amz-meta-* 自定义头存储权限,通过 x-amz-copy-source 高效修改

测试结果

完整对比表(五方案)

综合本文和上一篇文章的数据:

# 维度 S3 Files File Gateway Mountpoint CSI s3fs-fuse fsspec/s3fs
1 部署复杂度 3 步 13 步 kubectl apply 1 条命令 pip install
2 额外基础设施 m5.xlarge EC2+EBS DaemonSet
3 小文件写 (1KB) 17ms N/A N/A* 307ms 75ms
4 小文件读 (1KB) 11ms 6ms ~10-20ms* 61ms (cold) 57ms
5 大文件写 (10MB) 133ms N/A N/A* 723ms 303ms
6 大文件读 (10MB) 53ms 58ms S3 吞吐* 149ms (cold) 188ms
7 缓存命中读 4ms 2ms 无缓存 14ms 58ms
8 写回 S3 延迟 63s ~1s 即时 ~1s 即时
9 10 并发读 24ms N/A N/A* 541ms 198ms
10 POSIX 权限
11 文件锁
12 多客户端写
13 适用平台 Linux Linux/Windows K8s Linux/macOS 任何 Python
14 月成本 (100GB) ~$5-7 ~$164 ~$2.34 ~$2.30 ~$2.30

* Mountpoint CSI 和 File Gateway 数据引用自上一篇对比文章,Mountpoint 部分为文档推断。

延迟对比倍数(以 S3 Files 为基准)

操作 s3fs-fuse / S3 Files fsspec / S3 Files
小文件写 (1KB) 18x 慢 4.4x 慢
小文件读 (1KB) 5.5x 慢 5.2x 慢
大文件写 (10MB) 5.4x 慢 2.3x 慢
大文件读 (10MB) 2.8x 慢 3.5x 慢
缓存命中读 3.5x 慢 14.5x 慢
10 并发读 22.5x 慢 8.3x 慢

踩坑记录

踩坑 1: s3fs-fuse 的 iam_role=auto 在 IMDSv2 下静默失败

在默认启用 IMDSv2 的 EC2 实例上,s3fs-fuse 的 -o iam_role=auto 无法获取 Token 来查询实例元数据。挂载命令不报错,但后台 s3fs 进程在日志中显示 could not load IAM role name from meta data 后退出。挂载点存在但为空目录。

修复:显式指定角色名 -o iam_role=MyRoleName

踩坑 2: s3fs-fuse 随机写/追加写的隐藏成本

s3fs-fuse 文档声称支持"随机写和追加写",但实现方式是下载整个对象 → 内存中修改 → 重新上传整个对象。对于大文件,这意味着:

  • 追加 1 字节到 1GB 文件 = 下载 1GB + 上传 1GB
  • 这不是 s3fs-fuse 的 bug,而是 S3 API 的本质限制:对象存储没有 append API

如果你的应用频繁追加写大文件,s3fs-fuse 的性能会非常差。S3 Files 的高性能存储层可以在本地完成追加写,延迟低得多。

踩坑 3: fsspec/s3fs 的首次调用冷启动延迟

fsspec/s3fs 的首次 API 调用(Run 1)延迟远高于后续调用。实测中小文件写的 Run 1 为 3306ms,而后续 4 次在 56-94ms 之间。这是因为首次调用需要:

  1. 初始化 aiobotocore session
  2. 获取 IAM 临时凭证
  3. 建立 HTTPS 连接

在生产中,可以通过预热 S3FileSystem 实例来消除这个延迟。

费用明细

本次测试费用

资源 单价 用量 费用
EC2 t3.small $0.0208/h ~2h $0.04
S3 Files 高性能存储 $0.30/GB/月 ~50MB, 2h < $0.01
S3 Files 访问费 $0.03-0.06/GB ~100MB < $0.01
S3 存储 $0.023/GB/月 ~100MB < $0.01
合计 < $0.10

持续运行月成本对比

以「10GB 活跃数据 + 每月读 50GB + 写 5GB」为例:

方案 基础设施成本 数据成本 合计
S3 Files $0 ~$4(高性能存储 + 访问费 + S3) ~$4/月
s3fs-fuse $0 ~$0.25(仅 S3 标准费) ~$0.25/月
fsspec/s3fs $0 ~$0.25(仅 S3 标准费) ~$0.25/月

成本差异的本质

S3 Files 的高性能存储层($0.30/GB/月)比 S3 Standard($0.023/GB/月)贵 13 倍,这是"用钱换性能"的典型例子。开源方案免费但性能差 3-20 倍。

清理资源

# 1. 卸载文件系统
sudo umount /mnt/s3files
sudo umount /mnt/s3fuse

# 2. 删除 S3 Files 资源
aws s3files delete-mount-target --mount-target-id fsmt-xxx --region us-east-1
# 等待 mount target 删除
aws s3files delete-file-system --file-system-id fs-xxx --region us-east-1

# 3. 终止 EC2
aws ec2 terminate-instances --instance-ids i-xxx --region us-east-1

# 4. 删除安全组(等 EC2 终止后)
aws ec2 wait instance-terminated --instance-ids i-xxx --region us-east-1
aws ec2 delete-security-group --group-id sg-xxx --region us-east-1
aws ec2 delete-security-group --group-id sg-xxx --region us-east-1

# 5. 删除 IAM 角色
aws iam delete-role-policy --role-name S3FilesOSTestFSRole --policy-name S3Access
aws iam delete-role-policy --role-name S3FilesOSTestFSRole --policy-name EventBridge
aws iam delete-role --role-name S3FilesOSTestFSRole

aws iam remove-role-from-instance-profile --instance-profile-name S3FilesOSTestEC2Role-profile --role-name S3FilesOSTestEC2Role
aws iam delete-instance-profile --instance-profile-name S3FilesOSTestEC2Role-profile
aws iam detach-role-policy --role-name S3FilesOSTestEC2Role --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
aws iam detach-role-policy --role-name S3FilesOSTestEC2Role --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
aws iam delete-role --role-name S3FilesOSTestEC2Role

# 6. 清空并删除 S3 桶
aws s3 rm s3://YOUR-BUCKET --recursive --region us-east-1
aws s3api delete-bucket --bucket YOUR-BUCKET --region us-east-1

务必清理

S3 Files 高性能存储按 GB 计费。虽然测试数据量小,但忘记删除 File System 会产生持续费用。

结论与建议

一句话总结

  • S3 Files — 性能最强(3-20x 快于开源方案),但有 ~60s 写回延迟和额外存储费用
  • s3fs-fuse — 部署最简单的 POSIX 挂载方案,写回即时,但性能最差(FUSE 开销)
  • fsspec/s3fs — Python 数据科学场景首选,不是文件系统挂载,不能被非 Python 程序使用

场景化选型建议(含五方案)

场景 推荐方案 理由
EC2 新应用,需要文件系统语义 ✅ S3 Files 性能最好,零运维,完整 POSIX
需要写入后立即在 S3 可见 ✅ s3fs-fuse 或 fsspec S3 Files 有 ~60s 延迟
Python 数据科学/ML 管道 ✅ fsspec/s3fs pandas/dask 原生支持,最简洁
预算极度敏感 ✅ s3fs-fuse 或 fsspec 零额外费用(仅 S3 标准费)
多客户端共享读写 ✅ S3 Files 唯一支持 NFS 文件锁的方案
EKS 大文件只读 ✅ Mountpoint CSI 多并发 S3 GET 最高吞吐
需要 SMB / Windows ✅ File Gateway 唯一支持 SMB 的方案
快速原型/临时挂载 ✅ s3fs-fuse apt install && s3fs,最快上手
非 AWS S3 兼容存储 ✅ s3fs-fuse 或 fsspec 支持 MinIO/Ceph/等
高并发低延迟 ✅ S3 Files 内核级 NFS,并发性能最好

关键决策树

你的应用是 Python?
├── 是
│   └── 需要文件系统挂载(非 Python 组件也要读写)?
│       ├── 是 → S3 Files(性能优先)或 s3fs-fuse(成本优先)
│       └── 否 → fsspec/s3fs ✅(最简洁的 Python S3 接口)
└── 否
    └── 需要文件系统挂载?
        ├── 是
        │   └── 需要多客户端协调/文件锁?
        │       ├── 是 → S3 Files ✅
        │       └── 否 → 性能敏感?
        │           ├── 是 → S3 Files ✅
        │           └── 否 → s3fs-fuse ✅(零额外费用)
        └── 否 → 直接用 AWS SDK / boto3

从开源方案迁移到 S3 Files

适合迁移

  • ✅ 使用 s3fs-fuse 但遇到性能瓶颈(尤其是并发读写)
  • ✅ 需要多客户端共享写入(s3fs-fuse 无锁机制)
  • ✅ 生产环境需要 AWS 托管服务的可靠性和支持

暂不迁移

  • ❌ 依赖写入后立即在 S3 可见(S3 Files 有 ~60s 延迟)
  • ❌ 使用非 AWS S3 兼容存储(MinIO 等)
  • ❌ 成本敏感且性能需求不高

参考链接