资讯动态

存算分离 vs 存算一体:1TB数据实测,性能与成本全对比

发布时间:2026/9/8 10:53:17 来源:尧图企业网站定制
最近我们团队完成了核心数据平台从传统存算一体架构到存算分离架构的迁移方案论证迁移动工之前花了两周时间在完全隔离的两套集群上做了一场对照实测。测试范围覆盖SQL查询、ETL批处理、弹性扩缩容、资源利用率、三年TCO等多个维度数据全部来自生产脱敏数据规模1TB左右使用的组件以开源为主。这篇文章不打算写PPT式的概念对比只记录这次实测里我们怎么设计对照方案、跑出了什么结果、又踩了哪些网上通常看不到的坑。文章会比较长但每一段都是实测现场的真实记录不是从官方文档里抄来的参数罗列。1. 为什么突然想起来做这场对比实测1.1 集群的痛点已经藏不住了我们手上有一套运行核心批处理业务的传统架构集群12台双路物理机48核、256GB内存外加12块大容量SATA盘组成HDFS存储。组件是老组合HDFSYARNHiveSpark。这套体系在数据量只有几十TB的时候非常舒服调度器基本不用调任务丢进去就能跑。但业务翻到几百TB以后痛点开始一个个冒出来。最明显的是资源错配。白天开发团队做临时查询计算资源空闲得可怜晚上调度中心一发起几百个批任务集群CPU、内存立刻被打满任务队列一直排队。更头疼的是扩容逻辑存储快满了或者某张表需要多保留几个副本时你根本没办法只加存储。为了把容量扩上去你被迫连计算一起买等于给一堆白天利用率不到20%的CPU也付了全款。这种存储告警触发计算扩容的荒唐事在传统架构的后期几乎年年发生。1.2 存算分离其实不是新概念说实话存算分离不是这两年才冒出来的。早期MPP数据库干的就是这一套计算节点和存储节点本来就是分开的只是后来Hadoop生态把存储和计算强绑定在HDFS节点上才让存算一体变成国内大数据平台的主流。这些年对象存储技术逐渐成熟带宽和延迟都上来了数据湖、Lakehouse这些概念又把存算分离推回了主航道。我们这次要评估的目标非常明确继续以开源组件为基础把存储从HDFS换成对象存储计算层拆成可以独立伸缩的Spark和Trino集群。要求是同一套SQL两边都能跑然后在这个前提下谈性能差异。当时团队内部对这个方向吵得挺凶支持派和反对派各执一词所以大家一致同意用一场实测来结束争论。1.3 测试目标与验收标准在动工之前我们和业务方、财务一起定了几条硬指标目的是避免用感觉投票。第一条核心报表SQL在相同数据量下P95查询耗时增幅不超过20%。第二条夜间批量任务整体完成时间增幅不超过15%。第三条数据扩容或者业务突发时可以在一刻钟内拉起一批新的计算节点。第四条三年TCO不能比继续扩容传统架构更高。为什么把性能门槛定在允许一定损耗而不是必须持平因为纯从访问路径看存算分离必然多一跳网络指望它比本地读盘更快不符合物理规律。我们要验证的不是它是否更快而是这个损耗是否控制在业务可接受范围内换来的弹性和成本优势是否值回票价。2. 两种架构的原理拆解性能差异从哪来2.1 传统架构的看家本领是数据本地性传统Hadoop架构里HDFS把文件切成128MB的块每个块默认三副本分布在不同的物理节点上。YARN调度Spark任务时会尽量把executor调度到存储该数据块的节点上这就是所谓的data locality数据本地性。任务在本地直接读磁盘不走网络这是传统架构性能模型里最核心的一个假设。这个假设在数据量和作业数量都比较小的时候确实很香。但集群大了以后本地性也没有想象中完美。做join、group by这类宽表加工时shuffle阶段数据照样要跨节点传输。本地性主要对map阶段读输入数据那一层有效。而且一旦某些节点变成热点任务排队起来数据本地性的收益也会被排队时间稀释掉这是很多人在小规模测试里感受不到的。2.2 存算分离架构到底拆了什么存算分离的典型组合是存储层用对象存储开源自建可以用MinIO云上就使用对象存储服务计算层用独立部署的Spark或Trino集群两边走标准网络协议通信。这样存储和计算就解耦了各自按需扩展。注意一个常见误解存算分离不是彻底不用本地磁盘。实际落地时计算节点的本地SSD仍然承担两类重要任务一类是shuffle产生的中间数据这是任务执行期间的临时落地另一类是热数据的缓存。说白了存算分离做的是长期数据的托底存储和临时计算存储分离而不是消灭本地盘。理解这一点很关键因为很多性能调优动作本质上都是在优化这条远程存储本地临时盘缓存的组合路径。2.3 性能差异的三个核心来源第一个来源是IO路径变长。传统架构读一个block是本地磁盘直读延迟是毫秒级存算分离读同样的数据要先经过网络再经过对象存储的处理链路单次读延迟可能到几十毫秒。对小文件、点查询这类场景这个差异会被放大得非常明显。第二个来源是并发模型变化。传统架构下并发受限于集群里的计算槽位和磁盘IO能力任务一多就要排队存算分离下对象存储本身可以支撑很高的并发理论上计算侧有多少并发就能吃多少并发但如果数据组织得不好对象存储的请求QPS限制反而会成为新瓶颈。这个坑在小文件场景最为明显后面实测部分会专门讲。第三个来源是资源供给模型不同带来的排队效应差异。传统架构面对突发流量只能让任务在队列里干等资源不够就是不够存算分离则可以快速拉起一份新计算资源用弹性的方式把排队时间转化为资源调度时间。这个差异不会直接体现在单条SQL的耗时上但对业务侧早晚高峰的体感影响非常大。3. 实测环境准备与方案设计3.1 两套隔离环境的具体配置为了不被硬件差异干扰我们尽量把两边的基础硬件配成同一水平。每套环境都用了8台裸机配置完全相同差别只在软件架构层面。下表是我们最终的配置清单。项目传统架构存算一体存算分离架构节点数量8台计算4台存储4台单机配置48核 / 256GB / 4块1.92TB SSD 12块12TB HDD计算节点48核/256GB/4块1.92TB SSD存储节点48核/256GB/12块12TB HDD存储方案HDFS三副本MinIO三副本对象存储协议计算引擎Spark 3.3 / Hive 3.1Spark 3.3 / Trino 397资源管理YARNKubernetes调度器Capacity Scheduler自定义弹性队列网络万兆万兆这里要特别说明的是为了模拟真实的存算分离我们没有让MinIO和计算进程混部在同一批机器上而是单独用4台机器做存储节点另外4台只跑计算走万兆网络连接。这样得到的数据更接近生产环境但也意味着网络延迟带来的损耗会完整地暴露出来不会因为混部而显得好看。3.2 测试数据与测试工具测试数据没有用那种太干净的公开数据集而是直接用生产业务的脱敏数据。一共1TB覆盖300多张核心业务表包含宽表、明细表、维度表文件格式统一为Parquet按日期分区。之所以选业务数据做主测试集是因为公开数据集的分布特性跟实际业务差别太大测出来的结论没有说服力。同时也加了一组标准TPC-DS测试数据集规模选了100GB用来跑完全一样的99条查询做横向参考。毕竟业务数据的特性不透明如果只拿业务查询说事换一个场景可能就不成立了。两边都跑同一套TPC-DS的Spark SQL版本尽量让对比口径一致。3.3 测试指标定义我们统一按这几个指标收集数据。平均耗时和P95耗时反映绝大多数查询的体感任务吞吐量看单位时间完成的查询数和并发下的表现资源利用率看CPU、内存、存储IO的实际使用比例弹性扩展时间从发起扩容到新节点可被调度的时间单位成本按三年折旧把硬件、存储、网络、运维折算成每TB数据每月的费用。口径在两边完全一致同一个SQL文本只在必要情况下替换表名和连接参数。每一轮跑完之后清空缓存再跑第二轮避免缓存命中给某一侧加分或者减分。4. 实测结果性能与资源数据全记录4.1 SQL查询性能冷热数据差异明显先看冷数据场景也就是每次查询前把OS缓存、对象存储缓存全部清掉保证两边都是从存储里真正读文件。老实说第一轮数据出来之后团队里支持存算分离的人心里是有点虚的。冷数据下单表聚合和关联查询确实是传统架构占优这意味着我们后面要想办法在缓存层和参数层面把差距找回来。场景传统架构平均耗时存算分离平均耗时差距冷数据单表聚合查询100GB42秒58秒38%冷数据多表关联查询10个表200GB3分12秒4分05秒27%热数据重复查询同一条SQL跑第二遍8秒9秒12%冷数据场景下存算分离平均慢20%-40%这个结果符合我们的预期。但热数据场景非常有意思存算分离在SSD缓存命中后差距可以压到10%左右甚至在一些数据量不大但执行计划复杂的查询上反超传统架构。原因不难理解传统架构虽然本地读盘但HDFS三副本的元数据开销和节点间数据倾斜让某些查询执行起来没有那么理想。4.2 ETL批量任务shuffle才是真正的胜负手SQL查询只是前菜核心批处理任务的对比才是我们最关心的。因为批处理任务是平台每天凌晨要打硬仗的地方任何百分比的变化都会换算成业务方早上看报表的时间。我们挑了三个有代表性的ETL作业覆盖大shuffle、小shuffle和纯输出三种情况。一个大shuffle的全量拉链表加工shuffle数据量大约800GB一个轻度清洗的增量任务shuffle数据量大约120GB一个写最终业务宽表的任务输出量300GB。任务类型传统架构耗时存算分离耗时差距全量拉链表加工shuffle 800GB26分钟31分钟19%增量清洗任务shuffle 120GB9分钟10分30秒16%宽表输出任务输出 300GB18分钟21分钟17%批量任务整体慢15%-20%和SQL查询的冷数据结果基本一致。这里有一个重要变量shuffle中间文件落到本地SSD之后会做一轮自动分区分区多的时候任务之间的网络传输反而成为主要瓶颈。后来我们调整了spark.sql.shuffle.partitions这个参数把分区数从400改为与数据量更匹配的240存算分离一侧的耗时直接下降8%左右。这个后面在调优章节细说。4.3 资源利用率与弹性扩展存算分离的翻身仗性能上存算分离没有占到便宜但把资源利用率数据拉出来以后整个讨论的方向就不一样了。传统架构那套集群因为要保证晚高峰的批处理性能节点数是按峰值预留的。这就导致白天大部分时间CPU利用率只有15%-25%即使晚上大量跑批平均利用率也就50%上下。这里举个实际例子一套8台48核的集群白天可能有6台处于半闲置状态电费照样烧但你又不能把它们关了因为晚上的峰值任务会立刻用满它们。而存算分离环境下白天我们只保留4个计算节点晚上需要时动态扩展到8个忙完再缩回4个。这带来两个效果平均CPU利用率升到了60%左右更关键的是白天临时开发查询不再跟批处理抢资源因为可以随时开一个小规模的独立计算组。弹性扩展的实测数据是在Kubernetes上发出扩容指令后新节点Pod就绪并注册到Spark资源调度器平均耗时4分50秒。从用户视角看提交一个需要200个executor的大任务从资源不足告警到整个任务开始跑起来大约6分钟。理论上也可以把节点预热时间再压缩但6分钟对一个跑批平台来说已经足够让人满意了。4.4 综合成本测算三年TCO差距不小最后算钱。这块其实是财务最关心的也是存算分离能打赢传统架构的地方。传统架构要支撑未来三年的增长按我们现在的数据增长速度需要再买6台机器纯硬件大概要花40万左右还不算机柜、电费和硬盘故障更换。存算分离这边存储节点一次性投入20万计算节点因为可以弹性伸缩按三年折算下来实际采购量比传统架构少3台。更直观的计算方式是单TB存储成本。传统架构三副本实际可用空间是裸容量的三分之一。假设每块12TB硬盘采购价1500元12块盘一个节点裸容量144TB实际可用只有48TB。存算分离的对象存储虽然也做三副本但配合纠删码可以把冗余降到更低的水平我们这边4个存储节点共48块盘实际可用容量大约300TB单位存储成本比传统架构下降了约60%。当然这个数字没有把网络升级费用算进去。如果原来只有千兆网络存算分离需要万兆甚至25G网络这个成本必须单独评估。但对我们这个场景万兆是现成的所以三年TCO的差距仍然很明显。5. 踩坑记录与调优心法5.1 小文件才是最大的敌人存算分离第一个大坑就是小文件。对象存储对单次文件读写的请求是有固定延迟成本的如果一张分区表有几十万个小文件查询时Spark要枚举文件路径光plan阶段就能卡死。我们处理方式分两步。第一步是把分区写入的目标文件数调大用spark.sql.files.maxPartitionBytes配合自适应查询执行让每个输出文件尽量接近256MB而不是默认状态下的遍地小文件。第二步是建立周期性的小文件合并任务把一天生成的文件合并到合理粒度。合并完的效果非常明显同样一条扫描全表的SQL耗时从1分20秒降到40秒。这里说句实在话如果你的数据链路里整天产生大量小文件无论用什么架构都很难受但存算分离对这个问题尤其敏感。因为它没有HDFS那种可以缓存文件块列表的NameNode来兜底每次“列举目录”的成本都会被放大。5.2 网络抖动会被放大存算分离把存储挪到远端后网络质量被提到了空前重要的位置。实测期间我们遇到过两次查询突然变慢后来排查发现是万兆交换机上有个端口协商降速到了千兆一根网线的问题导致整个Spark executor读数据时延暴增。再一个是跨机柜。如果存储节点和计算节点不在同一个机柜中间还经过多级交换机延迟会成倍增加。调优时我们让executor尽量读取离自己最近的MinIO端点并且确保连接池不要被建满。另外要注意对象存储的请求连接数是有限制的默认并发太高时会报RequestTimeout这类错误。我们最后把spark.sql.files.openCostInBytes调大减少并发打开文件的数量同时把连接池的最大连接数配到和executor数量匹配问题才算消停。5.3 缓存策略既要也要的小技巧存算分离环境下热数据访问表现不差靠的是缓存。我们这轮测试用的是MinIO没有单独上缓存层而是用计算节点的本地SSD做了一层数据缓存具体办法是挂载JuiceFS这类文件系统缓存。没有引入单独的Alluxio集群因为那会增加一套系统要运维。对当前量级来说本地缓存已经够用。参数上我给读写缓存预留了每节点1.2TB的SSD空间缓存淘汰策略用LRU。实测下来常用报表的查询第二次以后的耗时和传统架构基本持平。如果你上的是云上的对象存储建议优先看一下它自带的数据缓存能力或者用Spark的local cache能省掉一套额外的组件。缓存这个东西属于典型的少一点就卡多一点又浪费建议根据热数据比例反复压测不要照抄别人的配比。5.4 元数据和权限体系要提前规划这个坑比较隐蔽。传统HDFS上我们用Ranger管控权限切到对象存储后Ranger策略并不能直接作用到MinIO桶。后来我们在MinIO侧重新配置了对应的桶策略并让Spark读取时用统一的临时凭证避免把访问密钥写死在配置里。这个事如果没提前做迁移后第一周就会被安全评审喊停。另外对象存储的目录命名和HDFS习惯完全不同HDFS里下划线开头是隐藏目录而对象存储没有这个概念脚本里如果有依赖隐藏目录逻辑的迁移后很容易出问题。6. 选型建议与一些实在话6.1 我建议选存算分离的场景如果你的业务满足下面任意几条存算分离值得重点考虑。第一存储增长快于计算增长。数据每天在增加但计算峰值不随之上升存算分离能避免反复为存储配计算。第二计算波峰波谷非常明显。白天查询多、晚上跑批是常见峰谷能够弹性伸缩省下的成本非常可观。第三多个计算引擎需要共享同一份数据。比如一套Spark做ETL一套Trino做即席查询大家都读同一份文件对象存储天然适合这种模式。第四正好到了机器置换周期。存量裸机已经折旧完这时候转存算分离的边际成本最低。6.2 哪些场景建议继续留在传统架构反过来也有几类场景硬迁存算分离是给自己找罪受。如果你的集群只有十几TB数据一台机器就能装下根本没有规模问题没必要折腾。如果你有大量事务性写入和强一致性需求对象存储在这方面不是强项传统HDFS或者专门的数据库系统更合适。如果你原有的作业对数据本地性高度依赖比如很多MapReduce任务直接读HDFS块迁移改造成本会非常高。还有一种是团队运维能力偏弱没有专职大数据运维对象存储的网络调优、缓存配置这些工作交给谁来做要提前摊开问清楚。6.3 迁移过程中的一些建议如果决定要迁我的建议是别搞“一刀切”。先拿最冷的一批历史数据做试点迁移到对象存储上让报表查询指向新的数据副本跑两周看看稳定性。同时保留HDFS上的那份数据作为回退点。等确认没问题再把增量链路切过去。整体节奏大概是先数据双写再读流量切换最后按保留策略清理旧副本。还有一点非常实际迁移期间一定要保证从对象存储读路径上有一个本地缓存层否则业务方第一天就会被冷查询的性能波动惊吓到。我们就是因为提前配好了缓存业务方基本没有感知到切换过程。另外建议把容量配额和访问监控都提前接入对象存储的请求数、流量、延迟这几个指标在迁移初期波动非常大没有监控等于裸奔。6.4 最后说几句实在话文章写到这里已经比较长了最后再分享一点我的个人体会。存算分离的本质不是一种“更快”的架构而是一种“更合身”的架构。它把存储从计算里拆出来让两者可以分别按需扩展代价是多了一条网络链路和一堆新的运维学问。你拿它跟传统架构比性能在冷数据、小文件、shuffle密集的场景下它确实不占便宜但要比长期成本、弹性、多引擎共享它几乎全面占优。如果你现在正纠结要不要迁移我的建议是先把业务场景列出来把上面这套测试方案照着自己的数据跑一遍用结果说话。我见过太多团队因为看了某个分享就直接上存算分离结果数据量连1TB都不到纯属自找麻烦也见过一些团队存储和计算的增长速度已经严重失衡还守着传统架构不肯放手。架构选型这事没有银弹只有合身。测试方法我已经写得很详细了哪怕环境不完全一样结论的参考价值也还在。如果还有具体场景上的问题欢迎在评论区留言我尽量把当时记录的数据翻出来回复。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价