跳过正文
MinIO 分布式对象存储生产实践:从 Erasure Code 到多租户

MinIO 分布式对象存储生产实践:从 Erasure Code 到多租户

·1181 字·6 分钟·
目录

一段前情
#

2024 年底 MinIO 团队做了一次引发社区热议的调整:把 Web 控制台的很多功能迁到了商业版 AIStor、对 Console UI 做了简化、对社区版的支持承诺变得模糊。这件事对正在跑 MinIO 的团队是个警示——开源软件的长期稳定性并不是理所当然的。

尽管如此,MinIO 仍然是目前自建对象存储的最优选:代码成熟、协议兼容、性能优秀、Operator 完善。这篇文章是我在三套生产 MinIO 集群(最大 16 节点 192TB 裸容量)上的运维笔记,既讲技术也讲一些选型上的思考。

文章基于 MinIO RELEASE.2024-09-13T20-26-02Z 之后的版本(注意这是社区版时间节点,更新的版本各家情况不一)。

一、Erasure Code:MinIO 的核心
#

1.1 为什么不是副本
#

对象存储的持久性方案主要两种:

  1. 多副本:数据复制 N 份,空间占用 N 倍
  2. 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/内存/网络
#

官方建议(每节点):

资源最小推荐高性能
CPU8 核16 核32 核
内存32GB64GB128GB
网络10Gbps25Gbps100Gbps

实测:EC 编码本身不吃 CPU,单核就能跑满 25Gbps。真正吃资源的是:

  1. TLS 加密:吃 CPU,有 AES-NI 的 CPU 能显著加速
  2. Scrubber 后台任务:定期校验数据完整性,占 10-20% CPU
  3. 内存:对象元数据缓存、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

注意:

  1. 所有 site 必须版本一致
  2. 第一个加入的 site 的数据会被复制到其他 site
  3. 后加入的 site 原数据会被清空(慎重!)
  4. 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_totalbucket 对象数
minio_bucket_usage_total_bytesbucket 总容量
minio_s3_requests_errors_totalS3 错误请求数
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 承担部分写入压力,最终达到容量比例均衡。

注意:

  1. 每个 pool 必须满足最小 drive 数要求(通常 4)
  2. 不同 pool 可以 EC 配置不同,灵活但复杂
  3. rebalance 是可选的:默认不自动 rebalance,只在写入时均衡,要主动 rebalance 用 mc admin rebalance start
  4. 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 块盘故障,数据没丢。

修复

  1. 紧急换盘
  2. MinIO 自动 heal 开始重建数据
  3. 监控 heal 进度:mc admin heal --recursive

教训

  1. 买盘分批次、分厂家,别"一次订一整箱"
  2. EC:4 是底线,没它这次就数据丢失了
  3. 长期:给 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 小时数据。

教训

  1. 所有生产 bucket 必须开 versioning
  2. 关键 bucket 加 Object Lock(合规模式)
  3. 限制 mc 权限:生产集群不给 s3:DeleteBucket 权限,强制经过 IaC
  4. 审计日志要开mc admin trace myminio 能看到所有请求

九、关于 MinIO 商业化的一些思考
#

2024 年底 MinIO Inc 把很多控制台功能迁到了商业版 AIStor,这对社区版用户意味着:

  1. 核心存储功能还在开源:分布式、EC、S3 兼容没变
  2. 控制台功能受限:用户管理、策略 UI、某些监控面板只在商业版有
  3. 文档分裂:docs.min.io 上能看到 AIStor 和社区版混在一起,容易误导

我的建议:

  • 已经跑生产的集群:继续用,锁定版本,做好监控
  • 新项目:评估一下是直接上 MinIO 还是考虑其他方案(Garage、SeaweedFS、Ceph RGW)
  • 大规模商业场景:考虑付费 AIStor 或者云服务商托管对象存储

替代方案简单对比:

方案优点缺点
MinIO成熟、性能好商业化方向不明
GarageRust 写、简单功能少、生态弱
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.mddocs/erasure/README.md
  • Reed-Solomon 编码的数学背景(维基百科已经足够)
  • MinIO Blog 的 Erasure Code Calculator 系列
Wenzhuo Huang
作者
Wenzhuo Huang
搞运维的工程师,写代码的运维人。专注 Kubernetes、AWS、GitOps 与基础设施可靠性。这个博客既是我的技术笔记本,也是我踩过的坑的受害者档案。

相关文章

Python 异步编程实战:asyncio 在 AI 应用中的使用

·1613 字·8 分钟
AI 应用天然是 I/O 密集型的:等 LLM 响应、等向量数据库检索、等多个工具调用返回。同步写法在这里是性能杀手。这篇文章从 event loop 原理讲到实际的 AI 应用模式,重点是 asyncio.gather 并发调用、SSE 流式输出处理和常见陷阱排查。

MongoDB 分片集群实战:从 shard key 设计到 chunk 均衡的全链路

·1406 字·7 分钟
很多团队把 MongoDB 分片当成"设个 shard key 就完事",结果上线半年后发现 80% 数据在一个 shard 上、balancer 每天搬几十 GB 却怎么都追不上、某个 collection 出现 jumbo chunk 无法分裂。这篇文章把我在几套 MongoDB 分片集群上的经验整理出来,希望能让你在分片之前少走一些弯路。