一段前情#
2024 年底 MinIO 团队做了一次引发社区热议的调整:把 Web 控制台的很多功能迁到了商业版 AIStor、对 Console UI 做了简化、对社区版的支持承诺变得模糊。这件事对正在跑 MinIO 的团队是个警示——开源软件的长期稳定性并不是理所当然的。
尽管如此,MinIO 仍然是目前自建对象存储的最优选:代码成熟、协议兼容、性能优秀、Operator 完善。这篇文章是我在三套生产 MinIO 集群(最大 16 节点 192TB 裸容量)上的运维笔记,既讲技术也讲一些选型上的思考。
文章基于 MinIO RELEASE.2024-09-13T20-26-02Z 之后的版本(注意这是社区版时间节点,更新的版本各家情况不一)。
一、Erasure Code:MinIO 的核心#
1.1 为什么不是副本#
对象存储的持久性方案主要两种:
- 多副本:数据复制 N 份,空间占用 N 倍
- Erasure Code:数据切成 K 份,编码成 K+M 份,允许丢 M 份
Erasure Code 的数学基础是 Reed-Solomon 编码。对一个对象:
- 切成 K 个数据块
- 计算 M 个校验块(parity)
- 总共 K+M 个块分布到不同磁盘
- 只要 ≥ K 个块存活就能恢复原数据
空间效率是 K / (K+M)。比如 EC:4+2 的空间效率是 66%(4 数据 + 2 校验),EC:8+4 的是 66%(8+4),EC:12+4 的是 75%。相比三副本的 33%,EC 的空间效率高得多。
MinIO 用 Reed-Solomon 实现 EC,支持每 erasure set 2-16 个 drive。
1.2 Erasure Set:数据放置单元#
Erasure Set 是 MinIO 的核心概念:它把你提供的所有 drive 分成若干个 set,每个 set 内部独立做 EC 编码。
例子:16 个节点、每节点 8 drive = 128 drive 的集群,可能被分成:
- 8 个 Set,每个 Set 16 drive(8 节点各出 2 drive)
- Set 内做 EC:12+4(12 数据、4 校验)
- 每个对象只在自己所属的 set 内切分
- 不同 set 之间独立,故障隔离
MinIO 自动决定 erasure set 大小,你可以通过 MINIO_ERASURE_SET_DRIVE_COUNT 手动指定(16、12、8 等)。
1.3 Storage Class:读写的容错策略#
MinIO 内置两种 storage class:
STANDARD: EC 默认校验块数,通常 4
REDUCED_REDUNDANCY: 较少校验块数,通常 2
配置:
export MINIO_STORAGE_CLASS_STANDARD="EC:4"
export MINIO_STORAGE_CLASS_RRS="EC:2"
EC:4 表示 4 个校验块。举个实际例子:
- 集群有 16 drive 的 erasure set
- STANDARD = EC:4 → 16 - 4 = 12 数据块,能容忍丢 4 drive
- RRS = EC:2 → 16 - 2 = 14 数据块,能容忍丢 2 drive
上传时指定:
aws s3 cp file.bin s3://bucket/ --storage-class REDUCED_REDUNDANCY
RRS 比 STANDARD 存储空间省 10-15%,代价是容错能力降低。适合归档、日志等可重建的数据。
二、硬件与拓扑选型#
2.1 节点数与 Drive 数#
MinIO 官方推荐:
- 最少 4 节点(能做 EC:2)
- 推荐 4-8 节点(成本/性能/容错平衡)
- 每节点 4-16 drive
- drive 尽量同型号同容量
为什么 drive 同型号很重要:MinIO 在 set 内按 drive 数量均分,容量不同会导致最小 drive 先写满、整个 set 拒写入。
2.2 CPU/内存/网络#
官方建议(每节点):
| 资源 | 最小 | 推荐 | 高性能 |
|---|---|---|---|
| CPU | 8 核 | 16 核 | 32 核 |
| 内存 | 32GB | 64GB | 128GB |
| 网络 | 10Gbps | 25Gbps | 100Gbps |
实测:EC 编码本身不吃 CPU,单核就能跑满 25Gbps。真正吃资源的是:
- TLS 加密:吃 CPU,有 AES-NI 的 CPU 能显著加速
- Scrubber 后台任务:定期校验数据完整性,占 10-20% CPU
- 内存:对象元数据缓存、multipart upload 缓存
2.3 磁盘选型#
| 磁盘类型 | 适用场景 | 性价比 |
|---|---|---|
| NVMe SSD | 高性能热数据 | 贵 |
| SATA SSD | 通用 | 中 |
| HDD 企业盘 | 冷数据、归档 | 好 |
| HDD SMR | 不要用 | 便宜但坑 |
SMR(叠瓦式)磁盘对随机写是灾难,MinIO 的后台 scrubber 和删除操作会把 SMR 性能打到地板。
文件系统推荐 XFS,比 EXT4 对大文件和高并发更友好:
mkfs.xfs -L data /dev/nvme1n1
mount -o noatime,nodiratime,largeio,swalloc,allocsize=131072k /dev/nvme1n1 /mnt/data1
noatime 避免每次读都更新访问时间,allocsize 提前预分配减少碎片。
2.4 网络拓扑#
MinIO 节点间通信量大,尤其是写入和 rebalance 期间。网络建议:
- 单网段部署:节点之间 < 1ms 延迟
- 不要跨机房:MinIO 不是为跨机房单集群设计的,跨机房用 site replication
- Jumbo Frame:MTU 9000 能提升大对象吞吐 5-10%
三、一个 4 节点 × 4 drive 的生产部署#
以 16 drive 的典型部署为例,完整配置示范:
3.1 systemd 单元#
/etc/systemd/system/minio.service:
[Unit]
Description=MinIO
After=network-online.target
[Service]
WorkingDirectory=/usr/local
User=minio-user
Group=minio-user
ProtectProc=invisible
EnvironmentFile=/etc/default/minio
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
Restart=always
LimitNOFILE=1048576
LimitMEMLOCK=infinity
LimitNPROC=1048576
TasksMax=infinity
TimeoutStopSec=infinity
SendSIGKILL=no
[Install]
WantedBy=multi-user.target
/etc/default/minio:
MINIO_ROOT_USER=minio-admin
MINIO_ROOT_PASSWORD="use-a-long-random-password-at-least-20-chars"
# 4 个节点,每个节点 4 个 drive,注意 hostname 要能解析
MINIO_VOLUMES="https://minio-{1...4}.example.com:9000/mnt/data{1...4}"
MINIO_OPTS="--address :9000 --console-address :9001"
MINIO_REGION_NAME=cn-north-1
MINIO_BROWSER=on
MINIO_PROMETHEUS_AUTH_TYPE=public
MINIO_PROMETHEUS_URL=http://prometheus:9090
# TLS
MINIO_SERVER_URL=https://minio.example.com
启动:
systemctl daemon-reload
systemctl enable --now minio
3.2 访问验证#
# mc 是 MinIO 的 CLI
mc alias set myminio https://minio.example.com minio-admin "password"
mc admin info myminio
输出:
● minio-1:9000
Uptime: 2 days
Version: RELEASE.2024-09-13T20-26-02Z
Network: 4/4 OK
Drives: 4/4 OK
Pool: 1
...
4 drives online, 0 drives offline, EC:4
看到 EC:4 就表示 erasure code 已经生效,能容忍 4 个 drive 故障。
四、Bucket 管理与策略#
4.1 基础操作#
# 创建 bucket
mc mb myminio/logs
mc mb myminio/backups
# 设置访问策略
mc anonymous set download myminio/public-assets # 只读公开
mc anonymous set none myminio/backups # 完全私有
4.2 Bucket Policy#
更细粒度的 IAM:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": ["arn:aws:iam::*:user/app-reader"] },
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::logs/*"]
},
{
"Effect": "Allow",
"Principal": { "AWS": ["arn:aws:iam::*:user/app-writer"] },
"Action": ["s3:PutObject", "s3:GetObject"],
"Resource": ["arn:aws:s3:::logs/*"]
}
]
}
mc admin policy create myminio reader-policy reader.json
mc admin user add myminio app-reader "secret"
mc admin policy attach myminio reader-policy --user app-reader
4.3 Versioning 和 Object Lock#
版本控制对防误删非常有用:
mc version enable myminio/critical-data
# 恢复误删对象
mc ls --versions myminio/critical-data/file.bin
mc cp myminio/critical-data/file.bin?versionId=xxx myminio/critical-data/file.bin
Object Lock(对象锁)做 WORM 存储,合规场景必备:
# 创建 bucket 时启用
mc mb --with-lock myminio/compliance-logs
# 设置保留策略(1 年不可删除)
mc retention set --default GOVERNANCE 1y myminio/compliance-logs
Governance 模式下特权用户能强制删除、Compliance 模式下任何人都不能删(包括 root)。合规场景用 Compliance。
4.4 Lifecycle Rules#
自动过期和降级:
{
"Rules": [
{
"ID": "archive-old-logs",
"Status": "Enabled",
"Filter": { "Prefix": "logs/" },
"Expiration": { "Days": 90 }
},
{
"ID": "transition-to-rrs",
"Status": "Enabled",
"Filter": { "Prefix": "data/" },
"Transition": { "Days": 30, "StorageClass": "REDUCED_REDUNDANCY" }
}
]
}
mc ilm import myminio/mybucket < lifecycle.json
自动降级到 RRS 能省 10-15% 空间,对冷数据划算。
五、Site Replication:跨集群复制#
MinIO 的跨集群方案叫 Site Replication,把多个 MinIO cluster 组成一个"逻辑站点组",数据、配置、IAM 都同步。
# 先分别部署两个 MinIO 集群
mc alias set site1 https://site1.example.com admin pw
mc alias set site2 https://site2.example.com admin pw
# 建立 replication
mc admin replicate add site1 site2
# 检查状态
mc admin replicate info site1
mc admin replicate status site1
注意:
- 所有 site 必须版本一致
- 第一个加入的 site 的数据会被复制到其他 site
- 后加入的 site 原数据会被清空(慎重!)
- IAM、bucket policy、lifecycle 都会同步
Site Replication 是 active-active,所有 site 都可写。适合跨机房灾备。
六、监控与告警#
6.1 Prometheus Metrics#
MinIO 内置 Prometheus endpoint:
curl http://minio-1:9000/minio/v2/metrics/cluster
curl http://minio-1:9000/minio/v2/metrics/node
curl http://minio-1:9000/minio/v2/metrics/bucket
核心指标:
| 指标 | 说明 |
|---|---|
| minio_cluster_drive_offline | 离线磁盘数 |
| minio_cluster_nodes_offline | 离线节点数 |
| minio_bucket_usage_object_total | bucket 对象数 |
| minio_bucket_usage_total_bytes | bucket 总容量 |
| minio_s3_requests_errors_total | S3 错误请求数 |
| minio_s3_requests_ttfb_seconds_distribution | 首字节延迟 |
| minio_cluster_health | 集群健康评分 |
6.2 告警规则#
groups:
- name: minio
rules:
- alert: MinIODriveOffline
expr: minio_cluster_drive_offline > 0
for: 1m
annotations:
summary: "MinIO cluster {{ $labels.instance }} has {{ $value }} offline drives"
- alert: MinIONodeOffline
expr: minio_cluster_nodes_offline > 0
for: 30s
labels:
severity: critical
- alert: MinIOCapacityHigh
expr: minio_cluster_capacity_usable_free_bytes / minio_cluster_capacity_usable_total_bytes < 0.15
for: 5m
annotations:
summary: "MinIO available capacity < 15%"
- alert: MinIOHighErrorRate
expr: rate(minio_s3_requests_errors_total[5m]) > 10
for: 5m
- alert: MinIOReplicationFailing
expr: minio_cluster_replication_last_minute_failed_count > 100
for: 10m
6.3 Scrubber 健康#
MinIO 会定期跑 scrubber(叫 heal),校验数据完整性:
mc admin heal --recursive myminio
mc admin heal --recursive --dry-run myminio # 只报告不修复
生产建议每周至少跑一次 dry-run,发现有 heal 需要再做真实修复。
七、扩容:Pool 模型#
MinIO 的扩容机制是 server pool:添加新的 pool(一组节点和 drive),新 pool 和旧 pool 并列,新对象写入时按容量权重选 pool。
MINIO_VOLUMES="https://minio-{1...4}.example.com:9000/mnt/data{1...4} \
https://minio-{5...8}.example.com:9000/mnt/data{1...4}"
重启所有节点后,MinIO 会识别出 2 个 pool。新 pool 承担部分写入压力,最终达到容量比例均衡。
注意:
- 每个 pool 必须满足最小 drive 数要求(通常 4)
- 不同 pool 可以 EC 配置不同,灵活但复杂
- rebalance 是可选的:默认不自动 rebalance,只在写入时均衡,要主动 rebalance 用
mc admin rebalance start - decommission 缩容:
mc admin decommission start myminio http://minio-{1...4}:9000/mnt/data{1...4}把老 pool 数据迁到新 pool
rebalance 和 decommission 都会占用大量 IO 和网络,建议在低峰跑。
八、真实故障复盘#
8.1 同型号 SSD 批次性故障#
现象:某天凌晨告警:drive offline,登上去看发现 4 个节点上 1 块 NVMe 同时离线。
排查:这 4 块盘是同一批次、同一时间买入、同一时间压力相同。达到设计寿命 SSD 有概率同时失效。EC:4 的配置下正好容忍 4 块盘故障,数据没丢。
修复:
- 紧急换盘
- MinIO 自动 heal 开始重建数据
- 监控 heal 进度:
mc admin heal --recursive
教训:
- 买盘分批次、分厂家,别"一次订一整箱"
- EC:4 是底线,没它这次就数据丢失了
- 长期:给 SSD 监控
smart_attribute_wearout(磨损度)指标,提前换盘
8.2 大对象上传 OOM#
现象:应用上传一个 50GB 视频文件,MinIO 节点 OOM 重启。
根因:应用没用 multipart upload,直接 PUT 50GB,MinIO 尝试全部读入内存。
修复:应用改用 multipart:
# 用 boto3 的 multipart
s3.upload_file(
local_path, 'bucket', 'key',
Config=boto3.s3.transfer.TransferConfig(
multipart_threshold=64 * 1024 * 1024, # 64MB 开始分片
multipart_chunksize=64 * 1024 * 1024,
max_concurrency=10
)
)
MinIO 侧可以设置 MINIO_API_REQUESTS_MAX 限制并发请求,给大对象上传预留资源。
8.3 误删 bucket 数据#
现象:开发同学跑了一条 mc rm --recursive --force myminio/prod-data,20 万对象瞬间没了。
根因:生产 bucket 没开 versioning。
恢复:从快照恢复(好在 EBS 底层有每日快照),丢了 3 小时数据。
教训:
- 所有生产 bucket 必须开 versioning
- 关键 bucket 加 Object Lock(合规模式)
- 限制 mc 权限:生产集群不给
s3:DeleteBucket权限,强制经过 IaC - 审计日志要开:
mc admin trace myminio能看到所有请求
九、关于 MinIO 商业化的一些思考#
2024 年底 MinIO Inc 把很多控制台功能迁到了商业版 AIStor,这对社区版用户意味着:
- 核心存储功能还在开源:分布式、EC、S3 兼容没变
- 控制台功能受限:用户管理、策略 UI、某些监控面板只在商业版有
- 文档分裂:docs.min.io 上能看到 AIStor 和社区版混在一起,容易误导
我的建议:
- 已经跑生产的集群:继续用,锁定版本,做好监控
- 新项目:评估一下是直接上 MinIO 还是考虑其他方案(Garage、SeaweedFS、Ceph RGW)
- 大规模商业场景:考虑付费 AIStor 或者云服务商托管对象存储
替代方案简单对比:
| 方案 | 优点 | 缺点 |
|---|---|---|
| MinIO | 成熟、性能好 | 商业化方向不明 |
| Garage | Rust 写、简单 | 功能少、生态弱 |
| SeaweedFS | 功能全、文件存储兼顾 | 复杂、坑多 |
| Ceph RGW | 真·企业级 | 运维成本极高 |
十、经验法则#
- Erasure Code 参数早期定死:EC:2 最低、EC:4 推荐
- drive 同型号同批次是大忌:分散故障概率
- XFS + noatime + 大 allocsize:文件系统优化能提升 10-20%
- Pool 是扩容单位:提前规划别贪便宜
- Versioning + Object Lock 是保命符:所有生产 bucket 默认开
- Site Replication 做跨机房:不要想着单集群跨机房
- Scrubber 每周跑:数据完整性校验是必需
- 监控 drive/pool/bucket 三层指标
- 版本选 LTS 风格的稳定点,不要追最新
MinIO 这个产品做对了一件事:把"自建对象存储"这件以前只能交给 Ceph 这种重型方案的事,变成了几乎任何团队都能跑的能力。即便商业化这一步走得不漂亮,核心引擎仍然值得信任。
参考资料:
- MinIO 官方
docs.min.io,注意区分 Community 和 AIStor 两套文档 - MinIO GitHub 仓库里的
docs/distributed/DESIGN.md和docs/erasure/README.md - Reed-Solomon 编码的数学背景(维基百科已经足够)
- MinIO Blog 的 Erasure Code Calculator 系列






