3141 字
约 10 分钟
15
S12-A10 · 数据分层与冷热分离:什么时候该动

一张订单表五年没清,99% 的查询只看近三个月,每次分页却要扫全表。直觉是挪走老数据,真问题不是能不能分,而是分了之后谁受影响:报表、对账、客服、审计、合规导出,全在剩下那 1% 里。

冷热分离是边界变更,不是清理:先列受影响名单,再算迁移、路由与一致性的账。


1. 先列受影响方,再谈技术方案

受影响方 关心什么 分层后的变化
在线接口 P99、可用性 热路径变快,跨层变慢
报表与对账 完整性、可重跑 跨层聚合或改跑汇总
客服与后台 能查任意一单 老单跨层或降为摘要
审计与导出 可追溯、可导出 冷层仍需可查可导
运维 备份、监控、容量 运维面翻倍,故障域增加

列不出五个真实使用方,就说明还没准备好——没人说得清老数据谁在用。

判据:答不上"最老那批数据最近被谁读过"之前,不要动;答不上来,边界就是猜的。


2. 冷热判定:四条依据,两两冲突

依据 判定方式 与谁冲突
访问频率 按分区统计读次数 时效:低频但须秒回
访问模式 点查还是范围扫描 频率:低频全扫更贵
时效要求 业务允许多久查到 合规:长期可查
合规要求 保留期、可导出 成本:不能删不能降级

优先级是合规 > 时效 > 访问模式 > 访问频率:违法是法律成本,查不到是业务成本,扫得慢是性能成本。

第二条最常被忽略:每天扫一次的全表聚合,成本可能高于十万次点查。

SELECT table_name, rows_read, rows_returned,
       rows_read / NULLIF(rows_returned, 0) AS read_amplification
FROM   performance_schema.table_io_waits_summary_by_table
ORDER  BY rows_read DESC;

放大倍数高说明在扫大量冷行,收益大;接近 1 说明是精准点查。


3. 四种实现与各自的迁移成本

实现 做法 迁移成本 主要风险
同库分表 冷热同实例,按时间后缀 低,改 SQL 与路由 表数膨胀,备份变重
分库 冷数据搬到独立实例 中,需同步与回滚 跨库查询与事务
分引擎 热走 OLTP,冷走列存 高,双写与类型映射 两套语义不一致
分介质 热在库,冷在对象存储 中高,需取回路径 取回延迟、格式演进

判据不是"哪层更省",而是查询模式能否拆成两套互不干扰的路径:点查与范围扫描能拆,实时聚合拆不动。

最易低估的是 DDL 与备份:按月分表后 1 张变 61 张,每次变更跑 61 次;在线 DDL 行为按版本核对。


4. 物理分离与逻辑分离

形式 消费者感知 代价
视图 无感,仍查同一视图 UNION 拖慢所有查询
分区表 基本无感,需分区键 键选错即退化为全扫
路由层 需改调用方或 SDK 复杂度上移,测试面变大
独立冷入口 感知"这是历史查询" 需独立 UI 与权限

逻辑分离最省事,但复杂度留在数据库里:不带分区键就全扫,UNION ALL 让计划变差。路由层适合"必须挪走",代价是逻辑显式化:

route(query):
  if time_range ⊆ hot_window:            return hot_store
  if time_range ⊆ cold_window:           return cold_store
  if has_aggregation or has_order_by:    return merge_engine     # 最贵
  if is_paginated and crosses_boundary:  return cursor_required
  else:                                   return error(needs_time_range)

最后一行最有价值:强制调用方给时间范围,成本是一次接口改造,收益是路由复杂度下降。


5. 查询路由变难的四件事

能力 单表时 分层后
跨层查询 一条 SQL 两次查询 + 应用侧合并
聚合 GROUP BY 直出 预聚合或分片再合并
排序 ORDER BY 走索引 归并排序或限单层
分页 LIMIT/OFFSET 需游标,深分页不可行

成本不是线性的:只要一个接口不能降级,整套方案就得保留跨层能力,而它一旦成为默认路径,最终等于没分层还多一套存储。

所以要把接口显式分级,只有白名单保留合并逻辑:

query_policy:
  tier_required:      # 必须跨层,白名单,每季度复核
    - report.monthly_settlement
    - audit.export
  tier_optional:      # 允许跨层,但必须带时间范围
    - order.detail
  hot_only:           # 超窗口直接拒绝,返回明确错误
    - order.list

6. 写路径的分裂:历史还能不能改

策略 做法 适用 代价
冷层只读 归档后禁更新 流水、日志、已结算 更正走审批补偿
冷层可写 保留写路径与路由 需事后更正 双写一致性、延迟
可写但延迟 队列异步落冷层 可容忍分钟级 读自己刚写的会失败

只读最省事,也最易被拒:一旦有客服改单、财务冲正,只读就变成"把数据搬回来改"。

判据:统计近一年对老数据的写操作次数。一年个位数只读即可;每周都有则冷层必须可写,降成本收益会被双写成本吃掉大半。


7. 一致性与延迟的账

异步归档必然有窗口:数据已"过期"但未搬走。窗口内的行为要写死。

A 双读兜底:先热后冷,miss 再查冷   → 延迟增加,一致性最好
B 只读热层:窗口内老数据不可见      → 简单,但会有"数据消失"投诉
C 双写过渡:同时写热与冷            → 一致,成本最高,仅迁移期

A 的代价是延迟与放大:每次 miss 多一次跨层调用,冷层更慢。B 的代价是体感故障——分页到第 3 页突然空了,用户以为数据丢了。

还有一处常被忽略:边界的时钟。按月分表时"上个月"由谁定义?三处时区不一致时,某一天的数据会两边都没有。


8. 迁移的执行顺序

1 影子读:新路径只读,与旧路径按天抽样比对,记录差异率
2 双写:写旧路径同时写新路径,差异告警接值班
3 回填:按时间分片、限速、可中断续跑,记录分片位点
4 校验:行数、金额汇总、抽样明细三方比对
5 切读:按接口灰度,从 tier_optional 开始
6 停双写:确认无差异后关闭旧写路径,保留回滚窗口

两处顺序不能颠倒:影子读在双写之前,停双写在切读之后(否则没有回滚数据)。

判据:每步都能单独回退;回填必须幂等可续跑——中断后从头再跑是常见事故。


9. 回退:分层做错了怎么回去

回退层级 手段 代价
查询回退 路由切回单层(需全量副本) 存储成本不降
数据回退 冷层反向回填热层 小时级,占磁盘与 IO
逻辑回退 关路由层,恢复单表查询 表结构需兼容
不可回退 冷层已降为摘要、明细已删 只能靠备份,天级

回退能力取决于是否保留完整原始数据。把冷层做成"摘要保留",回退就不可逆,这个决定要写进方案。

判据:回退时间超过一次故障容忍窗口,等于没有回退。


10. 成本账:省下的存储与新增的复杂度

项 方向 说明
存储与备份 下降 冷介质单价低,但副本数不变
热路径延迟 下降 热表变小,缓存命中变好
开发成本 上升 路由、合并、双写、回填
故障成本 上升 多一套存储,多"查不到"故障
运维成本 上升 备份、监控、容量、权限各一套

账常被写成"存储省了 X",但对照项是开发与故障成本——不在账单上,只在排期与事故里。

判据:存储节省小于新增一套存储的年运维成本、且动机不是性能时,不要做。


11. 合规压力可能直接否决分层

合规要求 对分层的影响
保留 N 年可查 冷层必须支持查询,不能只是文件
可完整导出 导出链路要走通跨层
不可篡改 冷层倾向对象存储 + 校验
删除覆盖所有副本 冷层与备份也要进删除链路

最后一条是最易忽略的副作用:分层增加了"位置",也扩大了删除必须覆盖的范围;确认删除链路能延伸过去再动手。


12. 度量分层是否成立

热数据占比   = 热层行数 / 总行数        (小而热,不是越小越好)
跨层查询比例 = 触发合并的请求 / 总请求    (> 5% 说明路由没起作用)
热层 P99     = 分层前后对比,按接口分桶
冷层取回延迟 = 冷查询 P95,按介质区分
校验差异率   = 影子读差异,应趋近 0

跨层比例居高不下,通常是没强制时间范围或白名单太长,该改调用约定而不是存储。


13. 排错:分层之后常见的六种故障

现象 根因 处理
老数据"消失" 窗口内只读热层 双读兜底或缩窗口
分页到后面空了 未用游标分页 改游标或限窗口
聚合结果对不上 合并漏层或重复计 统一口径,加对账
某天数据两边都没有 时区边界不一致 单一配置生成边界
回填反复重跑 非幂等、无位点 记位点,幂等写入
分层后更慢了 跨层查询成默认 收紧白名单

14. 边界:什么时候不要分层

场景 判断 替代做法
单表千万级以下 索引与分区够用 优化索引、做归档表
查询模式尚未稳定 边界会频繁改 先观察 3 个月分布
无运维两套存储能力 故障域翻倍 同库分表,先不动存储
数据几乎全被查询 冷热无区分 不拆,改查询方式
合规要求全量低延迟 冷层无法降级 只做索引与缓存优化

第二类最易被跳过:产品还在改、边界三个月一变,按今天分布切,半年后要重切。分层收益来自稳定的边界。


15. 自测

  1. 分层方案的第一份产出应该是什么,为什么不是技术方案?
  2. 四条判定依据冲突时,为什么合规排最前?
  3. rows_read / rows_returned 很高说明什么?
  4. 分区表最容易被误用的地方在哪?
  5. 冷数据设为只读之前,要先统计什么?
  6. 跨层查询比例长期 20%,该改存储还是改调用约定?
S12-A10 · 数据分层与冷热分离:什么时候该动
https://www.clxhxhhr.top/posts/6250/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。