先聊点实在的。这几年我深度参与过几套大数据底座的改造,从早期纯 HDFS 的数仓,到后来把热数、温数、冷数分层到对象存储,再到现在帮团队做存算分离方案的选型评估,最大的感受是:存算分离并不神秘,但远没有到“无脑乱选”的程度,它就是一次对集群资源管理方式的重构——把计算和存储从“绑死的资源”里拆出来,让两边各自独立扩缩容。而这份“技术选型指南”,本质上是要回答三个问题:你的数据规模够不够大?你的工作负载适不适合分离?选完方案后能不能平稳落地?
这篇内容我会直接从底层原理讲起,把 HDFS、对象存储、湖仓一体化方案的差异掰开讲清楚,再给出一套可落地的选型决策框架,包括成本估算、网络带宽评估、缓存层设计、迁移操作细节,以及我踩过的那些坑。适合正在做集群规划、想要优化资源利用率、或者被领导要求“出一个存算分离方案”的同学参考。
1. 存算分离到底是怎么一回事
1.1 为什么过去“存算一体”是主流
早期大数据生态基本绕不开 HDFS。NameNode 管元数据,DataNode 管数据块,MapReduce、Spark 这些计算框架跑在集群里,数据和计算天然在同一批机器上。这种“存算一体”的架构之所以能流行十几年,核心原因是 data locality——数据本地性,也就是让计算尽量靠近数据所在的磁盘,减少网络传输。
我最早搭 Hadoop 集群的时候,对 data locality 的理解非常朴素:谁有数据谁干活,网络 IO 尽量少。那时候万兆网还不普及,千兆网络下从远程节点拉数据可能比本地磁盘读慢一个数量级,所以把数据和计算放在同一批机器里,效率确实最高。再加上磁盘和 CPU 都很贵,一套物理机既当存储又当计算,性价比也没问题。
但这里有个隐含约束:HDFS 的容错是依赖数据副本的,默认三副本意味着存储利用率最高只有三分之一。而且当集群规模到了一定程度,你往往会发现计算资源和存储资源根本不是一个节奏在增长——业务高峰需要几百个 CPU,低谷可能只需要几十个;但数据却一直在涨,磁盘只进不出。于是某个时刻你会发现:要不 CPU 闲着,要不磁盘满了,怎么调都不对。
1.2 存算分离真正要解决的三类痛点
第一类痛点是资源利用率。业务负载有明显波峰波谷时,存算一体集群只能按峰值预留计算资源,低谷时段大量 CPU 和内存空转,但电费和维护成本一分不少。存算分离之后,计算集群可以按需启动,跑完缩容,存储层始终保持稳定。
第二类痛点是弹性与独立扩展。数据分析、临时需求、实验性作业可能突然出现,单独为这些负载扩容一套计算集群,用完后销毁,在存算一体架构下几乎不可能,因为机器又跑数据又跑计算,销毁等于丢数据。存算分离后,存储数据独立,计算集群想扩就扩、想缩就缩,完全不干扰数据安全。
第三类痛点是成本结构。成熟对象存储的每 GB 单价通常低于自建 HDFS 的高可用存储,尤其是考虑三副本和运维成本之后。把冷数据转移到对象存储,能显著降低整体的存储开销,但这部分节省的实际效果和你的访问模式、网络架构直接相关,并不是必然成立。
1.3 不是什么场景都适合存算分离
必须泼一盆冷水:存算分离不是银弹。如果你的集群只有几十 TB 规模、作业运行时间短、并发度不高,而且机器资源常年吃紧但也没到瓶颈,那么引入存算分离方案大概率只会增加复杂度,收益却不明显。
还有一个硬条件:网络。存算分离的本质是用网络换弹性,网络带宽不够,所有计算引擎都会卡在数据读取上。举个具体数字:跑一个 TPC-DS 测试,从 HDFS 换成远程对象存储后,如果只有千兆网络,同样的 SQL 可能慢一倍以上;如果能跑满万兆甚至 25G 网络,性能差距可以控制在可接受范围。
另外,如果你的业务对数据一致性要求极其苛刻,比如强事务、高频更新,当前很多存算分离的底层存储和元数据层还不一定能满足你。这不是说存算分离不能做到强一致,而是成熟度和验证案例可能不如 HDFS 丰富,选型时要做好技术验证和风险判断。
2. 主流技术路线横向对比
2.1 HDFS 底座:最保守但未必最差的选择
存算分离不是说不能用 HDFS,而是要让 HDFS 节点专注于存储,计算节点独立出来去读它。这种方案的变体很多:南向走 HDFS 的 Federation 做命名空间隔离,北向用 YARN、K8s 调度无状态计算 Pod,所有引擎通过网络去读 HDFS。
这种方案的优势是数据兼容度极高,因为 HDFS 本身就是 Hadoop 生态的“母语”,Ranger、Sentry 的权限体系、Hive 的 ACID、Spark 的 FileSource 等都天然适配。而且从存算一体迁移到这种模式,不需要改数据格式,不需要换计算引擎,也不用写额外的兼容层。
劣势也很明显:HDFS 毕竟是文件系统,NameNode 的内存上限、RPC 并发能力在超大规模下会成为瓶颈;三副本的成本在那里摆着;对象存储的很多生态能力(比如生命周期管理、跨区域复制、冷热转储)它没有或很弱。所以 HDFS 底座更适合那些对数据主权和管理边界要求高、不想依赖云厂商、且能接受三副本成本的团队。
2.2 对象存储底座:当前性价比最高的主流
对象存储是存算分离中最常见的数据底座,阿里云 OSS、腾讯云 COS、AWS S3 都属于这一类,Hadoop 生态里通过 S3A、OSS 的 connector 访问。这套模式的核心是把数据放在对象存储中,计算集群本地不再长期持有数据,只保留临时缓存或 shuffle 数据。
为什么推荐它作为主流选项?首先是成本。对象存储天然多副本或纠删码,单 GB 价格远低于自建 HDFS 的三副本;其次是弹性,对象存储的带宽和容量可以按需扩容,不会像 HDFS 那样需要往集群里加 DataNode;再次是稳定,对象存储的服务化能力通常由专业团队维护,几乎不需要自建存储的日常运维。
缺点是对象存储不是 POSIX 文件系统,随机写、目录 rename、小文件并发访问都存在一些限制。尤其是小文件问题,在 HDFS 上一个小文件只占用一个 block(默认 128MB),在对象存储上每个小文件都是一次完整的 PUT/GET 请求,元数据和请求费用会被放大。所以在对象存储底座的技术选型中,“小文件治理”几乎是一个必须提前规划的课题。
2.3 湖仓一体与存算分离的融合
如果只是把数据搬上对象存储,上面的表结构、文件格式、元数据管理还是老一套,那叫“伪存算分离”。真正有价值的是结合湖仓一体方案,比如 Iceberg、Hudi、Delta Lake 这类表格式,配合统一的 Catalog 服务,让 Spark、Flink、Trino 等多个引擎共享同一份数据、同一套事务语义。
湖仓一体和存算分离叠加的效果是什么?举个例子,数据团队经常遇到几个引擎同时读一份表——Spark 跑批处理,Trino 跑即席查询,Flink 做实时入库。如果都用同一份 Hive 表,文件覆盖和 ACID 事务很容易出问题。引入 Iceberg 这类表格式后,不同引擎通过 Catalog 和快照隔离来读写同一份数据,就不会互相踩脚,同时底层的文件还可以放在对象存储上,最终形成“存储对象化、元数据统一化、计算多引擎化”的完整体系。
这里最重要的选型考量是:你的团队是否具备玩转两类技术的能力?Lakehouse 的好处很多,但代价是引入了新组件、新概念、新的监控维度。如果团队连 Spark SQL 都还没完全吃透,建议先把存算分离做扎实,再逐步引入湖仓。
2.4 三种路线的适用边界
| 方案 | 存储成本 | 数据兼容性 | 弹性扩展 | 运维复杂度 | 适合场景 |
|---|---|---|---|---|---|
| HDFS 底座 | 高(三副本) | 最高 | 弱 | 中 | 数据主权要求高、强事务场景 |
| 对象存储底座 | 低 | 高(需适配) | 强 | 低 | 最普遍,批处理+即席查询 |
| 湖仓一体方案 | 低 | 中(需改造) | 强 | 高 | 多引擎共享、实时+离线融合 |
记住:选技术路线不是“哪个新选哪个”,而是“哪个方案对应的问题是你真正要解决的”。HDFS 底座看着老,但如果你所在行业对数据审计和本地化要求极高,它就是那个最可靠的选择;对象存储看着成熟,但如果你们的网络建设严重滞后,选择了它等于给自己挖坑。
3. 技术选型的核心考量维度
3.1 数据规模与访问模型决定下限
存算分离方案的下限由数据规模和访问模型决定。十 TB 级别的数据量,你只要做一个很简单的 HDFS 到 OSS 的数据迁移,再加一个 Hive on OSS 的引擎适配就够了;百 TB 级别就要开始考虑分区布局、查询裁剪、缓存策略;PB 级别则必须把元数据服务、连接数、对象存储的请求配额全部纳入设计。
访问模型指的是读多写多、大文件还是小文件、顺序读还是随机读。大数据分析里典型的访问模型是“批量顺序读 + 过滤后聚合”,这种模型对对象存储非常友好;但是如果你有大量点查,每秒几万次 GetObject 请求,对象存储不一定扛得住,这时候要么上缓存层,要么改造查询模式。
我之前评估过一个广告业务集群,表面看每天跑几十个 Hive 任务,数据量只有 20TB,觉得搬对象存储很轻松。细看才发现 70% 的任务数据来源于几十万个小文件,每个文件只有几 KB。对象存储的请求费用和并发瓶颈会直接拖垮整个方案。所以选型之前,有必要先做一轮数据画像:文件数量、平均大小、单任务读取路径、缓存命中率预期,这些指标比单纯的容量更关键。
3.2 成本结构不能只看存储单价
存算分离的成本,不只是你买的云产品标价。我见过不少团队看到 OSS 单价便宜,就赶紧把数据迁上去,最后月底账单出来傻眼了——流量费、请求费、低频存储提前取回费,加起来比原来 HDFS 的使用成本还高。
完整的成本模型至少包含四个方面:存储容量费、访问请求费、公网流量费(即使内网也要考虑跨可用区流量)、以及计算层的缓存加速费用。其中请求费最容易忽视,对象存储对 GET 请求、PUT 请求和 LIST 请求分别计费,而大数据场景里 Spark Job 的 task 数量巨大,每个 task 都要去 list 分区、get 文件元信息,请求量很容易超预期。
另一个容易被低估的是“冗余成本”。自建 HDFS 用三副本,实际可用存储是物理容量的三分之一;对象存储一般默认提供跨 AZ 的冗余能力,价格已经包含在单价里。如果你拿 HDFS 的物理裸容量单价去比对象存储的单价,就会产生“对象存储很贵”的错误判断。正确的比较口径是:可用容量成本的对比,外加请求、流量和运维人力。
3.3 计算引擎与生态兼容性
选型时一定要先列清楚你们当前用的计算引擎清单。Spark、Flink、Trino、Hive 对对象存储的支持成熟度差异很大:Spark 通过spark.hadoop.fs.s3a或独立 connector 能很好地读写对象存储,Trino 对 S3 的native配置也很顺,但 Hive 的某些 ACID 操作在对象存储上可能没法用,Flink 的增量 Checkpoint 在某些对象存储上有兼容性问题。
对于可能存在的不兼容,不要只看官网文档,要实际做一轮“最小复现测试”:把核心表的读、写、增量更新、删除操作在目标对象存储上跑一遍,同时记录执行计划和异常堆栈。很多时候问题不在于 A 产品支不支持,而在于你们代码里写死的路径前缀、文件系统抽象、权限校验逻辑,能不能平滑适配新存储。
另外要特别关注“元数据服务”。存算分离后数据和计算分开了,但表结构、分区信息、权限配置必须保留。主流选择是 Hive Metastore 或独立 Catalog 服务,选型时重点评估其扩展性、高可用能力、以及和对象存储的“list-after-rename”冲突处理机制。
3.4 缓存层:选型中的隐藏关键
存算分离不代表每次计算都去远端读全量数据,成熟方案通常会在计算层和数据层之间加一层缓存,比如 Alluxio、JindoFS 的 Cache 模式,或者计算引擎自带的 result cache、data skipping 机制。
缓存的引入会极大改变性能和成本结构。读数据时先查本地缓存,本地缓存没有再去对象存储拉,拉回来后既返回计算引擎,又写进本地缓存。热数据命中后,远端请求量下降,请求费用大幅降低,查询延迟也明显改善。但缓存也带来副作用:本地缓存盘占用需要规划,缓存淘汰策略要按业务特征定制,冷启动阶段的性能衰减要能接受。
这块经验是:不要一开始就上分布式缓存组件,先看计算引擎自带的 cache 机制能不能满足,比如 Spark 的spark.sql.files.openCostInBytes、Parquet 的 footer 缓存、Trino 的 split manager。只有缓存命中率低且业务对延迟感知强时,再考虑引入 Alluxio 或 JindoFS,否则就是多一层组件多一份运维成本。
4. 选型决策示例与配置参考
4.1 场景A:中小规模集群如何选
假设你的团队维护着 30 台物理机的 Hadoop 集群,数据量约 50TB,主要跑 T+1 的数仓任务,偶发 ad-hoc 查询,资源紧张但没有到不可容忍的地步。
这种情况下,我建议采用“HDFS + 对象存储分层”的轻量存算分离方案,而不是激进地把所有数据搬到对象存储。具体做法是:冷热数据分层,最近 30 天的热数据留在 HDFS 上,更早的数据通过任务调度迁移到对象存储,Hive 表通过分区级 location 指定存储位置;计算引擎配置一套统一的 HDFS federation 或 schema 映射,让用户无感访问两部分数据。
这个方案的改动量最小,短期就能见效。需要注意的是数据迁移任务的管理,我推荐为每个业务表建独立的迁移 Job,用时间分区作为批次依据,定期执行,迁移前记录数据校验和,迁移后做目录级对比。这套流程即便未来全面转向对象存储,也可以直接复用。
4.2 场景B:大规模批处理+交互查询混合负载
这类场景通常有几十到几百 TB 甚至 PB 级的离线数据,同时存在大量即席查询和 BI 报表需求,资源弹性尤为重要。
我会优先选择完整对象存储底座,配合一个轻量缓存层,再统一使用 Spark + Trino 双引擎。存储层用 OSS/COS/S3,表格式默认 Parquet 或 ORC,按日期分区;计算层分为两个集群,一个专跑离线批处理,一个专跑即席查询,两个集群共享同一个 Catalog 和同一个对象存储 bucket。
这里有个关键设计:离线集群和交互查询集群要隔离资源,但要共享数据权限。操作上,可以在 IAM 或云账号体系里为主机角色分配不同的读/写策略,写权限只给离线集群,读权限两个集群都有,这样即席查询只能读,避免误写破坏数据。
4.3 Spark 对接对象存储的核心配置
Spark 读写对象存储的配置是落地中绕不开的环节,以 S3A 协议为例,核心参数如下:
spark.hadoop.fs.s3a.endpoint=<endpoint> spark.hadoop.fs.s3a.access.key=<accessKey> spark.hadoop.fs.s3a.secret.key=<secretKey> spark.hadoop.fs.s3a.path.style.access=true spark.hadoop.fs.s3a.connection.maximum=512 spark.hadoop.fs.s3a.connection.timeout=60000 spark.hadoop.fs.s3a.attempts.maximum=10 spark.hadoop.fs.s3a.threads.max=64 spark.hadoop.fs.s3a.fast.upload=true spark.hadoop.fs.s3a.fast.upload.buffer=disk spark.hadoop.fs.s3a.multipart.size=128M spark.hadoop.fs.s3a.committer.name=magic其中multipart.size会影响 TN 级大文件的上传性能,推荐设置在 64M 到 256M 之间;fast.upload.buffer设为 disk 可以避免大规模写入时内存溢出;connection.maximum要根据 job 并发 task 数据调整,一般 256 到 1024 之间合理。
另外建议开启 Spark 的 Dynamic Partition Pruning 和 Object Store 的select下推,减少从对象存储拉取的数据量。这里有个经验:把分区字段设计为日期、地域这类低基数字段,能显著提升查询裁剪效果。
实际配置时还要在core-site.xml或 Spark 启动配置里统一设置,避免每个 job 单独传参。注意对象存储的 AK/SK 不要写死在代码里,建议通过环境变量、Hadoop Credential Provider 或云平台的实例角色注入,这样权限审计和轮换都更方便。
4.4 成本估算的一个简单模型
在设计阶段,最好做一个基础的成本表格。假设你的数据总量为 1PB,副本策略从 HDFS 三副本切换到对象存储单副本(带跨 AZ 冗余),存储层面大概节约多少?我们可以这样算:
- HDFS 三副本下,扣掉 NameNode 和系统空间,1PB 实际数据需要约 3PB 物理存储;按照单 TB 每月 200 元的维护成本计算,每月就是 31000200=60万元。
- 对象存储按可用 1PB 计费,单价如果为 0.12 元/GB/月,则每月成本约为 1000*0.12=120 元/TB/月,乘以 1000TB 就是 12 万元/月。
这只是存储费用的粗略对比,实际还少算了原来 HDFS 那批机器上 CPU 的折旧——存储集群的 CPU 可能只在做块校验和复制时用到,绝大部分时间闲置。把这些也算进去,存算分离后计算资源利用率提升带来的成本节省会更明显。
但反过来,不能忽略对象存储的请求费。如果你每天有 100 万个 Spark Task,每个 Task 都要执行一次 list 分区、两次 get 文件元数据,每天请求量就是 300 万次,一个月会多出上百万次的外部服务调用,虽然单价很低,但累积起来也要计入成本。所以建议在方案里加上“请求费用预估”这一行,并制定削减请求的措施,比如开启目录分区缓存、适当增大文件粒度。
5. 落地迁移的实操过程
5.1 迁移前要做的事:盘点与校验
从 HDFS 迁移到对象存储,绝对不是“跑个 distcp 就完事”。在迁移之前,我会建议团队做三个准备动作:全量数据画像、SLA 确认、回滚预案。
数据画像要回答几个问题:哪些表是热表、哪些表是归档表;每张表有多少文件、平均文件大小;表之间的依赖关系和上游产出时间;每天新增数据量以及最大分区大小。有了这个画像,才能确定迁移顺序——通常先把体积大、访问频率低的冷数据迁过去,风险最低;再把中低频的中间表迁过去;最后评估核心热表是否要迁移。
SLA 确认是容易被忽视的环节。迁移期间如果某个核心报表延迟出数,能否接受?如果不能,就要设置“影子任务”,在迁移完成后先跑影子验证任务,对比新旧路径下相同 SQL 的输出结果以及运行时长,确认无异常后,再在调度系统把数据路径切到新位置。
回滚预案要落到操作文档里。我的做法是:每次迁移一个分区或者一张表,迁移完成后立即写入一个_MIGRATION_COMPLETE标记文件;如果后续验证失败,调度系统可一键切回旧 HDFS 路径,不需要重新迁移已有数据。看似多了一个文件,实际上能大幅减少事故恢复时间,非常值得。
5.2 distcp 迁移的执行细节
最常用的工具是 Hadoop 自带的 distcp。一条典型的命令如下:
hadoop distcp -Dfs.s3a.endpoint=<endpoint> \ -Dfs.s3a.access.key=<accessKey> \ -Dfs.s3a.secret.key=<secretKey> \ -m 200 \ -numListstatusThreads 50 \ -update \ -delete \ hdfs://namenode:8020/user/hive/warehouse/dim.db/my_table \ s3a://my-bucket/warehouse/dim.db/my_table-update可以在增量迁移场景下只传输新变化的文件,-delete可以删除目标端多余文件,两个参数联合使用时,实质上是把 distcp 变成了“同步任务”,很适合周期性增量迁移场景。
执行时要注意-m参数大小。-m太小,客户端并行度不够,跑得慢;太大又可能把 NameNode 和对象存储的请求配额打满。一般 200 到 500 之间比较稳妥,1500 以上反而会引起限流,出现大量重试。我建议在迁移前先做一个小分区测试,测出当前网络和对象存储能承受的最大并行度,然后按 80% 的阈值设置。
迁移完成后,要在第一批数据上执行fsck或对象存储的 checksum 校验。distcp 默认会做 CRC32 校验,但只能校验文件大小和块数量,无法识别文件内容级别的轻微差异。对于特别核心的数据表,我会额外跑一个 Spark 任务做字段级抽样比对,确保数据一致。
5.3 计算侧适配与验证
数据迁移到对象存储后,计算侧要改的地方也不少。第一是 Hive 表的 location 指到新的对象存储路径;第二是 Spark、Flink、Trino 中关于文件系统的相关配置要同步更新;第三是调度系统的数据加载和输出路径检查。
这里分享一下我的验证顺序:先做连通性验证,确保计算集群能通过 Hadoop 兼容接口访问对象存储;再做性能摸底,针对典型 SQL,分别记录 HDFS 和对象存储下的执行时间,重点看瓶颈是否从 CPU/内存转移到了网络 IO;最后做全链路回归,把几个核心数据任务的输入输出路径切到新的存储路径,观察一整天。
这个阶段最常遇到的问题是“任务在 HDFS 上能跑,切到对象存储后非常慢”,原因往往是没启用 fast upload、分区裁剪失效、文件数量和大小没有优化。慢的排查思路是:先看 Spark UI 的 stage 耗时,再看 Executor 的 IO 指标,最后看对象存储的访问日志。数据读慢大概率是拉取量太大,写慢大概率是传输并发或缓冲配置不对。
6. 常见问题与排查技巧实录
6.1 小文件问题:无感的成本黑洞
存算分离方案中,小文件问题被放大得非常明显。对象存储上大量几 KB 的文件会导致 list 请求激增、读放大严重、即使 SQL 只扫描 1MB 数据,也可能触发几万次 GET 请求,最后性能极差、账单极贵。
解决手段我一般按三个阶段来做:迁前治理,在迁移之前先把小文件合并到大文件,通常用 Spark 的repartition或coalesce重写目标分区,把文件控制在 256MB 到 1GB 之间;迁移时控制并行度,避免 distcp 把大文件切碎;运行期持续治理,建立周期性监控,对文件数量异常增长的分区发出告警并触发合并任务。
对于流式写入产生的文件碎片,建议让 Flink 或 Spark Streaming 的 Checkpoint 周期与文件滚动周期匹配,尽量以较大的 checkpoint 间隔生成较大的文件,否则当天写入就可能创建上百万个小文件。
6.2 网络带宽与访问限流
对象存储在服务端有请求配额,超了会返回 503 或 429,Spark 作业会因此不断重试,表现为偶发任务卡顿、重复执行、整体变慢。这个问题的排查思路是先看对象存储侧的可观测指标,比如 QPS、平均延迟、错误码,再对比任务高峰和限流发生的时间窗口。
应对限流的策略有三个:优化数据体量,通过分区裁剪、列裁剪、数据 skipping 减少请求次数;提高单文件访问效率,尽量一次拉大文件而不是频繁拉小文件;最后是降低作业并行度,对 task 数量做合理控制。不要一遇到限流就无脑增加重试次数,那样只会让对象存储配额更快被打满。
另外网络带宽一定要提前规划和测试。我曾经在迁移时忽略了一个细节:大数据集群在多个可用区都有节点,跨可用区访问对象存储会产生更高延迟和流量费用。后来我把计算集群整体安排到对象存储同可用区,IO 延迟下降了 40%,费用也有明显降低。上生产前务必检查每个 Executor 节点和目标 bucket 是否在同一可用区。
6.3 一致性与权限问题
读 HDFS 时,Hive 表通过 rename 操作实现“原子提交”,因为 HDFS 的 rename 在同一个命名空间内是原子的并带锁。对象存储上的 rename 则是“先 copy 再 delete”,中间状态可能被并发查询看到,导致数据不一致。
这个问题的解决方案是引入目录级或表格式级的事务能力。Iceberg 这类表格式通过元数据文件来管理快照,写入完成后只修改元数据指针,底层文件不做原地覆盖,天然避免了 rename 带来的不一致问题。没有上 Iceberg 的话,可以怎么做?我的建议是:写任务先写到临时目录,完成后再通过计算引擎或任务调度执行一次“双阶段提交”,保证使用者不会读到半成品数据。
权限体系方面,Ranger 策略依赖 HDFS 路径,切到对象存储后要重新配置。好的做法是统一用云平台 IAM 做基础权限隔离,用 Ranger/Sentry 做表级权限控制,两层结合。我见过很多团队切到对象存储后只给了 AK/SK,导致所有作业共有同一份读写权限,数据审计完全失效——这个坑一定要避免。
7. 收个尾,说点实际的心得
这几套方案都跑过之后,我个人体会就是:存算分离是一个“系统工程”,而不是一个“组件替换”。如果只把存储换了,计算侧的资源调度、数据治理、成本模型、监控告警不跟着变,那只是把 HDFS 换了个名字放在云上,本质区别不大。
选型阶段一定要舍得花时间做测算和验证。数据量、访问模式、网络带宽、团队能力、合规要求,五个维度缺一不可。遇到拿不准的方案组合,就做一个小规模的功能原型,拉一批真实查询跑一遍,比看一百篇架构对比文档都管用。
最后分享一个小技巧:在迁移后的前两周,一定要保留旧存储路径的只读快照,并开启调度系统层面的双写开关。这样一旦出现数据质量、权限、依赖问题,你可以快速回切,不会把团队推到“必须连夜修 bug”的处境。稳定落地比快速上线重要得多。