项目经验_之_冷热数据分离
前言
Github:https://github.com/HealerJean
来自字节:https://mp.weixin.qq.com/s/ZKRkZP6rLHuTE1wvnqmAPQ
一、为什么要冷热分离
1、背景与目标
1)业务快速增长带来的挑战
- 订单量持续增长。
- 历史订单访问频率低,但占用大量在线 MySQL(InnoDB)存储空间。
- 在线数据库扩容成本高,且扩容过程可能导致服务不可用(停服)。
2)核心痛点
- 存储成本高:历史数据长期存放在高性能热库中,浪费资源。
- 扩展性差:
MySQL单表数据量过大影响查询性能和维护效率。 - 风险集中:所有数据集中在一套数据库,一旦故障影响面大。
- 热库挂了 → 历史数据仍可查(不影响客服、对账等后台功能);
- 冷库挂了 → 不影响用户下单、支付等核心链路(因为实时交易不依赖冷库)。
3)目标
- 降低热库存储压力:只保留最近
X天的“热数据”。 - 历史数据归档到冷库:使用低成本、高压缩比的
RocksDB存储。 - 保证业务无感:查询、插入、更新等操作对上层透明,不影响现有逻辑。
- 零事故、零资损:确保数据一致性、幂等性和事务安全。
2、技术选型与架构
1)组件
| 组件 | 作用 |
|---|---|
| 热库(MySQL InnoDB) | 存储最近 X 天高频访问数据,支撑实时交易 |
| 冷库(RocksDB) | 存储 X 天前的历史数据,支持压缩、低成本 |
| 归档表(MySQL) | 仅用于交易表,记录已归档数据状态,辅助查询过滤 |
| MQ + 延迟队列 | 控制热库数据删除时机,避免立即删除导致查询失败 |
| 兜底任务 | 补偿机制,处理 MQ 消息丢失或任务失败场景 |
2)归档结构
| 字段 | 作用 | 示例 |
|---|---|---|
| 唯一键 | 匹配热库交易表的所有唯一键 | 如 (id, mch_order_no),防止误删 |
| 归档状态 | 控制生命周期 | HOT(未归档)、PROCESSING(正在归档)、COLD(已归档) |
| 创建时间 | 用于监控和排查 | 查看某条记录何时开始归档 |
| 修改时间 | 用于兜底任务 | 判断是否超时未完成 |

3)归档流转

3、基本原则
| 维度 | 原则 | 目的 |
|---|---|---|
| 写入 | 热库是唯一写入口,冷库只接收同步 | 保证数据权威性和一致性 |
| 更新 | 冷库无 update,更新必须回流热库 |
避免逻辑分散,简化事务模型 |
| 删除 | 删除热库前必须验证冷库存在 | 防止误删未归档数据 |
| 查询 | 尽量不查冷库,查也要有策略 | 保护冷库性能,保障线上 SLA |
| 配置 | 归档天数 m > 查询天数 n |
防止数据“真空期”,增强系统鲁棒性 |
1)数据插入唯一性:
核心目标:防止冷热库出现主键/唯一键冲突或数据错乱
注意:通过严格的写入顺序和条件校验,保证冷热数据在逻辑上是同一份数据的不同副本,而非两套独立数据。
a、归档表唯一健要一致
热库归档表的所有唯一键必须跟要归档的热库表保持一致。
- 意味着归档表不是“随便建”的,它的约束(如订单号唯一)必须和热库完全一致。
- 否则可能出现:热库认为某订单不存在,但归档表里却有重复,导致后续同步或查询出错。
b、冷热数据要一致
热库归档记录已存在的订单,冷库必须有相应数据,
- 归档的本质是“迁移”,不是“删除”。所以只要热库某条记录被归档了,冷库就必须有它。
2)数据更新一致性:
核心目标:确保数据更新的权威性和单写入口
注意:热库是唯一写入口,冷库是只读副本。任何变更必须走热库,确保业务逻辑集中、可审计、可追溯。
热库是唯一写入口,冷库是只读副本。任何变更必须走热库,确保业务逻辑集中、可审计、可追溯。
a、冷库不允许直接 update
- 冷库只接受来自热库的“全量快照式写入”(
insert或delete+insert),不支持局部字段更新。 - 原因:冷库通常是只读或低频写入的
OLAP系统(如HBase、TiDB冷层、S3 + 查询引擎),不适合高频事务更新。
b、如果要更新的数据只在冷库?必须先同步回热库!
- 例如:用户要修改一个 90 天前的订单(已在冷库)
- 系统需先将该订单“回流”到热库(作为临时活跃数据),
- 在热库完成更新,之后可能再次归档。
- 这保证了 所有业务逻辑变更都发生在热库,冷库只是历史快照。
c、同步操作必须在同一事务内完成
- 比如把冷库数据同步回热库时,要同时更新热库的交易表 + 删除/标记归档表。
- 使用“写库”(主库)查询,避免读从库导致的延迟不一致。
d、热库是“权威源”
- 当冷热库都有同一条数据时,以热库为准。冷库数据只能由热库同步而来,不能反向污染。
- 防止“冷库被人工修正后,覆盖热库正确数据”的风险。
3)数据查询准确性
核心目标:在保证正确性的前提下,尽量减少对冷库的依赖,提升性能
a、单笔查询:热库查不到就结束,不再查冷库
- 除非能从订单号解析出日期(如
ORDER_20241201_XXXX),且该日期明显属于历史数据,才去查冷库。 - 避免每次查不到都扫冷库,造成冷库压力过大。
b、批量查询:优先返回热库数据
- 如果同一条记录在冷热库都存在(比如刚归档还没清理热库),以热库为准。
- 合并结果后,如果原始接口要求按时间/
ID排序,合并后仍需重新排序,避免顺序错乱影响业务(如分页)。
c、减少冷库压力
- 冷库通常部署在低成本存储(如 HDD、对象存储),查询延迟高、吞吐低。
- 所以线上交易链路应尽量屏蔽冷库访问,可通过:
- 订单号含日期 → 直接判断是否需查冷库
- 维护“归档标记表” → 快速判断某订单是否已归档
d、天数控制分离:m > n
- 举例:
- 应用层(
mode层):只查最近 n=30 天 的订单,超过才查冷库 - 归档任务:只归档 m=60 天前 的数据
- 应用层(
- 这样即使归档策略调整(比如 m 从
60改成 45),只要 m > n,就不会出现“应用想查冷库,但数据还没归档”的空窗期。
4、方案对比
- 想彻底减压 → 选方案一(但要扛住冷库压力)
- 想安全过渡 → 选方案二(牺牲一点空间换稳定性)
- 想精细控制 → 选方案三(但代价是复杂度飙升)
| 方案 | 特点 | 适用场景 |
|---|---|---|
| 方案一 | 直接查冷库,无需归档表 | 查询条件能通过单号判断时间(如支付单号含日期) |
| 方案二 | 引入“热库归档表”中转 | 无法通过单号判断时间,需减少冷库查询(如交易单号无规则) |
| 方案三 | 按业务场景归档 | 场景简单、历史数据不再变更 |
| 业务类型 | 推荐方案 |
|---|---|
| 支付、充值等内部单号有序 | 方案一(直接冷热分离) |
| 交易、订单等外部单号随机 | 方案二(带归档表) |
| 日志、报表、审计等静态数据 | 方案三(按场景归档) |
1)方案1:直接冷热分离(无归档表)
唯一键都为内部单号,现有主要查询可以根据单号判断时间,不需要归档表,可以彻底解决热库数据库存储问题。
- 适用场景:能通过单号判断时间(如内部生成的有序 ID)
- 代表业务:支付表
- 优点:
- 侵入业务少→ 不需要修改现有代码逻辑,仅在数据库交互层做路由。
- 能彻底解决热库存储压力问题→ 所有历史数据全部迁移到冷库,热库只保留近期数据。
- 彻底释放热库空间,无需额外表
- 缺点:
- 对单号规则有强依赖:只有当所有操作都能通过单号或参数准确判断数据时间范围时,才能避免冷库穿透。
- 一旦存在无法判断时间的查询(如外部随机单号),将导致高频访问冷库,使其成为性能瓶颈。
a、插入

b、更新

c、查询

2)方案2:有归档表
特点: 唯一键有外部单号,订单规则随机无法根据单号判断时间,因此必须有归档表。
- 适用场景:无法通过单号判断时间(如商户订单号随机)
- 代表业务:交易表
- 优点:
- 侵入业务少→ 只增加一张归档表,不影响主业务逻辑
- 能够延缓数据库存储压力→ 虽不能彻底解决,但显著缓解热库压力
- 降低对冷库的实时查询压力→ 查询时优先走热库,通过归档表判断是否已归档
- 冷库性能要求不高→ 冷库主要用于存历史快照,无需高性能读写。
- 缺点:
- 新增热库归档表→ 占用热库空间,虽小但长期累积也不容忽视
- 因新增的归档表记录全量数据,没有彻底解决热库存储压力问题→ 归档表本身也是 MySQL 表,仍占用磁盘空间。
- 插入、更新、查询时依赖查询热库归档,热库压力增加→ 每次操作都要查归档表,增加了热库的 I/O 压力
a、插入

b、更新

c、查询

3)方案3:按业务场景归档(简单场景)
-
适用场景:历史数据永不变更(如日志类)
-
优点
-
资损风险小→ 只对“不会变更”的静态数据归档,避免误删或更新冲突。
-
能够延缓数据库存储压力→ 选择性归档,减轻热库负担。
-
冷库性能要求不高→ 主要是查询型操作,不需要高并发写入。
-
-
缺点
-
对业务侵入多,各种订单关联关系要分开发→ 需要根据每个业务场景单独设计归档规则,复杂度高。
-
后续归档维护成本高,需要一直维护新场景和场景变更是否需要归档→ 新增功能时需评估是否归档,运维成本上升。
-
二、冷热分离调研
基于时间维度将高频访问的“热数据”与低频访问的“冷数据”物理隔离
| 维度 | 说明 |
|---|---|
| 热数据定义 | 通常为最近 30~90 天 的订单 |
| 冷数据定义 | 超过热数据窗口的历史订单,访问频率极低(<1% 查询量) |
| 分离目标 | - 提升 OLTP 性能 - 降低主库存储压力 - 降低存储成本 - 保证历史数据可查 |
| 核心策略 | 归档优先于分库分表(冷数据迁移成本远低于热数据拆分) |
1、公司调研
| 公司 | 文章 | 地址 | |
|---|---|---|---|
| 阿里 | 淘宝万亿级海量交易订单存储在哪? | https://zhuanlan.zhihu.com/p/138760212 | |
| 阿里 | 淘宝应对”双11”的技术架构分析 | https://developer.aliyun.com/article/278072 | |
| 京东 | 京东广告基于 Apache Doris 的冷热数据分层实践 | https://juejin.cn/post/7473378562293612582 | |
| 美团 |


