如果你也用过 AWS S3、MinIO 或者 LocalStack,那你一定知道:这些工具虽然功能强大,但动辄几十 MB 的二进制文件、上百 MB 的内存占用、成百上千的依赖项,常常让人“又爱又恨”。尤其是本地开发调试时,光是启动 MinIO 就得等上好几秒,更别说 CI/CD 流水线里还要拉个 Docker 镜像……
但最近,GitHub 上一个叫 zs3[^1] 的项目火了——它用 不到 1400 行 Zig 代码,实现了 完整的 S3 兼容协议,零依赖,编译后只有 250KB,内存占用 2MB 起步,性能还比同类工具快 几十倍!
今天,咱们就来深入解析这个“小而美”的项目,看看它是如何做到的,并探讨我们能否在实际场景中应用它。
一、S3 协议的核心与重量级实现的困境
在深入了解 zs3 之前,我们需要先明确一点:S3 到底是什么?
简单来说,Amazon S3 是一个通过 HTTP API 进行文件存取的对象存储服务。其最核心的操作无非以下几个:
PUT:上传文件
GET:下载文件
DELETE:删除文件
LIST:列出文件(支持前缀、分页)
HEAD:获取元信息
DeleteObjects:批量删除
再加上一套 身份认证机制(SigV4),就覆盖了日常开发中 95% 以上的使用场景。
然而,为了支持企业级需求,如版本控制、生命周期策略等,主流实现(如 MinIO)的代码量已膨胀至 20 万行以上,二进制文件超过 100MB,启动即占用 200MB+ 内存。
这就像你只想煮碗泡面,却不得不启动一整套复杂的商用厨房设备。
zs3 的作者一针见血地指出:“大多数 S3 使用场景不过是带基础认证的 PUT、GET、DELETE、LIST,为此你根本不需要 20 万行代码。”
于是,他选择用 Zig 这门新兴的系统编程语言,打造了一个极简版的 S3 服务——仅用 1400 行代码,就实现了所有核心功能。
二、为什么 Zig 语言能实现如此极致的轻量?
zs3 的“轻”很大程度上源于其语言选型:Zig。
Zig 的设计哲学是“无运行时、无垃圾回收、无隐藏分配、无意外依赖”。它追求的是极致的透明与可控:你的代码编译后就是系统调用本身,几乎没有额外开销。
例如,用 Zig 编写一个 HTTP 服务器,最终的二进制文件除了你的逻辑和必要的系统调用外,没有任何额外的运行时库或垃圾回收器。没有 libc(除非显式链接),没有黑魔法。
这带来了两大优势:
- 极致轻量:zs3 编译后仅 250KB,甚至小于一张普通的高清图片。
- 极致可控:每一行代码的行为都清晰可预测,没有难以追踪的隐藏开销。
相比之下,Rust 项目通常依赖大量第三方 crate,Go 语言则自带完整的运行时和 GC。而 Zig 项目,往往只需要一个 build.zig 构建文件,就能实现零依赖编译。
三、zs3 的能力边界:能做什么,不能做什么?
明确一个工具的定位,是正确使用它的前提。
✅ 它能做的(核心功能全支持):
- 完整 SigV4 认证:完全兼容
aws-cli、boto3 等所有官方 SDK。
- 标准 S3 操作:
PUT、GET、DELETE、HEAD、LIST(v2)。
- 批量删除:
DeleteObjects。
- 大文件分片上传:支持 Multipart Upload(含断点续传)。
- Range 请求:支持视频流、文件分段下载(如
curl -r 0-1000)。
- 超小体积:250KB 的静态二进制,随处可运行。
❌ 它不能做的(作者明确划清边界):
- 版本控制(Versioning)
- 生命周期策略(Lifecycle)
- 桶 ACL / 对象标签 / 加密
- 预签名 URL(Presigned URLs)
- 多租户隔离
- 高可用 / 分布式存储
作者的立场很明确:“如果你需要这些功能,请使用 MinIO 或 AWS。” 因此,zs3 的定位并非生产级替代品,而是面向开发、测试、CI/CD及嵌入式场景的“瑞士军刀”。
四、快速上手:五分钟内搭建本地 S3 环境
zs3 的使用方式简单到极致。
第一步:安装 Zig(0.15+)
# macOS (Homebrew)
brew install zig
# Linux (从官网下载)
wget https://ziglang.org/download/0.15.0/zig-linux-x86_64-0.15.0.tar.xz
tar -xf zig-linux-x86_64-0.15.0.tar.xz
sudo mv zig-linux-x86_64-0.15.0 /opt/zig
echo 'export PATH=/opt/zig:$PATH' >> ~/.bashrc
第二步:编译 zs3
git clone https://github.com/Lulzx/zs3
cd zs3
zig build -Doptimize=ReleaseFast
编译生成的二进制位于 ./zig-out/bin/zs3,大小约 250KB。
第三步:启动服务
./zig-out/bin/zs3
服务默认监听 0.0.0.0:9000,所有数据将存储在当前目录的 ./data 文件夹下。
第四步:使用 aws-cli 进行操作
# 设置访问凭证(默认为 minioadmin/minioadmin)
export AWS_ACCESS_KEY_ID=minioadmin
export AWS_SECRET_ACCESS_KEY=minioadmin
# 创建存储桶
aws --endpoint-url http://localhost:9000 s3 mb s3://mybucket
# 上传文件
aws --endpoint-url http://localhost:9000 s3 cp file.txt s3://mybucket/
# 列出文件
aws --endpoint-url http://localhost:9000 s3 ls s3://mybucket/ --recursive
# 下载文件
aws --endpoint-url http://localhost:9000 s3 cp s3://mybucket/file.txt ./
# 删除文件
aws --endpoint-url http://localhost:9000 s3 rm s3://mybucket/file.txt
完全兼容! 使用体验与真实的 S3 服务无异。
五、技术亮点剖析:极简设计的智慧
zs3 最令人称道的是其清晰而高效的设计哲学。
1. SigV4 认证:150 行代码的优雅实现
AWS 的 SigV4 签名机制听起来复杂,但逻辑清晰:
- 构造“规范请求”。
- 生成“待签名字符串”。
- 使用密钥进行分层 HMAC-SHA256 计算。
- 比对客户端与服务端计算的签名。
zs3 用 大约 150 行代码 纯手工实现了整个流程,没有引入任何第三方加密库。正如作者所说:“没有魔法。” 看完代码你会发现,协议本身并不复杂,只是官方文档的表述方式增加了理解成本。
2. 存储模型:文件系统即对象存储
zs3 的存储设计直接而透明:s3://mybucket/folder/file.txt 直接对应文件系统路径 ./data/mybucket/folder/file.txt。
这意味着:
- 你可以直接用
ls ./data 查看所有桶和文件。
- 可以手动用
cp 命令复制文件进去,客户端立即可见。
- 删除文件等同于执行
rm 命令。
- 备份数据只需打包整个
./data 目录。
这种“透明存储”极大降低了心智负担,你不需要理解抽象的对象存储模型——它就是你硬盘上的一个文件夹。当然,这也意味着它没有元数据索引、事务或强一致性保证,但对于本地开发场景,这已经足够了。
六、性能表现:极简设计带来的速度飞跃
zs3 在 README 中展示的基准测试数据非常惊人:
| 操作 |
zs3 |
RustFS |
性能提升 |
| PUT 1KB |
0.46ms |
12.57ms |
27倍 |
| GET 1MB |
0.43ms |
53.22ms |
124倍 |
| LIST |
0.86ms |
462ms |
537倍 |
LIST 操作快了超过 500 倍!
原因很简单:为了支持复杂功能,重型实现构建了多层抽象、缓存和权限检查。而 zs3 的 LIST 操作基本上是 直接调用 readdir + stat 系统调用,虽然粗暴,但极其高效。
在 50 个并发 worker、1000 个请求的测试中:
- zs3 吞吐量:5000+ req/s
- RustFS 吞吐量:174 req/s
存在近 30 倍的差距! 这并非说明 RustFS 不好,它面向的是功能完备的生产环境。但 zs3 有力地证明了一点:在简单明确的场景下,极简的设计就是最高的性能。
七、适用与不适用场景分析
✅ 推荐使用场景:
- 本地开发:替代 LocalStack 或 MinIO,秒级启动,资源占用极低。
- CI/CD 流水线:作为临时构建产物(artifact)的存储,无需启动 Docker 容器。
- 个人/家庭备份:在 NAS 上运行,用于存储照片、文档等。
- 嵌入式/资源受限环境:路由器、工控机等。
- 学习 S3 协议:通过 1400 行清晰易懂的源码分析,比阅读厚重的官方文档更直观。
❌ 绝对不要用于:
- 生产环境(尤其对外网暴露):它不支持 TLS、多用户隔离和审计日志。
- 需要高数据持久性保证的场景:它只是简单写入本地磁盘,无任何冗余机制。
- 需要高级 S3 功能的场景:如预签名 URL、服务端加密、事件通知等。
记住:zs3 是一把锋利的瑞士军刀,适合特定场景下的精细操作,而非抵御冲击的盾牌。
八、安全考量与已知限制
zs3 并非毫无防护:
- 所有请求均经过 SigV4 签名验证。
- 对桶名和对象键进行了 严格校验,防止路径遍历攻击。
- 对请求头和 Body 大小进行了限制,以防止 DoS 攻击。
- 实现中 无 Shell 执行、无 eval、无外部网络调用。
但它 原生不支持 TLS。作者的建议是:通过 Nginx 或 Caddy 等反向代理为其添加 HTTPS 支持。
其他一些合理的限制包括:
- 最大请求头:8KB
- 最大请求体:5GB
- 对象键最大长度:1024 字节
- 桶名规则:3-63 个字符,符合 DNS 命名规范
这些限制对于绝大多数开发和测试场景来说已经足够。
九、如何定制化修改?
想要更改端口、密钥或数据目录?非常简单。
打开 main.zig 文件,找到如下配置部分:
const ctx = S3Context{
.allocator = allocator,
.data_dir = "data", // ← 修改数据目录
.access_key = "minioadmin", // ← 修改访问密钥
.secret_key = "minioadmin", // ← 修改秘密密钥
};
const address = net.Address.parseIp4("0.0.0.0", 9000); // ← 修改监听地址和端口
修改后,重新执行 zig build 即可。没有繁琐的配置文件,没有环境变量解析,一切配置都明明白白地写在代码里。这再次体现了其极简但高度可控的设计理念。
十、结语:在复杂世界中拥抱简单
在这个普遍追求“大而全”的时代,zs3 项目像一股清流,提醒我们“少即是多”的朴素真理。它通过对 System Design 核心需求的精准把握和 Zig 语言特性的巧妙运用,创造了一个在特定场景下无比高效的工具。
项目地址:https://github.com/Lulzx/zs3
开源协议:WTFPL
对于开发者而言,无论是将其用作提升效率的本地工具,还是作为一个学习极简系统编程和网络协议实现的优秀范本,zs3 都具有很高的价值。希望这篇文章能帮助你更好地理解和运用它。如果你想了解更多类似的优质项目或技术解析,欢迎访问 云栈社区 进行交流与探索。
[^1]: zs3 项目地址: https://github.com/Lulzx/zs3