纠删码到底吃掉了多少容量:EC:4、EC:8 的利用率与容错怎么算

买了 8 块 16TB 的盘,128TB 裸容量,装出来的桶能用多少?大多数人拿 128 × 0.75 估一个大概就往下走了。但这个 0.75 从哪来、什么时候不成立、坏几块盘真的没事吗,才是决定数据会不会丢的那几件事。

对象存储的可靠性不走"多存几份"那条路,它用 Reed-Solomon 纠删码:一个对象被切成若干数据片,再算出若干校验片,一起散到不同盘上。坏了几片,靠剩下的还能反推回去。整盘买卖里最容易算错的就是下面这几个数字。

N、M、K 这三个字母分别在说哪件事

文档里写的 EC:4、EC:8,说的是 M,也就是校验片(parity shard)的数量。它必须和另外两个字母放在一起才有意义:

  • N:一个纠删集里有几块盘。纠删集是把一堆盘横向划出来的小组,写对象时按组为单位落盘
  • M:校验片数量,也就是 EC: 后面那个数
  • K:数据片数量,K = N - M

RustFS 官方文档把这套关系写得很直接:一个含 N 块盘、M 个校验片的纠删集,数据片是 N - M,最多能重建的不可用分片数是 M,近似容量利用率是 (N - M) / N。文档给的算例是 16 盘纠删集配 EC:4,存 12 个数据片加 4 个校验片,在扣除文件系统、元数据与运行开销之前的近似利用率是 75%。

所以 0.75 的来路是 12 / 16。它跟默认配置无关,也不是什么行业惯例,只代表"恰好 16 盘一组、恰好 4 个校验片"这一种情况。换成 EC:2(14/16)是 87.5%;EC:8 那档掉的就狠了:16 盘配 EC:8 时 N=16、M=8、K=8,K 顶到 N/2,利用率同样 50%,但两者的写入门槛已经完全不一样,后面的法定人数会展开讲。

同一个 16 盘集群,只改这一个参数,可用容量就在 50% 到 87.5% 之间来回摆。

这里还有一个容易被忽略的边界:单盘部署是另一种独立布局,零校验。RustFS 文档明确写到多盘纠删集的盘数范围是 2 到 16,而单盘部署是一条单独的布局路径, parity 为 0。也就是说开发机上拿一块盘跑起来的实例,利用率写的是 100%,但它没有任何冗余,盘坏了数据就没了。看到 100% 这个数字先高兴起来的话,多半是踩在这个坑里。

默认不用你配,因为它是从盘数倒推出来的

多数人装完集群从不设置 EC 相关变量,存储自己挑了一个。这个"自己挑"是有明确规则的:RustFS 会为每个存储池,按它的纠删集大小独立推导 STANDARD 存储级别的奇偶值。

官方给出的默认奇偶表:

每纠删集盘数 自动采用的奇偶 数据片 近似利用率
1 EC:0 1 100%
2--3 EC:1 1--2 50%--67%
4--5 EC:2 2--3 50%--60%
6--7 EC:3 3--4 43%--50%
8--16 EC:4 4--12 50%--75%

MinIO 官方文档里列的表与这张完全一致:同样是 1 对应 EC:0、2--3 对应 EC:1、4--5 对应 EC:2、6--7 对应 EC:3、8--16 对应 EC:4。两家收敛到同一套推导,背后是同一个约束:校验片不能超过总盘数的一半。

RustFS 文档把这条约束写成了启动时的校验条件 M <= N / 2。填进去的非法值不会让服务悄悄降一档继续跑,而是启动直接失败。这个设计比自动降级更诚实:它不会让集群带着一个你没意识到的低可靠性一直运行下去。

顺着这条边界往另一头看,是零校验。EC:0 同样能通过校验、给出 100% 的利用率,代价官方写得很直白:换掉或清空一块盘,那块盘上的零校验对象永久丢失,heal 对它们只会回一句 no-parity object is unrecoverable。官方给出的下限是生产部署至少 EC:1,而一旦这个纠删集跨了节点,通常按 EC:2 起步。利用率表里的 100% 不是"赚到",它只是没有冗余兜底而已。

拿自己那批盘算一遍

官方给出的口径是:

复制代码
可用容量 ≈ 裸容量 × (N − M) / N

它自己举的例子是 160 TiB 裸容量、16 盘纠删集配 EC:4:160 × (16 − 4) / 16 = 120 TiB。

这条公式有三个容易踩的地方。

第一,N 是纠删集大小,不是集群总盘数。 一个 64 盘的集群通常会被划成多个纠删集,比如 4 组每组 16 块,算的时候用的是 16 而不是 64。纠删集宽度默认由存储从卷拓扑里自动挑一个合法值,需要钉死时可以用 RUSTFS_ERASURE_SET_DRIVE_COUNT 指定,前提是这个值能把已配置的端点整除,否则会被拒绝。

对比之下,MinIO 在 RELEASE.2026-02-02T23-40-11Z 及之后的版本允许通过 MINIO_ERASURE_SET_DRIVE_COUNT 把纠删集放宽到 17 到 32 块盘,默认值仍是 16。同一批 128 块盘,配 32 是 4 个纠删集,不配是 8 个纠删集。而这个数字一旦集群初始化就再也改不动了,官方文档写得很明白:selected stripe size is immutable after the cluster has been initialized。这笔账必须在装机前算,容量不够了再回头调是调不了的。

第二,公式给的是近似值,文档特意加了"之前"这个限定。 RustFS 原文的表述是 "before file-system, metadata, and operational overhead",也就是扣掉文件系统、元数据和运行开销之前。实际可用一定比公式结果少一截,做容量规划时要给这部分留余量。

第三,混合存储级别的场景会让账不准。RustFS 支持 STANDARD 和 REDUCED_REDUNDANCY 两个存储级别,各自有独立的奇偶设置:RUSTFS_STORAGE_CLASS_STANDARD 管前者,RUSTFS_STORAGE_CLASS_RRS 管后者,后者在多盘纠删集上默认是 EC:1。两者都存在时,STANDARD 的奇偶值必须大于等于 REDUCED_REDUNDANCY 的值,这条同样进了校验条件。同一个集群里两种级别混用,整体利用率会落在两者之间的某个位置,不能简单套一个 (N-M)/N 了事。另外还有一个 RUSTFS_STORAGE_CLASS_OPTIMIZE 变量控制选奇偶时的优化目标,默认值是 availability,也就是说默认倾向可用性而不是空间利用率。

"EC:4 能扛 4 块盘"这句话差一个条件

这是最容易被话术带偏的一处。单看重建能力,M 确实等于"最多可重建的不可用分片数",所以 EC:4 能从任意 12 个存活分片里把数据算回来。但这个推论挂着两个前提,官方都做了提示。

不可用的是"分片",不是"节点"。 RustFS 文档在原话后面跟了一句警告:不要假设 EC:4 总能容忍四个完整节点故障,因为一个节点可能同时承载同一个纠删集里的多块盘。4 节点 × 4 盘的部署中,一台下线意味着它上面的 4 个分片同时不可用;两台同时下线,同一个 16 盘纠删集上可能直接少了 8 片,超过 M=4 的重建上限。要在主机或机架维度谈容错,就得让同一个纠删集的盘尽量分散到不同节点,除了 RUSTFS_ERASURE_SET_DRIVE_COUNT,部署时的端点排列顺序也得看。

写入时允许的失败次数会被压缩。 读的门槛好算,写的门槛常被忘掉。RustFS 官方把这两个数字直接列出来了:读法定人数等于 K,写法定人数等于 K,但当 K == M 时写法定人数抬到 K + 1。落到具体盘数上:

  • 16 盘 EC:4(K=12、M=4):读要凑齐 12 个有效分片;写则尝试写满 16 片,允许其中 4 片失败,凑够 12 片就向客户端返回成功
  • 16 盘 EC:8(K=8、M=8):读要凑齐 8 个分片;写却必须至少 9 片应答,能容忍的写失败只剩 7 片

EC:8 那一行是分界线。它的读恢复能力不差,任意 8 个分片就能把数据算回来,但写入路径的容错反而比 EC:4 少一片。这个不对称全部来自 K == M 时那道 K+1 门槛,官方给的理由是防止 split-brain 那类场景:两半各握着足够多的分片,各自都觉得自己还能继续写。落到部署上,M 顶到 N/2 就再没有加校验的空间了,生产环境里这一档用得很少,属于"利用率和写入可用性都压到极限"的取舍。RustFS 官方对这条没有额外的禁用标注,上面这句是经验判断。

官方还有一句边界值得记住:低于法定人数的写入不会被报成成功,服务端不会给客户端一个假的成功响应。这比争"到底允许失败几次"更重要,因为失败会明确暴露出来,不会攒到坏盘那天才发现。

再补一个同样容易误判的门槛:删除标记走的是多数派,N/2 + 1,16 盘集上是 9。所以一个正在降级、读写都在失败的纠删集,删除仍可能成功。删除成功不代表这个集是健康的,判断健康还是要看分片状态和读写是否达标。

RustFS 不会按离线盘数临时抬高奇偶。MinIO 有一个动态行为:发现纠删集里有盘离线但写法定人数仍满足时,会给正在写的对象逐级提升奇偶值,每离线一块盘加一,升级后的值写进对象元数据。RustFS 没有这套东西,原因是它的几何按对象写死在 xl.meta 里,官方原话是 The geometry is stored per object in xl.meta, so changing the default later rewrites nothing。运行期不会因为某块盘离线就临时抬高校验,改默认值也不会回头重写任何存量对象,想提奇偶只对之后新写入的对象生效,旧的要重新上传或走服务端复制。好处是行为可预期,代价是进入退化状态后没有额外的余量补偿,那一刻的容错就是配置值给的那个数。

回到那 8 块盘,以及一个外部校验值

8 块 16TB 构成一个纠删集时,自动奇偶取 EC:4,可用容量约 128 × (8-4)/8 = 64TB。注意 8 盘这一档的 K 和 M 都是 4,正好落在 K == M 的边界上:读要凑齐 4 个分片,写法定人数却是 K+1,也就是 5。坏任意 4 个分片仍能重建,此时读刚好达标、写已经差一个。配成 EC:2(K=6、M=2),容量涨到 96TB,读写法定人数都是 6,重建上限 2 片。

问题就出在这个"2 片"是分片口径,换成节点口径结论会翻。两台机器各插 4 块盘、同属一个 8 盘纠删集时,一台整机掉电等于同一纠删集上 4 个分片同时没了:EC:2 超出上限,EC:4 剩下 4 片也刚好压在读写门槛上,一点余量都不剩。要让整机掉电也扛得住,得换打法:同一纠删集的分片摊到 4 个节点、每节点 2 块盘,同样 EC:2,整机掉电只掉 2 片,读写都还能达标,代价是再坏一片就没有任何余量了。同样的 EC 值,打散得好能扛整机故障,打散得差连一半都算不上。这也是为什么 EC 参数只是纸面数字的一部分。

纠删集宽度本身还有反向约束。这个数不是越大越好:宽度越大,坏一片之后重建要读回的分片成比例变多,而同一个纠删集内的重建是串行的,一次 rebuild 拖长,下一次故障的窗口就跟着变宽。宽度太小也不行,利用率低、容错档位少。RustFS 的硬范围是每纠删集 2 到 16 块盘,且每个存储池必须能被这个宽度整除;12 到 16 这个常见区间属于业界经验,官方页面上并没有推荐值,别把它当硬性建议用。

MinIO 官方给了一条生产下限:生产部署必须使用 EC:3 或更高的奇偶值 ,低于这个值的配置(包括 5 块及以下盘那几档自动选出来的默认值)容错不足,只适合开发和测试环境。这条可以当作外部校验用:拿到任何一套默认配置之后,先核它的 EC 值是否 ≥3。

规划阶段的拓扑也该单独标一笔。盘数选对了不等于打散对了。RustFS 官方在集群规划第一步就要求按节点、机架、供电、网络这四类故障域安排端点顺序,并且给了一句很实在的提醒:声明拓扑不等于已经具备高可用,单节点的存储池会随主机一起丢掉全部分片,多盘的存储池在启动时都会打一条 host_failure_data_unavailable 警告。这条警告不用当成启动失败去紧张,它出现在每一次多盘池的启动里,提醒的是同一件事:同一个纠删集的分片如果落在同一台机器上,那台机器就是这部分数据的单点。

落到 RustFS 上,这笔账最后收敛到三个环境变量加一组校验条件:

bash 复制代码
export RUSTFS_STORAGE_CLASS_STANDARD="EC:4"
export RUSTFS_STORAGE_CLASS_RRS="EC:1"
export RUSTFS_ERASURE_SET_DRIVE_COUNT=16

三条要同时成立:M <= N/2;STANDARD 的 M 不小于 REDUCED_REDUNDANCY 的 M;指定的纠删集宽度能整除端点数。任何一条不满足,服务会拒绝启动而不是降级运行。改完这三行先别急着庆祝,看一眼启动日志,把"没起来"当成预期内的反馈处理。

RustFS 在 Apache 2.0 许可下开源,二进制、容器镜像与 Kubernetes 部署路径都能直接取用,上面提到的 EC Configuration 与环境变量参考两页都公开在 docs.rustfs.com。装集群之前花十分钟把 (N-M)/N 算一遍,成本远低于上线后发现可用容量少了一半。

相关推荐
遇见小修修1 小时前
3步解决打印机0x00000709报错 ,广州深圳程序员可自行排查
运维·打印机·维修·打印机报错·打印机运维·打印机故障自查
Huangjin007_3 小时前
【Linux 系统篇(二十五)】文件(二) 系统文件I/O详解
linux·运维·服务器
沐言Agent3 小时前
太惊艳了!2 个让你的 Codex 狠狠省 Token 的开源项目,必须收藏!
人工智能·ai·开源
程序员清风3 小时前
vLLM 实战:用 OpenAI 兼容接口部署本地大模型推理服务
开源·github·vllm
微小冷4 小时前
Mermaid画甘特图
运维·markdown·甘特图·mermaid·时间图
念何架构之路4 小时前
zap日志SugaredLogger 剖析
云原生·golang
狗凯之家源码网4 小时前
PHP 开源 IM 即时通讯系统效果实测与功能展示
开发语言·开源·php
天天向上2915 小时前
Spring AI 实战:14 个踩坑记录,其中一个让我的测试全绿但产品是坏的
java·开源
LBL12205 小时前
内网容器部署FTP日志监控服务
运维·服务器·容器