前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

来自字节: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(已归档)
创建时间 用于监控和排查 查看某条记录何时开始归档
修改时间 用于兜底任务 判断是否超时未完成

image-20251110141843276

3)归档流转

image-20251110142714338

3、基本原则

维度 原则 目的
写入 热库是唯一写入口,冷库只接收同步 保证数据权威性和一致性
更新 冷库无 update,更新必须回流热库 避免逻辑分散,简化事务模型
删除 删除热库前必须验证冷库存在 防止误删未归档数据
查询 尽量不查冷库,查也要有策略 保护冷库性能,保障线上 SLA
配置 归档天数 m > 查询天数 n 防止数据“真空期”,增强系统鲁棒性

1)数据插入唯一性:

核心目标:防止冷热库出现主键/唯一键冲突或数据错乱

注意:通过严格的写入顺序和条件校验,保证冷热数据在逻辑上是同一份数据的不同副本,而非两套独立数据。

a、归档表唯一健要一致

热库归档表的所有唯一键必须跟要归档的热库表保持一致。

  • 意味着归档表不是“随便建”的,它的约束(如订单号唯一)必须和热库完全一致。
  • 否则可能出现:热库认为某订单不存在,但归档表里却有重复,导致后续同步或查询出错。

b、冷热数据要一致

热库归档记录已存在的订单,冷库必须有相应数据,

  • 归档的本质是“迁移”,不是“删除”。所以只要热库某条记录被归档了,冷库就必须有它。

2)数据更新一致性:

核心目标:确保数据更新的权威性和单写入口

注意:热库是唯一写入口,冷库是只读副本。任何变更必须走热库,确保业务逻辑集中、可审计、可追溯。

热库是唯一写入口,冷库是只读副本。任何变更必须走热库,确保业务逻辑集中、可审计、可追溯。

a、冷库不允许直接 update

  • 冷库只接受来自热库的“全量快照式写入”(insertdelete+insert),不支持局部字段更新。
  • 原因:冷库通常是只读或低频写入的 OLAP 系统(如 HBaseTiDB 冷层、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、插入

image-20251110143347178

b、更新

image-20251110143401450

c、查询

image-20251110143423638

2)方案2:有归档表

特点: 唯一键有外部单号,订单规则随机无法根据单号判断时间,因此必须有归档表。

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

a、插入

image-20251110143113079

b、更新

image-20251110143054317

c、查询

image-20251110142619436

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  
美团      

ContactAuthor