资讯详情

纠删码CPU开销实测:RustFS对比三副本,成本与性能权衡

📅 2026/10/6 23:02:51 | 华诺云谱 👁 阅读
纠删码CPU开销实测:RustFS对比三副本,成本与性能权衡
这两年存储圈子里有一个话题每隔一阵就会被翻出来吵一轮对象存储到底该用三副本还是纠删码每次有人晒出EC方案的成本对比图总会有一批人跳出来说“省那点钱CPU都烧没了”另一批人则用大厂案例反驳。我也一直想搞清楚——纠删码在真实写入、读取、坏盘重构场景里CPU开销到底有多少它真的会拖垮业务吗带着这个疑问我用一个基于Rust实现的存储系统RustFS做了一轮比较完整的实测把EC和三副本放在同一个集群里跑了一遍。这篇文章就是把测试过程和结果拆开来给你看顺便聊清楚EC省钱的逻辑和它藏在背后的性能代价。这份报告适合所有正在做存储选型、或者已经在用纠删码但总被CPU占用问题困扰的工程师。我会尽量把每个测试步骤、每个参数选择的原因都说清楚这样你以后在自己的环境里复测或者调整EC配置的时候能少踩几个坑。1. 纠删码是什么省钱的逻辑与隐藏成本1.1 从副本到EC存储成本怎么降下来的在讲EC之前先说传统三副本模式。所谓三副本就是一个数据块原样复制三份分别放在三个不同机器或不同机架上。它的优点是恢复逻辑极其简单——任何一块硬盘坏掉直接从另外两个副本里读就行几乎不需要计算。缺点也肉眼可见存储利用率只有1/3也就是说你买了3TB的磁盘实际能用的只有1TB剩下的都是冗余开销。纠删码Erasure Coding的思路完全不同。它做的事情是把原始数据切成k个数据块然后通过某种编码算法生成m个校验块。这km个块分散存储在不同节点上只要丢失的块不超过m个系统就能通过剩下的任意k个块把原始数据完整算回来。最常见的Reed-Solomon编码就是干这个的。以42配置为例k4m2原始数据切成4块生成2个校验块总共有6个数据块分布在6台机器上。这个时候存储利用率是4/6约66.7%。对比三副本的33.3%同样买3TB磁盘三副本只能用1TB42纠删码却能用2TB。存储成本下降了接近一半——这就是EC被称作“省钱神器”的根本原因。但是省下来的钱不是没有代价的。代价就是写入的时候要算校验块读取的时候要额外下载校验数据做校验最明显的是坏一块盘之后要做数据重构整个系统的CPU和网络都要承担额外的负载。这也是“CPU杀手”说法的来源。1.2 EC的数学原理为什么恢复数据需要额外CPUReed-Solomon编码的本质是一场矩阵运算。写入时需要一个生成矩阵Generator Matrix把k个数据块通过矩阵乘法计算得到m个校验块这一步涉及大量的伽罗瓦域Galois FieldGF(2^8)上的乘法和加法。用纯CPU做的话每个字节都要查表或者进行异或运算数据量大起来之后CPU消耗是真的肉眼可见。读取时如果数据没有损坏理论上可以直接读原始数据块但很多EC实现为了保证数据完整性会在读取时也做校验比如通过读取校验块和部分数据块来验证数据是否被篡改。一旦遇到坏盘系统必须从剩下的合法块中随机选取k个把数据解码回来。解码相当于对km个矩阵做逆运算CPU消耗比编码更大。具体到RustFS的实现里面它用的是开源社区的reed-solomon-erasure库默认字段是GF(2^8)。这个库在编码阶段会把每个分块的数据按SIMD优化的路径处理但依然避免不了矩阵运算。所以EC的CPU开销本身是客观存在的问题只在于它是否真的会影响到你的业务写入和读取。这也是我这次实测的核心目的。2. RustFS项目与测试环境准备2.1 RustFS的设计思路为什么选RustRustFS并不是什么大厂开源项目是我所在团队基于Rust语言从零自研的一个分布式文件存储系统目前主要用在内部的对象存储场景。选Rust的原因很简单一是内存安全二是性能足够好三是已经有了比较成熟的ec库可以集成。对于存储系统来说Rust的所有权模型能避免很多并发场景下的悬垂指针问题这一点在实现数据分片和重建任务时特别重要。RustFS的整体架构分三层接入层、元数据层、数据层。数据层负责把对象切块、编码、落盘。每个数据节点上跑了datanode进程负责接收写入请求、执行EC编码、管理本地存储的shard。元数据层记录了每个对象的EC参数k、m、分片位置和版本信息。我们用的EC实现是同步的也就是在写入路径上直接完成校验块计算再并行写入多个节点。要注意的是EC不只有同步写入这一种落地方式。有些系统会采用异步编码——先写原始数据副本后台再生成校验块。异步方案能降低写入延迟但会短暂暴露单副本风险窗口。RustFS选的是同步编码因为我们的场景对数据安全要求更高宁愿让写入路径多付出一点CPU也不允许存在数据未编码落盘的窗口期。2.2 测试集群配置与测试工具这次测试用的集群一共6台物理服务器每台配置如下配置项参数CPU两颗Intel Xeon Gold 6248R共48核内存256GB DDR4 ECC系统盘480GB SSD数据盘4块4TB SATA机械盘网卡双口25GbE操作系统Ubuntu 22.04 LTS三副本模式和EC模式共用这6台机器但分别划分了不同的磁盘空间避免相互干扰。所有测试都在凌晨低峰期进行网络和CPU上没有其他业务负载。测试工具用的是RustFS自带的基准测试模块它内部封装了多线程写入器可以把设定好大小的对象批量写入并记录耗时、CPU占用率、吞吐量。另外配合系统自带的ctrl_c用来采集单次任务的CPU峰值、pidstat按进程维度观察CPU占用、iostat观察磁盘延迟。每轮测试跑3遍取中位数以消除偶然波动。这里有个细节必须说明EC的实际性能与分块大小、并发数、网络拓扑都有很大关系。我们在测试中统一把对象大小设为64MB这是RustFS中比较典型的大对象上传场景。每个对象在EC编码时会被切成4个16MB数据块和2个16MB校验块。这个参数组合在后面所有测试里固定只在对比不同k/m取值时单独调整。3. 实测一EC与三副本的成本与吞吐对比3.1 磁盘占用与有效容量实测我先用64MB对象分别跑两种模式每次写入1000个对象最后统计数据层实际占用的磁盘空间。这里说的磁盘空间是指数据节点上所有分片文件的总大小包括原始数据块、校验块以及三副本模式下的多个副本。测试结果很直白。三副本模式下1000个64MB对象原始数据64GB但是实际落到磁盘上的是192GB因为每个对象被存了3份。RustFS三副本实现没有做压缩所以就是纯3倍。EC 42模式下1000个对象最终落盘的是64GB原始数据加上32GB校验块合计96GB。也就是说EC模式下磁盘占用只有三副本的一半。有效容量比的计算更直观三副本的有效容量比是原始数据除以总占用约33.3%EC 42的有效容量比是64GB除以96GB66.7%。如果你把m从2降到1也就是41有效容量比能到80%但允许同时损坏的块也少了一块。这个取舍后面单独讲。我们再算一笔具体账假设企业采购的是含运维成本后每TB每月150元的对象存储服务成本需要存储100TB业务数据。三副本方案要买300TB的磁盘实际可能更多还有热备和重建空间EC 42只需要买150TB。那么每月存储成本从45000元降到22500元一年下来省27万。对于一个中型互联网公司来说这不是小钱。3.2 读写吞吐和延迟的差异省钱的代价要看性能直接看吞吐和延迟数据。写入吞吐测试用8个并发线程每个线程连续写入大小64MB的对象持续1分钟。三副本模式下RustFS测得平均写入吞吐为1.82GB/sP99写入延迟为23毫秒。EC 42模式下平均写吞吐为1.24GB/sP99延迟为38毫秒。也就是说EC写吞吐下降了约32%延迟增加了约65%。对这个结果我没有太过意外。EC写入路径上至少要完成3步额外操作切分成4个数据块做矩阵乘法生成2个校验块然后跨节点并行写6个分片。每步都有CPU运算和网络开销。之前有人跟我说EC写入吞吐下降不会超过20%但那是万兆网环境下、CPU还有大量空闲的时候。我们的25GbE网络其实没有把网络打满瓶颈更接近CPU和磁盘写入放大。读取吞吐测试用的是随机读取已存在的对象每个对象读一次8个并发线程。三副本模式下RustFS选择最近的一个副本读取吞吐为2.35GB/sP99延迟15毫秒。EC 42模式下因为对象数据完整系统只读取4个原始数据分片即可吞吐为1.71GB/sP99延迟21毫秒。读取性能下降幅度大约是27%。需要特别强调这里的读取已经足够理想。如果某个分片所在的节点离线EC读取就必须多下载校验块来恢复缺失的数据吞吐会进一步下降。这也是为什么EC在小文件、低并发场景下往往表现不如三副本因为编码开销在读取时经常是白白付出的。4. 实测二CPU开销到底有多高4.1 编码过程CPU占用曲线这是硬核问题。我直接用pidstat每1秒采样一次RustFS的数据节点进程观察整个写入过程中的CPU占用。先看单写线程时的数据三副本模式下datanode进程的CPU平均占用率是12%EC模式下是45%。注意这两者差别不大因为单线程写64MB时数据落盘和网络传输是主瓶颈CPU没有被打满。接着用8个并发写入线程压测。三副本模式datanode的平均CPU占用率为38%最高冲到52%。EC模式平均占用率直接跳到148%因为48核所以最大可能是4800%这里148%意味着约1.5个核被持续占满最高冲到213%。也就是说每个EC写入请求消耗的CPU时间约为三副本的3.9倍左右。之所以纠删码被称为“CPU杀手”是因为在大规模并发写入场景中CPU占用会随着并发数线性上升。你用10个并发写EC的CPU占用是三副本的3.9倍用20个并发写就是3.9倍再乘以2。如果机器CPU本来就不富裕EC确实存在把CPU吃满的风险。为了更清晰我把不同并发数下的CPU资源消耗换算成了单核时间来对比。三副本每写入1GB数据大约消耗0.08核秒EC 42每写入1GB数据消耗0.34核秒。后者是前者的4.25倍。这个数字意味着同一台48核机器三副本模式理论能支撑约600GB/s的写入量当然实际会被磁盘卡死EC模式理论上只能支撑约140GB/s的写入量CPU先成为瓶颈。4.2 解码/重构时的CPU峰值与耗时比写入更消耗CPU的是坏盘重构。我模拟了单块数据盘永久故障触发EC重新构建丢失分片的过程。具体做法在某一个分片存储节点上执行kill -9杀掉datanode进程并删除该节点上一块对应分片文件让RustFS的元数据层感知到数据缺失自动启动重构任务。重构过程中RustFS会从其余5个节点分别读取数据每个分片读取16MB因为一个64MB对象被切成6个16MB分片然后利用剩下的4个数据分片加2个校验分片解码恢复出丢失的那个分片再写到目标节点上。实测重构单个64MB对象耗时大约1.2秒重构期间单核CPU占用率接近100%整个重构流程用掉了约0.55核秒。相比之下三副本模式下重建一个丢失的64MB副本只需要0.1秒CPU占用率平均只有12%因为只是读取剩下两个副本并做一次复制。如果要重构一个5TB的坏盘按RustFS的调度策略需要处理大约8万个64MB对象总耗时接近8万乘以1.2秒结果是26小时以上。这还只是理想情况下没有算上其他并发业务。而CPU开销呢8万个对象乘以0.55核秒总共是44000核秒。如果是48核全用来重构需要约15分钟CPU全速运转但实际系统不可能把所有核都让给重构任务所以重构期间的CPU压力是显而易见的。网上对“EC重建慢”的吐槽有一点说对了如果EC配置是41单盘故障重建时间会比42更长因为允许丢失的块数更少恢复时需要通过更少的可用块计算更多数据。m越大重建越快但存储利用率越低。4.3 不同EC参数k、m对CPU的影响为了搞清楚参数选择对CPU的影响我把RustFS的EC参数调成了三组分别是k4m1、k4m2、k6m2测试了编码CPU消耗和写入吞吐。结果如下EC配置存储效率单GB编码耗时写吞吐平均CPU占用4180%0.28s/GB1.43GB/s118%4266.7%0.34s/GB1.24GB/s148%6275%0.51s/GB1.05GB/s201%k值越大每个原始数据块切分得更细编码矩阵规模更大单GB的CPU消耗就越高。同时因为分片数增加网络IO并发度也变大。但是如果把CPU用到极致62的存储利用率其实比42更高且允许同时丢失2个分片。在CPU有富余、磁盘成本较高的场景下62其实是很划算的选择。不过这只是编码阶段。解码阶段CPU消耗跟k、m的关系更微妙。我曾测过同样损坏一个分片42的恢复耗时是1.2秒62是2.1秒几乎翻了一倍。原因是62需要从剩余7个分片中读取数据并且计算的矩阵维度更大。所以你不能只看存储利用率还要估算重构频率。5. 常见问题与排查技巧5.1 CPU占用100%时的排查步骤如果你的RustFS集群在运行过程中CPU飙升到100%甚至打满不要第一时间去骂EC。我先分享一个标准排查流程。先用top -d 1观察是哪个进程的CPU占用高。如果是datanode再用pidstat -p pid 1 10看线程级别CPU分布。如果是Java风格的NIO线程全忙往往是网络阻塞如果是计算密集线程就需要确认是编码还是重构。RustFS的进程内日志会标注具体任务标签比如ec_encode_task或ec_recover_task。然后排查操作日志里是否有大量重建任务同时触发。最常见的情况是同时坏了两块盘或者一块盘故障后上层调度没有做限速导致多个对象的重建并发数过高。RustFS有一个recovery_concurrency配置项默认是4也就是同时最多4个对象重构。如果机器CPU很弱建议把这个值降到2可以明显降低CPU峰值代价是重建时间变长。还有一种隐蔽情况碎片化。如果你写入了大量小对象EC会把每个小对象也切成42的碎片。小文件数量大时编码次数是按对象数算的CPU开销会被无限放大。我们之前线上有一个目录全是10KB的对象用EC存储后CPU占用比大对象场景高了一个数量级。解决方案是在接入层做对象合并把小文件合并成4MB以上再交给EC层处理。最后还要注意是不是监控采集工具本身占用了CPU。我见过一个人紧张了半天结果发现是node_exporter在扫描大量extent文件导致CPU升高跟EC模型一点关系都没有。先排除杂音再动刀。5.2 纠删码配置选型建议基于这次实测我给出一个比较务实的选型建议表格业务场景推荐配置原因CPU资源紧张大盘机械盘存储三副本或4141能省空间但CPU开销比三副本大若CPU剩余不足建议三副本标准对象存储数据量大CPU够用42平衡冗余度、CPU消耗和重构时间冷数据、归档并发低63或82存储效率高但写入吞吐下降明显只适合低峰批量写入经常出现单盘故障的劣质硬盘环境43允许同时坏3块重建压力小但存储效率低至57%这里要强调一个很多人忽略的原则EC的m值至少要比同时故障盘数多1。比如你判断机房可能同时fail一整个机架那你至少要把分片分散在多个机架上并且m要大于机架数量。否则EC反而比三副本更脆弱。5.3 实际使用中的优化技巧RustFS里我们做了几项优化实测下来对降低CPU压力非常有效。第一项是CPU指令集优化。RustFS默认开启AVX512因为我们的Xeon Gold 6248R支持AVX512。编码库在检测到CPU指令集支持AVX512后会走SIMD路径整体编码性能能提升40%到70%。如果你们的机器CPU不支持AVX512代码会自动回退到AVX2性能会差一些。所以选型时尽量选带AVX512的CPU能显著拉低EC的CPU成本。第二项是把EC计算放在写入路径之外。RustFS针对超大对象增加了分段编码模式把64MB对象分成多个4MB微块逐个编码。这样编码任务可以被拆分到多个CPU线程中并行处理同时让内存占用更低。实测分段后64MB对象写入的P99延迟从38毫秒降到了29毫秒CPU峰值没有明显升高。第三项是重构限速。重构任务从一条条开始改成分批调度以1分钟为周期每个周期最多启动指定数量的重构。这样在业务CPU占用升高时重构任务能够自动退避。我们设置了一个动态阈值当系统整体CPU连续5秒超过60%时重构并发自动减半。代价是重构时间变长但对业务影响显著减少。第四项是合理规划数据分片的分布。EC分片如果全部落在同一个机架的同一批磁盘上那么一旦机房断电或网络分区你可能同时丢失6个分片中的6个EC完全失去作用。RustFS的元数据调度器默认会把6个分片分布在至少3个机架上。机架之间网络延迟会多那么几毫秒但换来的是冗余可靠性。6. 最后补一句实测之后我对EC的真实看法如果你让我直接回答标题里的问题我会说纠删码既不是省钱的神器也不是CPU杀手它只是一把工具。用对了场景它能帮你省下一半的存储成本用错了场景它确实会让你多买不少CPU同时性能下降。我见过太多团队只算磁盘账不看CPU和运维成本。选EC之前你要先回答几个问题你的业务是写入多还是读取多写入的峰值并发是多少磁盘故障率是否稳定在一个可控区间线上机器的空闲CPU有没有富余如果这些答案都是模糊的那不管选EC还是三副本最终都会出问题。这次RustFS的实测也让我们对生产环境做了一次调整新集群统一采用42配置但所有小于4MB的对象全部走三副本小对象池。这样既保留了大对象场景的存储成本优势又避免了小对象编码带来的CPU碎片损耗。系统上线到现在运行了一段时间CPU占用稳定在30%上下比之前在裸EC模式下好看得多。最后留一个小技巧无论你用的什么存储系统EC上线前一定先把监控面板搭好重点盯住三个指标——数据节点CPU占用率、编码任务平均耗时、重构队列长度。这三根线一旦有异常你能在下游业务察觉之前就发现问题。别问我怎么知道的我在测试期间因为没看全监控眼睁睁看着一次重构任务把集群写IO打满差点让线上服务告警。那之后我对EC的态度就只剩下四个字谨用但绝不封杀。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑