1. 项目背景:为什么大数据架构一定要动刀降本
先说个现实问题。我们团队之前维护的大数据平台,承担着全公司用户行为日志、订单流水、风控特征、推荐召回等核心链路的读写。高峰期日增数据量在几十TB级别,总存储量奔着PB去,组件也越上越多:HBase 管宽表,Redis 管缓存,ES 管检索,Kafka 做缓冲。架构看起来“全”,但每个月的账单和人力投入,站在 2024 年看已经非常夸张了。
老板给的目标很直接:在不砍业务、不降 SLA 的前提下,把平台整体的运维成本砍掉一半以上。说实话,刚接到这个任务的时候,我心里是有点虚的。因为按照惯性思路,成本降低往往意味着砍机器、降冗余,但这对大数据核心链路来说,很容易把稳定性搞崩。
我们最后选择的路子是:整体评估后发现自建 HBase 和自建 Redis 这两个大头,加起来占了集群成本的 60% 以上,且长期处于“高投入、低利用率”状态,于是决定将核心存储和缓存层迁移到瑶池数据库家族的 Lindorm 和 Tair 上,靠托管能力和冷热分离把成本结构彻底打散。
标题里写“运维成本降 60%”,这个数字不是拍脑袋算出来的,是综合了机器费用、存储费用、人力投入、迁移成本之后的一个总账。这篇文章我会把我们当初选型、评估、迁移、踩坑的全过程拆开讲清楚,适合正在为大数据平台成本头疼、或者准备做 HBase/Redis 迁移的技术负责人、架构师、运维同学参考。
需要先说明一点:每个团队的基线不同,降幅比例会有差异。但从自建 HBase + Redis 转向云上托管 Lindorm + Tair 的成本优化逻辑,是可复制的。文章里所有计算过程、参数选择、问题排查方法,都是我们实际跑过、验过的。
2. 整体设计与选型拆解:为什么是 Lindorm + Tair 的组合
2.1 自建 HBase 和 Redis 的真正痛点在哪
聊选型之前,得先把自建方案的痛点摆出来,不然“为什么换”这个问题说不透。
先算笔账。我们自建 HBase 集群用的是 12 台物理机,规格 32 核 64G,每台挂 4 块 3.84T NVMe SSD,跑三副本,可用存储大约 60T 左右。加上 3 台协调节点和 2 台 HMaster,硬件加机柜电费网络分摊,一年成本大约在 80 万上下。听起来还行对吧?但真正的问题是:
- 数据增长很快,60T 可用空间撑不过一个季度就会告警,扩容就得再买机器,周期 2 到 4 周,期间一直在“刀尖上跳舞”。
- 自建集群的机器利用率其实很低。因为要预留双十一这类大促的峰值能力,日常 QPS 只有峰值的 20% 左右,但机器是满配常开的,电费和折旧一点没少。
- 运维成本更是看不见的无底洞。Region Server 的 split 和 compaction、节点宕机后的数据均衡、HDFS 的磁盘均衡、小文件合并,这些都是实打实的人力投入。我们团队当时两个人一周至少三个下午都泡在 HBase 集群的各种“慢性病”里,根本没时间做业务优化。
Redis 这边的问题更典型。自建 Redis 集群 8 台 32G 机器,主从加哨兵,一年成本 30 万左右。但真正存的有效数据平均只有 15G 左右,其余全是预留内存和副本开销。更头疼的是,Redis 的持久化、故障自动切换、数据迁移这些事,全部要自己搞,经常大半夜被哨兵切换告警吵醒。
所以第一层结论就出来了:传统自建大数据组件,成本不是花在你“用到的那部分”上,而是花在“为可能发生的峰值和故障兜底”上。云数据库托管之所以能降本,本质上就是把“兜底成本”从你这边转移走,并按实际使用量计费。
2.2 为什么选 Lindorm 而不是继续用 HBase
既然决定要动,第一反应就是换云上的 HBase 托管。但后来对比了一下,发现瑶池 Lindorm 在成本和能力上,都比单纯的 HBase 托管更合适。
Lindorm 是阿里云推出的一款多模数据库,兼容 HBase、Cassandra、OpenTSDB 等宽表和时序 API。这意味着从自建 HBase 迁过去,业务代码基本不用大改,原来用 HBase 的 API 操作数据,迁移后改成 Lindorm 的客户端,接口语义是兼容的。我们当时线上服务端是用 Java 写的 HBase 客户端,迁移时把依赖切换成 Lindorm 的 client,改了配置和少量参数,核心读写逻辑一行没动。
但 Lindorm 真正的杀手锏,是它的存储计算分离和冷热分层能力。自建 HBase 的数据全部存在本地 SSD 上,不管数据多久没被访问,都占着同样的成本。而 Lindorm 天然支持把热数据放在高速存储上,把冷数据自动沉降到低成本的对象存储中,读取冷数据时的性能也还能接受。
拿我们自己的数据来说,用户行为日志类数据有明显的“热读窗口”,最近 7 天被频繁扫描,超过 30 天的数据几乎只有风控合规偶尔拉取。自建 HBase 里这些数据一视同仁占着 SSD,换算下来的单位存储成本非常高。Lindorm 冷热分离后,30 天前的数据自动转冷,热数据只占实际“正在被高频读写”的那部分,存储成本降得非常明显。
从成本结构上看,Lindorm 的计费也更灵活。按量付费加包年包月的组合,低峰期可以缩容,高峰期临时扩容,算下来的综合成本比自建低很多。我们迁移后做过一次对比,同样数据量下,Lindorm 的存储费用大约是自建 HBase 的 30% 到 40%,计算资源费用也少了一截。
2.3 Tair 在缓存层的能力和成本优势
缓存层选 Tair 的理由,跟选 Lindorm 有相似之处,但也有自己特别的考量。
Tair 是阿里云的内存数据库产品,完全兼容 Redis 协议和命令。从自建 Redis 切到 Tair,客户端基本不需要换,直接把连接地址改掉就行。这意味着业务侧的业务逻辑代码、缓存 key 设计、过期策略,完全不用动。
但 Tair 相对自建 Redis 有几个明显优势。一是高可用和容灾能力,Tair 默认就是主从高可用架构,故障自动切换由云端完成,不需要自己维护哨兵机制。二是数据持久化可靠性,自建 Redis 最怕的就是宕机丢数据,Tair 在持久化方面做了更多改进,能有效降低缓存穿透和雪崩的风险。三是规格选择灵活,可以按实际需要选择标准版或者集群版,内存和 QPS 不够时可以平滑扩容,不需要像自建集群那样先预留一大块资源。
成本上,Tair 同样走“按需付费”的逻辑。我们用 Tair 集群版,看起来每个月有一笔固定的实例费用,但对比之前自建 8 台 Redis 机器的成本,少了三副本内存的浪费,少了哨兵和备用节点的开销,整体费用降低了 50% 左右。更关键的是,运维成本直接归零——不用再被主从切换、内存碎片整理、RDB 备份这些事缠着了。
2.4 成本降 60% 是怎么分解出来的
很多人一看“降 60%”就觉得是夸张宣传。我列一个我们当时的实际成本对比表,大家就明白了。
自建方案改成云上方案之后,我算过一个总账,各项成本的减少基本来自以下几个方面:硬件和机柜费用因为不再需要自购和扩容消失了,运维人力因为托管而大幅释放,权限和控制面的管理也有了系统化的手段。
具体数字看起来是这样的:
| 成本项目 | 自建 Hadoop/HBase + Redis | Lindorm + Tair | 降幅 |
|---|---|---|---|
| 存储成本 | 本地 SSD 三副本,冷热同价 | 热数据 + 冷数据沉降对象存储 | 约 45% |
| 计算成本 | 常驻 12 台 RegionServer | 按需缩扩容,包年包月计价 | 约 30% |
| 缓存成本 | 8 台 Redis 主从 + 哨兵 | Tair 集群版 | 约 50% |
| 运维人力投入 | 2 人每周 3 天 | 1 人每周不到 1 天 | 约 85% |
综合下来,TCO 降幅确实在 60% 上下。这里的关键不是哪一个单项省了多少,而是存储、计算、人力、管理成本全部同时往下降,才有这个量级的整体效果。
3. 核心细节解析与实操要点:迁移前必须搞懂的几件事
3.1 先做容量和 QPS 评估,别急着下单
很多团队迁移云数据库,第一步就跑去开了实例,这是大忌。云上实例规格选大了,费用比自建还贵;选小了,业务高峰期直接被打爆。合理的方式是先做一次系统的容量评估。
我们在迁移前的评估分了三步走:
第一步,盘点现有数据规模。把 HBase 里所有表的行数、region 数、单行平均大小、列族数量、TTL 情况全部统计出来。这里容易踩的坑是:不能只看总存储量,还要看每个表的“热点分布”。比如某个大表的 rowkey 前缀是用户 ID,那访问就是高度倾斜的,对分片规则的要求就会更高。
第二步,压测确认 QPS 和时延基线。我们用了开源的 YCSB 和自研的模拟流量工具,按照线上读多写少的比例打了三天压测,统计出平均 QPS、峰值 QPS、P99 时延这几个关键指标。当时得出的结论是:宽表核心读写峰值 QPS 大约在 8 万左右,P99 时延要求控制在 20ms 以内。
第三步,根据压测结果和设备配额选择云上实例规格。Lindorm 的节点规格选择,主要看两个维度:CPU/内存规格和存储类型。我们最终选了 8 核 32G 的规格,存储配了 1.5T 热存储 + 大容量冷存储,预留了未来半年的增长空间。这里有个建议:冷存储的容量可以在初始时配小一点,后续按需扩容,因为冷存储的扩容成本和代价都很低。
3.2 数据模型映射和 rowkey 设计细节
从 HBase 迁到 Lindorm,表面上是“兼容的”,但细节上有几个地方必须注意,否则上线必出问题。
第一个是列族数量。HBase 建表时我们用了两个列族,一个存业务字段,一个存索引字段。Lindorm 的宽表模型对多列族的支持有限,官方建议单表一个列族。我们在迁移时直接把两个列族合并成了一个,原来的列名用分隔符区分,业务代码里做一次映射就行。
第二个是版本数和 TTL。HBase 里我们有些表开了 3 个版本,TTL 设置 30 天。Lindorm 同样支持这些语义,但要注意:TTL 的单位是秒,而且对冷数据同样生效。如果你原来把 TTL 当成“软删除”手段在用,迁移到 Lindorm 后要重新梳理一遍,避免冷数据被提前清掉,或者反过来,过期数据一直占着存储。
第三个是rowkey 的散列设计。自建 HBase 的时候,我们有些表的 rowkey 直接用时间戳做前缀,导致写入全部落在最后一个 region 上,热写问题非常严重。迁移到 Lindorm 时,我们把 rowkey 升级成了“用户 ID 哈希前缀 + 时间戳”的组合,写入可以均匀打散到各个分片上。这个改动对整体性能的提升非常明显,而且不需要改动业务主键逻辑,只是在生成 rowkey 的时候加了一段盐值。
3.3 Tair 的规格选择和命令兼容性验证
Tair 这边的评估相对简单,但也不代表可以随便选型。
先确认业务侧用了哪些 Redis 命令。我们用脚本扫描了全量代码,把所有 Redis 命令汇总去重,发现用的主要是 String、Hash、List、Set、ZSet 这几类的常用命令,以及少量 Lua 脚本。Tair 对这些命令的兼容性没有问题,但在 Lua 脚本和 pipeline 这类高级特性的表现上,建议在压测环境里实际跑一遍,避免极端场景下行为不一致。
规格选择上,Tair 分标准版和集群版。我们数据量不大但 QPS 波动大,最终选了集群版,设置了 16 个分片,每个分片 8G 内存。这么选的逻辑是:集群版可以根据流量增加分片,大促前临时扩容,结束后再缩回来,灵活性更好。而标准版更像原来的单机 Redis,升级需要迁移,扩缩容的弹性差一些。
还有一个容易被忽略的点是淘汰策略。自建 Redis 我们用的 allkeys-lru,迁移到 Tair 后,要确认实例的 maxmemory-policy 参数同样配置成这个值,否则默认的 noeviction 策略会在内存打满时直接报错,线上故障就来了。
3.4 冷热分离参数怎么设最合理
冷热分离是 Lindorm 降本的关键,但参数设置不好,很容易出现“该冷的不冷、该热的不热”的尴尬。
Lindorm 冷热分离的核心参数有两个维度:时间策略和访问策略。时间策略就是“超过多少天的数据转为冷存储”,访问策略则是“最近多少天内被访问过的数据保留在热存储中”。
我们在实际配置时,按表类型做了区分:
- 用户行为日志表:最近 7 天的数据为热,7 天前转冷。
- 订单流水表:最近 90 天为热,90 天前转冷。
- 风控特征表:因为实时风控查询频繁,最近 3 天为热,3 天前转冷。
这么设置之后,热存储的容量需求大幅降低,机器配的 1.5T 热空间足够用了,而冷存储因为用的是对象存储,成本大约只有热存储的十分之一。系统运行时,数据会在后台自动完成搬迁,业务无感。
需要注意,冷数据的读取性能比热数据要慢,从几毫秒变成几十毫秒甚至百毫秒。如果有些业务对冷数据也有高实时性要求,就不适合走冷存储,得单独建表保留在热区。我们当时就把“用户最近订单查询”这类高频率历史查询的表,强制设置为全热。
4. 实操过程与核心环节实现:从迁移到切换的完整流程
4.1 迁移策略:双写 + 全量快照 + 增量追平
数据迁移的方案选择,基本决定了整个过程的风险高低。我们最终采用“双写 + 全量快照 + 增量追平 + 校验 + 切流”五步走的方案,这也是目前业界比较稳妥的一种数据同步思路,虽然前期工作量大一些,但整体可控性很高。
第一步,代码层面启动双写。业务服务在原有写 HBase 的逻辑后面,增加了一份写 Lindorm 的逻辑。这里我们做了一个开关控制,刚开始只灰度 5% 的流量写入,跑两天确认无误后逐步放量。双写阶段,Lindorm 的数据会比 HBase 的数据“新”一点点,但因为我们只验证写入链路,不依赖它做读取,所以风险完全可控。
双写的伪代码大概长这样:
// 伪代码,实际实现时会封装成统一的 StoreClient public void writeRow(String tableName, Put put) { // 1. 先写老的 HBase hBaseClient.put(tableName, put); // 2. 异步写新的 Lindorm,失败只记录日志,不影响主流程 lindormAsyncClient.put(tableName, put) .whenComplete((result, error) -> { if (error != null) { log.error("双写 Lindorm 失败, table={}, rowkey={}", tableName, put.getRowKey()); } }); }这里有个经验:双写往云数据库写失败时,一定要异步记录日志,而不是同步重试。否则老库一个抖动,新库跟着被拖垮,两边一起出问题,反而更危险。
第二步,做全量数据快照迁移。我们用自研的导出工具,将 HBase 中现有 history 数据按表批量导出,再通过 Lindorm 的批量写接口导入。这里要注意的是,全量数据量很大,一次性导入会对线上造成压力,所以我们是按表名分批操作,每批控制在 500 万行左右,分时段执行,避开业务晚高峰。
第三步,增量追平。全量导入结束后,双写期间新产生的数据需要补到 Lindorm 上。这一步我们直接复用了双写逻辑,把灰度比例从 5% 逐步提升到 100%,保证新写入的数据始终同时落在两边。当两个集群的数据量差距稳定在一个很小的范围内时,就认为增量追平完成。
4.2 数据校验:抽样 + 总量 + 明细三层验证
数据迁移最怕的就是“感觉没丢,其实丢了”。我们当时做了三层校验,才敢放心切流。
总量校验:对每一张迁移的表,分别统计 HBase 和 Lindorm 中的总行数、总大小,两个值基本一致才能进入下一步。这里注意:由于双写开始后线上持续有写入,两边数量本来就可能有微小差异,所以我们定的阈值是差异小于 0.1% 就算通过。
抽样校验:按 rowkey 前缀随机抽 1000 条数据,逐字段比对 Lindorm 与源 HBase 中的数据是否完全一致。抽样不是全随机,而是按业务重要性加权——核心订单表多抽,日志表少抽。
明细校验:对于订单、账户这类关键表,我们直接把一天的增量数据做全量拉链校验,比对每个字段、每个版本,确保业务数据完全无损。
三层校验的核心原则是:在切流前,你必须对“新数据源是可信的”这一结论有底。如果校验有任何一个环节过不了,都得暂停迁移,先查清楚原因再继续。
4.3 Redis 到 Tair 的平滑迁移
缓存层的迁移比宽表要简单,但同样有细节。
我们的方案是:先用自研的迁移工具将 Redis 的存量数据全量导出并导入 Tair,然后开启 Tair 的增量同步,最后切换客户端连接地址。这个过程的业务影响很小,因为缓存本来就是可丢失、可再建的,即使有少量 key 没有同步过来,通过缓存穿透回源数据库也能补上。
关键在于切换时机的选择。我们是挑了一个业务低峰期的凌晨,将服务端的 Redis 连接配置从旧地址切换到新地址,先切一个机房,观察 10 分钟确认无异常,再切另一个机房。整个过程大概 30 分钟完成,线上没有任何感知。
缓存切换完成后,还有一件不能漏的事:确保旧 Redis 集群的 TTL 继续运行一段时间再下线。因为有些业务可能还残留了长连接或本地缓存引用,如果立刻关旧库,可能会引发线上异常。我们保留旧集群一周,每天观察 Tair 的命中率和 QPS,确认全部稳定后才正式下线。
4.4 切流与回滚预案
最后一步是切流,这也是整个迁移项目里最紧张的时刻。
我们的做法是按业务线灰度切流。先把对延迟不敏感的分析型业务切到 Lindorm,观察 24 小时,确认无问题;再把风控类等对一致性要求高的业务切过去;最后才切核心交易链路。每一条业务线切换时,后端服务通过配置中心动态切换数据源地址,不需要重启服务,这样即使出问题也能秒级回滚。
因为我们做了回滚预案,所以即使出现最坏的情况——Lindorm 在切流后出现性能问题,也能通过配置开关把流量拨回 HBase。不过实际情况是,全程没有触发一次回滚。从最终效果来看,整个切换过程对用户无感,Lindorm 和 Tair 的稳定性比我们预想中还要好一些。
5. 常见问题与排查技巧实录:真实踩坑记录
5.1 冷数据读取变慢,怎么优化
这是迁移 Lindorm 后第一个遇到的问题。上线一周后,数据分析团队反馈:查历史数据时,耗时有时会达到 200ms 甚至 500ms,比之前自建 HBase 还慢。
排查后发现,问题出在冷热分离的时间策略上。我们把用户行为日志表 7 天前的数据都转到了冷存储,但分析团队经常要查最近 15 天的数据做漏斗分析,这部分数据在冷存储里,性能自然差。
优化方案有两个:一是拉长热数据保留周期,把该表的热数据保留时间从 7 天改到 30 天;二是对冷数据建立访问优化,Lindorm 支持对冷数据按需缓存,在访问频率高的冷数据上开启读缓存,能显著降低读取延迟。我们两个方案都做了,效果很明显,P99 时延回到了 20ms 以内。
这里给一个经验:冷热分离配置不是一次到位,需要根据实际业务访问特征持续调整。上线后前两周,每周都要看一次访问数据,找出哪些表被频繁访问但数据在冷区,及时调整热数据保留天数。
5.2 Tair 热 Key 和读放大问题
切到 Tair 后,我们发现有个做秒杀的营销活动,活动开始后热 Key 的 QPS 瞬间飙到几十万。虽然 Tair 本身支撑住了,但下游数据库却被穿透流量打得很惨。
排查方案是用 Tair 的慢查询和热 Key 分析功能,定位到具体是哪个 key。然后我们做了两层优化:一是把热点 key 做了本地缓存,在服务端增加一层 Caffeine 缓存,过期时间设为 5 秒,大幅减少对 Tair 的直接访问;二是对特定活动场景的 key 做了数据分片,把单个 key 拆成 10 个带后缀的 key,均衡读写压力。
这类问题在自建 Redis 时代也会遇到,但 Tair 的热点分析工具让排查效率高了很多,不用再去翻慢日志和 INFO 输出。
5.3 Lindorm 写入堆积排查
上线后的一个晚上,监控显示 Lindorm 的写请求有堆积,队列深度持续上涨,P99 时延也出现抖动。
第一次遇到这种情况,容易慌。我们的排查思路是先区分是“业务流量涨了”还是“实例能力不够”。看了一轮监控后,发现是一个离线跑批任务在整点启动了批量写入,瞬间打高了写入 QPS。
处理方式很直接:一是把跑批任务的写入速度做限流,控制到实例评估吞吐的 80%;二是临时给 Lindorm 扩容了一个节点,等跑批任务结束再缩回去。Lindorm 在线扩缩容的功能帮了大忙,整个过程不需要重建集群,业务无感。
5.4 迁移过程中最容易忽略的三个“坑”总结
第一个是连接池参数。从自建 HBase 切到 Lindorm,服务端的连接池配置如果还是按原来那个量大值,很容易把 Lindorm 的资源占满。建议迁移后对连接池做一次压测校准,把 maxTotal、maxIdle 等参数调到合理范围。
第二个是客户端版本兼容性。Lindorm 虽然兼容 HBase 协议,但客户端库还是要用官方推荐的新版本。我们一开始用的旧 HBase 客户端版本,连接时有莫名的超时,换成官方最新版后问题消失。所以迁移前,一定要按官方兼容性列表核对依赖版本。
第三个是监控指标口径变化。Lindorm 和 Tair 控制台提供的监控指标,跟自建集群的粒度、口径不完全一样。迁移后要花一点时间去理解这些指标的含义,重新配置告警阈值,避免“告警疲劳”或者“该告警的没告警”。
5.5 常见问题速查表
我把这次迁移遇到的典型问题和解决方案整理成了一张表,后续团队接手时可以直接查:
| 问题现象 | 排查方向 | 解决方案 |
|---|---|---|
| 冷数据查询延迟高 | 数据是否落在冷存储 | 调整热数据保留周期,给高频冷数据开缓存 |
| 写入有堆积 | 是否有批量任务瞬时高吞吐 | 限流 + 临时扩容,错峰执行 |
| 热 Key 穿透 | 活动流量集中于单 Key | 本地缓存 + Key 分片 + Tair 热分析 |
| 连接超时 | 客户端版本不兼容 | 升级到官方推荐的客户端版本 |
| 数据总量对不上 | 双写期间有丢失或重放 | 打开双写日志,按 rowkey 重放增量 |
| 内存打满报错 | maxmemory-policy 没对齐 | 统一配置为 allkeys-lru |
6. 写在迁移之后的一点个人体会
整个项目从评估到全量切流,我们花了大概两个月时间,真正踩过的坑不算多,核心原因是前期的评估和设计做得足够细。以前总觉得自建开源组件“省钱”,但算上人力和稳定性成本,对于中小团队来说其实非常昂贵。Lindorm + Tair 这套组合,解决的不只是成本问题,还顺带把稳定性和运维效率提上来了。
如果你们团队也在考虑同样的事,我给三个最实在的建议:第一,先算清楚自己的 TCO,不要凭感觉判断“云上一定更贵”或者“云上一定更省”,把硬件、人力、扩容、故障损失全部摊进去再对比;第二,迁移过程中,双写 + 灰度切流是底线,任何“一次性切换”的方案都值得怀疑;第三,冷热分离的参数不要一步到位,预留两周的观察和调优期,按真实访问数据慢慢调。
成本降下来之后,省出的预算我们一部分投入到了监控告警和数据质量体系上,也算补上了过去几年一直想补的短板。这套方案后续还可以按照业务增长继续优化存储分层策略,甚至把更多的业务场景逐步并入云原生数据库体系,发挥托管能力的复用价值。