部署与高可用
从单机到分布式
单机版跑通之后,生产要考虑的事情立刻变成三件:容量不够了怎么办、一块盘坏了数据还在不在、一台机器挂了服务还能不能用。MinIO 的答案是同一个:分布式模式。
分布式模式和单机模式的差别,不是「多起几个进程」,而是:
- 所有节点共用同一个对象命名空间,客户端连任意节点都能访问全部数据;
- 每个对象被切成纠删码分片,分散在多个节点上,节点故障时靠其他节点的分片重建;
- 集群状态通过节点间通信维护,没有中心元数据节点,也就不存在元数据单点。
拓扑规划
最小可用形态
官方推荐、也是最常见的起点是 4 节点 × 4 盘 = 16 块盘,正好组成一个 16 盘的纠删码集合,默认 EC:4:
| 部署规模 | 拓扑 | 纠删码集合 | 可用容量比 | 可容忍故障 |
|---|---|---|---|---|
| 开发验证 | 1 节点 4 盘 | 4 盘 1 集合 | 50% | 2 块盘 |
| 最小生产 | 4 节点 4 盘 | 16 盘 1 集合 | 75% | 4 块盘 / 1 个节点 |
| 中等规模 | 8 节点 4 盘 | 2 个 16 盘集合 | 75% | 每集合 4 块盘 |
| 大规模 | 16 节点 8 盘 | 8 个 16 盘集合 | 75% | 每集合 4 块盘 |
注意最后两行的差别:集合是独立的,一个集合坏 4 块盘只影响这个集合里的对象,其他集合照常工作;但单个集合丢超过 4 块盘,这部分数据就永久丢失了。
硬性约束
规划阶段有几条不能违背的规则,违反了下场都很惨:
- 至少 4 块盘才能启用纠删码;少于 4 块只能用单机单盘模式,没有冗余。
- 节点数、每节点盘数尽量取偶数,集合划分更规整,扩容时也好算。
- 同一池内的盘要同类型、同容量:MinIO 会把每块盘的可用容量限制为池内最小盘,混插一块小盘等于全体缩水。
- 不要用 RAID:MinIO 自己就是冗余层,RAID 会隐藏磁盘故障,还会让纠删码分片分布失真。盘要直通(JBOD/HBA 直通模式)。
- 不要用 NAS/SAN/NFS:网络存储的延迟和一致性保证撑不住纠删码的读写仲裁。
- 文件系统用 XFS,挂载点连续编号(
/mnt/disk1到/mnt/disk4)。
MinIO 要求对磁盘有独占访问权。不要在数据盘上放别的东西,更不要写脚本去移动、修改、删除盘上的分片文件或 xl.meta 元数据——这些操作会绕过 MinIO 的校验,直接造成不可恢复的损坏。迁移数据只能用 mc mirror 这类 S3 层面的工具。
容量怎么算
原始容量乘上纠删码效率,再打一个安全余量:
可用容量 = 节点数 × 每节点盘数 × 单盘容量 × (K / N)
= 4 × 4 × 4TiB × (12 / 16) = 48TiB
再留 30% 余量应对突发增长和后台扫描,实际可写入量大约 33TiB。MinIO 官方建议一次性规划至少两年的容量,并在使用率达到 70% 之前完成扩容准备——频繁小步扩容通常说明规划没做好。
分布式部署
前置准备
每台节点都要做:
# 主机名和 hosts 解析(没有内部 DNS 时手工写)
# 192.168.10.11 minio1.example.net
# 192.168.10.12 minio2.example.net
# 192.168.10.13 minio3.example.net
# 192.168.10.14 minio4.example.net
sudo hostnamectl set-hostname minio1.example.net
# 时间同步、XFS 数据盘、独立服务账号,和单机部署完全一样
sudo systemctl enable --now chrony
sudo mkfs.xfs -f /dev/vdb
sudo mkdir -p /mnt/disk1 && sudo mount /dev/vdb /mnt/disk1
四台机器之间必须双向网络可达,防火墙放通 9000 端口(节点间通信也走这个端口)。所有节点必须使用相同的监听端口,这是硬性要求。
环境变量文件
每个节点的 /etc/default/minio 内容完全一致,区别只在数据盘路径(如果各节点盘符相同则连路径也一样):
# /etc/default/minio(四个节点内容一致)
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=ChangeMe-Str0ng-Pass
# 扩展写法:minio1 到 minio4,每台 4 块盘
MINIO_VOLUMES="https://minio{1...4}.example.net:9000/mnt/disk{1...4}/minio"
MINIO_OPTS="--console-address :9001"
https 表示启用 TLS,证书配好后才能用;先用 http 验证通了再换 https 也可以。
启动
四个节点要几乎同时启动,不要滚动启动:
# 在每台机器上执行(或用 ansible/pssh 并发执行)
sudo systemctl daemon-reload
sudo systemctl enable minio
sudo systemctl start minio
MinIO 的写操作需要跨节点仲裁,滚动重启(一台一台来)会让集群反复进出「降级」状态,极端情况下触发写拒绝。升级、改配置、扩容,都应该所有节点同时重启。MinIO 的读写是原子的,同时重启不会丢数据。
验证:
mc alias set cluster https://minio1.example.net:9000 admin 'ChangeMe-Str0ng-Pass'
mc admin info cluster
输出里确认:Servers 是 4 个且全部 online,Drives 是 16 块且全部 online,Usage 和 Capacity 有正常数值。管理命令连任意一个节点都可以。
数据路由与一致性哈希
理解数据怎么分布,才能理解扩容和故障时的行为。
MinIO 对每个对象的完整命名空间(BUCKET/PREFIX/OBJECT,含版本)算一个确定性的哈希,据此选定服务器池,再选定池内的纠删码集合。这就是「一致性哈希」的思路:同一个对象永远映射到同一个位置,不需要中心元数据表去记录「它在哪」。
多池部署时,写入还会按各池的空闲空间比例加权——空闲多的池分到更多新对象。对象落在哪个池,写完之后就记在对象的元数据里,后续读请求以元数据为准,不会因为池的权重变了就找不到数据。
这带来几个直接结论:
- 任意节点都能处理任意请求:客户端连谁都可以,节点内部会转发到正确的集合,所以负载均衡器不需要做「一致性哈希」,普通的 least_connections 就够。
- 没有元数据热点:不存在「元数据服务器」这个性能和故障瓶颈。
- 扩容只影响新写入的路由:新加的池只承接新数据,已经写下的对象还在老池里,除非手动重平衡。
- 单个池整体掉线会影响全集群:MinIO 无法判断请求原本该去哪个池,会暂停整个部署的 I/O——这是多池部署最需要注意的风险点。
TLS 证书配置
MinIO 检测到证书目录里有合法的 public.crt 和 private.key 就自动启用 TLS 1.2+,不需要改任何配置。
证书目录按进程用户的 home 走:
# systemd 以 minio-user 运行,所以是这个路径
sudo mkdir -p /home/minio-user/.minio/certs/CAs
sudo cp fullchain.crt /home/minio-user/.minio/certs/public.crt
sudo cp privkey.key /home/minio-user/.minio/certs/private.key
sudo chown -R minio-user:minio-user /home/minio-user/.minio
sudo chmod 600 /home/minio-user/.minio/certs/private.key
sudo systemctl restart minio
也可以用 --certs-dir 指定别的目录,把这个参数加到 MINIO_OPTS 里即可。
几个关键点:
- 证书 SAN 必须包含客户端实际访问的域名,用 IP 访问就要把 IP 写进 SAN,否则客户端报证书不匹配。
- 内部 CA 或自签证书必须分发 CA:把 CA 证书放到所有节点的
certs/CAs/下,MinIO 只信任这里的 CA。集群内部节点互访也走 TLS,缺一个节点的 CA 就会导致节点间通信失败。 - 客户端也要信任 CA:
mc会把 CA 证书装在系统信任链里;临时测试可以加--insecure,生产别这么干。 - 多域名用 SNI:想同时用
s3.example.net和s3-internal.example.net访问,就把两个证书分别放到certs/s3.example.net/这样的子目录里。 - 换证书要重启:MinIO 不会热加载证书,续期后必须重启服务,记得把自动续期的 hook 配上。
扩容:加池,不是加盘
这是 MinIO 最容易被误解的地方:分布式模式不能给已有的池加盘。扩容的唯一方式是新增一个服务器池,然后把所有节点的启动参数改成包含新旧两个池。
# 原有一个 4 节点池,新增一个 4 节点池,空格分隔两个池
MINIO_VOLUMES="https://minio{1...4}.example.net:9000/mnt/disk{1...4}/minio https://minio{5...8}.example.net:9000/mnt/disk{1...4}/minio"
新池的准入条件:
- 每个池至少提供 2 × EC:N 块盘。默认
EC:4就是至少 8 块盘,4 节点 × 2 盘也能满足,但更推荐 4 节点 × 4 盘保持拓扑一致。 - 所有节点使用相同端口,主机名连续编号,用扩展写法。
- 加完必须所有节点同时重启,改完配置直接
systemctl restart minio全量执行。
扩容之后的行为:
- 老数据不会自动迁移。新写入按各池的「空闲空间占比」分配:A 池空 3TiB、B 池空 5TiB,那新对象落到 B 池的概率就是 62.5%。
- 需要让老数据也分布过去,用
mc admin rebalance start手动触发重平衡,mc admin rebalance status看进度。重平衡很吃 I/O,挑业务低峰期做。 - 想退役旧池用
mc admin decommission start,它会先把数据迁走再下线池。
加池只增加容量和吞吐,不提供跨站点容灾。而且只要有一个池整体不可用,整个部署的 I/O 都会停止。真正的容灾要靠站点复制(mc replicate add)或异地 mc mirror,这两件事不要混为一谈。
负载均衡与健康检查
生产环境不要让客户端直连某个节点,前面挂一层负载均衡:
upstream minio_api {
least_conn; # MinIO 官方推荐,不要用 ip_hash
server minio1.example.net:9000 max_fails=3 fail_timeout=10s;
server minio2.example.net:9000 max_fails=3 fail_timeout=10s;
server minio3.example.net:9000 max_fails=3 fail_timeout=10s;
server minio4.example.net:9000 max_fails=3 fail_timeout=10s;
}
server {
listen 443 ssl;
server_name s3.example.net;
client_max_body_size 0; # 不限上传大小,大对象必配
proxy_buffering off; # 流式转发,别把大对象缓到内存/磁盘
proxy_request_buffering off;
chunked_transfer_encoding off;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 300;
proxy_read_timeout 300;
proxy_pass http://minio_api;
}
}
健康检查用哪个端点,取决于你要探什么:
| 端点 | 含义 | 用途 |
|---|---|---|
/minio/health/live | 进程活着就返回 200 | 负载均衡摘除故障节点、K8s livenessProbe |
/minio/health/cluster | 集群达到仲裁(quorum)才返回 200 | 判断整个集群是否可服务,告警用 |
/minio/health/ready | 节点准备好服务读请求 | K8s readinessProbe |
/minio/health/cluster 会真的检查集群仲裁状态,高频率探测会给集群增加负担。负载均衡的被动检查(max_fails)配合 30 秒一次的主动探测就够了,不要设成 1 秒一次。
小结
- 生产从 4 节点 × 4 盘起步,
EC:4下可用容量 75%、能扛住 4 块盘或 1 个节点故障;容量按两年规划、70% 水位前扩容。 - 硬性约束记牢:至少 4 盘、盘要直通不要 RAID、文件系统 XFS、所有节点同端口、时间必须同步。
- 对象路由靠命名空间哈希,无中心元数据;任意节点都能处理请求,负载均衡用 least_conn。
MINIO_VOLUMES用扩展写法列出所有池,配置变更、升级、扩容都要全节点同时重启,禁止滚动(单节点硬件维修是例外)。- TLS 靠
certs/public.crt+private.key自动启用,内部 CA 要分发到每个节点的certs/CAs。 - 扩容只能加池(每池至少 2 × EC:N 块盘),老数据不自动迁移,按空闲空间比例写新对象,必要时
mc admin rebalance。 - 健康检查分三层:
live探进程、ready探节点、cluster探仲裁。
集群跑起来只是开始。下一篇《运维与监控》讲日常巡检、heal 修复、Prometheus 指标和容量治理。