3. 历史数据存储策略:分区策略设计、数据保留周期、冷热数据分层
风控历史数据,说白了就是越存越值钱,但也越存越头疼。我见过不少团队,一开始图省事,把所有数据塞进一张大表,结果半年后查询慢得像蜗牛,存储成本还蹭蹭往上涨。今天咱们就聊聊怎么把这事儿理顺。
3.1 分区策略设计:别让查询扫全表
分区是 Lakehouse 里最基础的优化手段。没有分区,每次查询都得全表扫描,数据量一上来,谁也扛不住。
分区字段怎么选? 我个人习惯,优先看查询条件。风控场景里,绝大多数查询都带时间范围——比如“查某笔交易当天的所有记录”或者“统计上个月的风险事件”。所以,时间字段是第一选择。
核心原则: 分区字段必须是查询中最常用的过滤条件,且基数适中。基数太大(比如毫秒级时间戳)会导致分区数爆炸;基数太小(比如只有“是/否”)又起不到剪枝效果。
举个例子,交易流水表按天分区:
-- 创建分区表(以 Apache Iceberg 为例)
CREATE TABLE risk.transaction_events (
event_id STRING,
user_id STRING,
amount DECIMAL(18,2),
risk_score DOUBLE,
event_ts TIMESTAMP
)
USING iceberg
PARTITIONED BY (days(event_ts)); -- 按天分区
这样查询 WHERE event_ts BETWEEN '2024-01-01' AND '2024-01-07' 时,引擎只会扫描 7 个分区,而不是全表。我在项目中遇到过,一个没分区的表跑一次月报要 40 分钟,加上按天分区后,直接降到 3 分钟。
多级分区呢? 有时候单靠时间还不够。比如数据来自多个业务线,查询也经常按业务线过滤。这时候可以加二级分区:
PARTITIONED BY (days(event_ts), biz_line)
但要注意,分区层级别太多。我见过有人搞了四层分区,结果小文件多到元数据服务都扛不住。一般来说,两层就够用了。
小技巧: 如果查询条件里经常出现“用户ID”这种高基数字段,别用它做分区字段——分区数会爆炸。改用 Z-order 排序 或 Bucket 分桶 更合适。
3.2 数据保留周期:存多久是个学问
风控数据不能随便删,但也不能无限存。存储成本、合规要求、查询性能,这三者得平衡。
不同数据,不同生命周期。 我一般把风控数据分成三类:
| 数据类别 | 保留周期 | 典型数据 |
|---|---|---|
| 热数据 | 近 30 天 | 实时交易、风控决策日志 |
| 温数据 | 30 天 ~ 1 年 | 月度报表、模型训练样本 |
| 冷数据 | 1 年 ~ 7 年 | 监管审计、历史回溯 |
这个周期不是拍脑袋定的。你得看业务需求和合规要求。比如金融行业,监管通常要求交易记录保留 5 年以上。我曾经帮一家支付公司做方案,他们一开始按 3 年设计,结果合规审计没过,又回头补数据——那叫一个折腾。
自动清理怎么做? Lakehouse 里可以用 Time Travel 和 Retention Policy 来管理。以 Delta Lake 为例:
-- 设置数据保留 90 天
ALTER TABLE risk.transaction_events
SET TBLPROPERTIES (
'delta.logRetentionDuration' = '90 days',
'delta.deletedFileRetentionDuration' = '90 days'
);
-- 手动清理过期快照
VACUUM risk.transaction_events RETAIN 90 HOURS;
注意: VACUUM 操作不可逆。执行前一定要确认保留周期设置正确。我曾经手滑少写了一个 0,把本该保留 90 天的数据清到了 9 天,还好有备份才没出大事。
3.3 冷热数据分层:把成本降下来
数据分层,说白了就是把访问频率高的数据放快盘,访问频率低的数据放慢盘。这样既保证查询性能,又控制存储成本。
我常用的分层策略是这样的:
- 热层: SSD 或高性能对象存储,存放最近 30 天的数据。查询延迟要求毫秒级。
- 温层: 标准对象存储,存放 30 天到 1 年的数据。查询延迟秒级可接受。
- 冷层: 归档存储或廉价对象存储,存放 1 年以上的数据。查询延迟分钟级甚至小时级。
在 Lakehouse 里,分层通常通过 表分区 + 存储策略 实现。比如用 Apache Iceberg 的 分区演进 功能,把旧分区自动迁移到冷存储:
-- 设置冷数据存储路径
ALTER TABLE risk.transaction_events
SET TBLPROPERTIES (
'write.data.path' = 's3://hot-bucket/risk/',
'write.folder-storage.path' = 's3://cold-bucket/risk/'
);
嗯,这里要注意,不同引擎的冷热分层实现不太一样。Delta Lake 用 分区级别的表属性,Iceberg 用 存储桶策略,Hudi 用 Clustering。选哪个取决于你的技术栈。
我的建议: 别一上来就搞太复杂的分层。先按时间分区,把热数据放高性能存储,等数据量大了再逐步迁移冷数据。我见过一个团队,一开始就设计了 5 层存储,结果运维成本比存储成本还高。
3.4 整体策略:一张图看懂
说了这么多,咱们用一张图把整个策略串起来。你想想看,从数据写入到最终归档,整个流程应该是这样的:
这张图把咱们刚才聊的三件事串起来了:数据进来先分区,然后按冷热分层存储,最后根据保留周期自动清理。每一步都环环相扣。
3.5 避坑指南
最后,分享几个我踩过的坑:
- 分区字段别选错。 我曾经用
user_id做分区字段,结果分区数比数据行数还多,查询反而更慢。后来改成按天分区 + Z-order 排序,才解决问题。 - 保留周期别设太短。 有个项目为了省存储,把保留周期设成 30 天。结果模型训练需要 60 天的历史数据,又得从备份恢复,折腾了两天。
- 冷热分层别搞太复杂。 分层越多,运维越累。我建议最多三层,再多就是过度设计了。
- 别忘了监控。 分区大小、存储用量、查询延迟,这些指标得盯着。我见过一个案例,冷数据迁移脚本跑挂了三个月没人发现,存储成本翻了一倍。
一句话总结: 分区策略决定查询性能,保留周期决定合规成本,冷热分层决定存储成本。这三件事做好了,你的 Lakehouse 才能又稳又省。