☰
MinIO 集群扩缩容时数据重平衡拖垮带宽:对象存储选型的 5 个维度,我列了一张打分表
2026/10/4 8:22:55 网站建设 项目流程

title: "MinIO 集群扩缩容时数据重平衡拖垮带宽:对象存储选型的 5 个维度,我列了一张打分表"
description: "从 HDFS、Ceph、MinIO、阿里云 OSS 四个维度对比分布式存储选型,附扩缩容、EC 纠删码、S3 兼容性的真实测试数据。"
tags: ["分布式存储", "MinIO", "HDFS", "Ceph", "对象存储", "Java"]


2024 年 4 月,我们的文件存储从本地 NAS 迁移到 MinIO 集群。初期 4 节点跑得很稳,但两个月后业务增长需要扩到 8 节点,MinIO 的mc admin rebalance一启动,内网带宽直接被占满,业务 API 的 P99 延迟从 120ms 飙到 3 秒。那次扩容让我意识到:对象存储的选型,不能只看单节点压测数据,扩缩容时的行为才是分水岭。

HDFS:大数据场景的标配,但小文件是噩梦

HDFS 是为 MapReduce 设计的:大文件顺序读、高吞吐、一次写入多次读取。

// HDFS Java API 写文件 Configuration conf = new Configuration(); conf.set("fs.defaultFS", "hdfs://namenode:9000"); FileSystem fs = FileSystem.get(conf); Path filePath = new Path("/data/logs/2024/04/01.log"); FSDataOutputStream out = fs.create(filePath, (short) 3); // 3 副本 out.writeBytes("log line 1\n"); out.close();

fs.create(filePath, (short) 3)的第二个参数是副本数。HDFS 默认 3 副本,一个 100MB 的文件实际占用 300MB 存储空间。FileSystem.get(conf)会连接 NameNode 获取元数据,真正的数据读写通过 DataNode 直接传输。

HDFS 的问题是小文件存储效率极低。NameNode 把所有文件元数据放在内存里,一个文件对象约 600 字节。1 亿个小文件就是 60GB 内存,NameNode 根本扛不住。我们有一次把日志按 "每分钟一个文件" 存进 HDFS,3 个月产生了 1.2 亿个文件,NameNode 直接 OOM。

// HDFS 小文件合并方案:SequenceFile Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(conf); Path seqFile = new Path("/data/logs/combined.seq"); // 把大量小文件合并成一个 SequenceFile SequenceFile.Writer writer = SequenceFile.createWriter( conf, SequenceFile.Writer.file(seqFile), SequenceFile.Writer.keyClass(Text.class), SequenceFile.Writer.valueClass(Text.class) ); // 写入 key-value:文件名 -> 文件内容 writer.append(new Text("2024-04-01-10-00.log"), new Text("log content...")); writer.close();

SequenceFile是 HDFS 的原生二进制格式,把大量小文件合并成一个大的顺序文件,NameNode 只看到一个文件对象。但代价是:不能单独删除里面的一条记录,只能全量重写。

Ceph:功能最全,但运维复杂度最高

Ceph 的统一存储模型(对象、块、文件)很诱人,但我在 2022 年部署过一个 12 节点的 Ceph 集群,运维复杂度让我印象深刻。

Ceph 的核心是 CRUSH 算法:客户端直接计算数据应该存在哪个 OSD(对象存储守护进程),不需要中心化的元数据服务器。这个设计消除了单点,但带来了数据分布的不可预测性。

# Ceph 集群健康检查:PG 状态是核心指标 ceph -s # 典型输出: # health: HEALTH_WARN # 2 pgs degraded # 1 pgs undersized # PG(Placement Group)是 Ceph 数据分布的最小单元 # PG 数量 = (OSD 数量 × 100) / 副本数,调整需要 rebalancing

HEALTH_WARN里的pgs degraded表示某些 PG 的副本数不足(可能是 OSD 挂了)。Ceph 会自动恢复,但恢复期间集群性能会下降 30-50%。

Ceph 的运维门槛体现在:
1.PG 数量调优:太少会导致数据倾斜,太多会导致元数据开销大
2.BlueStore 调优:SSD 和 HDD 混合部署时,WAL/DB 分区大小要精确计算
3.网络分区处理:Ceph 对网络抖动敏感,脑裂后数据可能不一致

我只推荐有专职存储运维团队的组织使用 Ceph。对于中小团队,Ceph 的维护成本会超过它带来的功能收益。

MinIO:S3 兼容 + 简单,但扩缩容有坑

MinIO 是目前最热门的自建对象存储方案,100% S3 兼容,单二进制文件部署,5 分钟启动。

// MinIO Java SDK(兼容 AWS S3 SDK) MinioClient minio = MinioClient.builder() .endpoint("http://minio-cluster:9000") .credentials("ACCESS_KEY", "SECRET_KEY") .build(); // 上传文件 minio.putObject( PutObjectArgs.builder() .bucket("documents") .object("contracts/2024/04/contract-001.pdf") .stream(fileInputStream, fileSize, -1) .contentType("application/pdf") .build() );

putObject的object参数就是 S3 的 key,用/分隔模拟目录结构。stream()的第三个参数-1表示未知大小(MinIO 会用分块上传)。

MinIO 的默认部署模式是Erasure Code(纠删码)而非副本。4 节点时默认配置是 2 数据盘 + 2 校验盘(EC:2+2),存储利用率 50%,但可以容忍任意 2 个节点同时故障。这比 HDFS 的 3 副本(33% 利用率)经济得多。

扩缩容的坑:数据重平衡

我们从 4 节点扩到 8 节点时,MinIO 需要把已有数据重新分布到新节点上。mc admin rebalance start命令一执行:

  1. 所有节点开始互相拷贝数据块
  2. 内网带宽(10Gbps)被占满
  3. 业务 API 的 S3 请求排队,P99 延迟飙高
# MinIO 重平衡命令 mc admin rebalance start myminio # 监控重平衡进度 mc admin rebalance status myminio # 输出:Current throughput: 1.2 GiB/s, ETA: 4h 32m

1.2 GiB/s的吞吐听起来不错,但这是 10Gbps 网络的极限。重平衡期间,业务流量和重平衡流量抢带宽,没有 QoS 隔离。

我们的解决方案:
1.扩缩容放在低峰期(凌晨 2-6 点)
2.限速重平衡:MinIO 目前没有内置限速,我们通过 Linux tc(traffic control)给重平衡流量限速到 3Gbps
3.预规划节点数:MinIO 的 EC 配置在初始化时确定,后续不能改。我们一开始按 "最终 16 节点" 规划了 EC:8+8,初期用 4 节点跑(降级模式),后续加节点时不需要改 EC 配置

# Linux tc 限速:给 MinIO 重平衡流量限速 3Gbps tc qdisc add dev eth0 root tbf rate 3gbit burst 1g latency 100ms

tc qdisc add dev eth0 root tbf在网卡eth0上添加 Token Bucket Filter。rate 3gbit是限速 3Gbps,burst 1g是突发缓冲 1GB,latency 100ms是最大排队延迟。

阿里云 OSS:省心但不省钱

如果不想自建,公有云对象存储是最省心的选择。阿里云 OSS 的 Java SDK:

// 阿里云 OSS Java SDK OSS ossClient = new OSSClientBuilder() .build("oss-cn-shanghai.aliyuncs.com", "ACCESS_KEY_ID", "ACCESS_KEY_SECRET"); // 上传文件 PutObjectRequest putObjectRequest = new PutObjectRequest( "my-bucket", "data/file.zip", new FileInputStream("/local/file.zip") ); // 开启服务端加密 putObjectRequest.setServerSideEncryption( ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION ); ossClient.putObject(putObjectRequest);

setServerSideEncryption开启 OSS 服务端加密(SSE),数据在 OSS 服务端用 AES-256 加密存储。密钥由 OSS 托管,适合合规要求高的场景。

OSS 的隐性成本:
1. ** egress 流量费:从 OSS 下载到公网,0.8-1.0 元/GB。日均 1TB 下载就是 800-1000 元/天
2.
API 调用费:PUT/LIST 请求 0.01 元/万次,GET 请求 0.001 元/万次。高频小文件场景这个费用会超过存储费
3.
跨区域复制费**:如果做异地容灾,数据复制也要收 egress 费

我们算过一笔账:日均存储 50TB、下载 2TB、API 调用 5000 万次的场景,OSS 月费用约 12 万,自建 MinIO(硬件 + 运维人力)月费用约 6 万。但 OSS 省去了运维人力和扩容时的半夜起床。

选型打分表

维度(权重)HDFSCephMinIO阿里云 OSS
小文件支持(15%)2/107/108/109/10
大文件吞吐(20%)10/109/108/108/10
扩缩容友好度(20%)4/105/105/1010/10
运维复杂度(15%)5/102/108/1010/10
成本可控性(15%)7/106/108/104/10
S3 兼容性(15%)0/108/1010/1010/10
加权总分5.06.27.38.4

加权总分只是参考。我的实际选择是:
-离线大数据分析(TB 级日志、Hive 表):HDFS
-通用文件存储、需要 S3 API:MinIO(控制节点数规划,做好重平衡预案)
-没有运维人力、预算充足:阿里云 OSS
-除非有块存储需求,否则不推荐 Ceph:运维成本太高

总结

对象存储选型不是技术优劣问题,是"团队能承担多少运维复杂度" 的问题。MinIO 是我们目前的默认选择,但它的扩缩容重平衡问题必须在架构设计阶段就规划好——预留带宽、选择正确的 EC 配置、低峰期执行。

那个凌晨 2 点的带宽打满事件让我记住:任何存储系统,单节点压测数据都没有意义,扩容时的行为才是真面目。

思考题

  1. 你现在的存储系统扩容时需要重平衡数据吗?有没有做过限流?高峰期扩过容吗?
  2. 如果你的对象存储明天要支持 "用户上传的文件 30 天后自动转冷存储",HDFS/MinIO/OSS 分别怎么实现?哪个成本最低?

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询