微服务架构落地:大表治理与冷热分离 —— 历史单据到底怎么存?

本文聚焦微服务架构中历史单据导致的数据库性能瓶颈,系统阐述冷热数据划分标准(时间+状态维度)、三级分级存储方案(热库MySQL分库分表、温库归档MySQL、冷库OSS/ClickHouse/ES),并详解平滑归档任务调度与应用层路由拦截机制,同时指出主从延迟、冷查询超时、跨库统计等关键落地风险及规避规范。

大宗商品销采运储系统・六层架构连载(数据持久层)

上一篇我们通过分布式事务,解决了跨库单据流转的数据一致性问题。

到这里,分库分表做了,读写分离有了,事务也稳了,系统是不是就高枕无忧了?

并没有。还有一头“房间里的大象”在悄悄压垮你的数据库:历史数据。

大宗商品系统运行三年后,单表数据量可能逼近几千万甚至上亿行。其中 80% 是历史单据(已完结的运单、三年前的出库单)。这些数据业务员平时根本不查,但它们在物理上死死占着磁盘空间,甚至污染了 MySQL 的 Buffer Pool(内存缓存)。

如果不做冷热分离,你分再多的表,也会被这些“死数据”拖死。

一句话定调:

冷热分离不是为了省磁盘,而是为了给数据库做“减负手术”。让热数据跑得更快,让冷数据查得到但不碍事。


一、痛点:历史单据,是如何拖垮系统的?

1. 缓存污染(最致命)

InnoDB 的内存是有限的。当业务员查询一张新单据时,MySQL 需要把数据页从磁盘读入内存。如果历史大表占据了大量空间,甚至导致内存频繁换入换出(Swap),热数据的查询延迟会从 10ms 飙升到 500ms。

2. 索引树变深

几千万行甚至上亿行的数据,B+ 树的层级会变深(通常从 3 层变成 4 层),每次查询都要多一次磁盘 IO。

3. 备份与 DDL 灾难

一个几百 GB 的数据库,做一次全量备份要几个小时,恢复起来更是噩梦。如果要给单据表加个字段,直接 ALTER TABLE 动辄锁表几十分钟,业务全线瘫痪。

4. 合规与审计的红线

根据《会计档案管理办法》等合规要求,大宗商品的交易单据、财务凭证往往需要保留 10 年甚至 30 年。
你不能直接 DELETE,只能分离。

图片


二、冷热数据怎么划分?(大宗商品业务标准)

不能拍脑袋决定什么是冷、什么是热,必须结合业务状态和时间维度。

1. 按时间维度(最常用)

  • 热数据:近 3 个月的单据。业务员高频查询、修改、流转。

  • 温数据:3 个月 ~ 1 年的单据。偶尔查询对账。

  • 冷数据:1 年以上的单据。基本只有财务审计、历史凭证核查时才会看。

2. 按状态维度(更精准)

  • 热数据:状态 = 流转中 / 待审核 / 待出库。只要没走完流程,不管放多久,都是热数据。

  • 冷数据:状态 = 已完结 / 已作废 / 已红冲,且 完结时间 > 3个月。

判定公式:

冷数据 = (状态 IN ('FINISHED', 'CANCELLED')) AND (完结时间 < NOW() - 3个月)


三、架构演进:冷热数据分级存储方案

业界标准的冷热分离架构,通常分为三层:

应用服务层  → 路由层(ShardingSphere / 业务代码拦截)      → 【热库】MySQL 主集群(分库分表,高配SSD):近3个月数据      → 【温库】MySQL 从库 / 归档库(低配HDD):3个月~1年数据      → 【冷库】对象存储(OSS/S3)或 ClickHouse / ES:1年以上数据

1. 热库:MySQL 分库分表

只保留最近 3 个月的数据。单表数据量保持在 500 万行以内,保证极速响应。

2. 温库:独立的归档 MySQL 实例

将 3 个月到 1 年的数据迁移至此。使用普通的 HDD 磁盘即可。查询频率低,可以接受一定的延迟。

3. 冷库:大数据的归宿

  • 如果仅仅是合规要求(存起来不查):直接导出为 CSV / Parquet 文件,存入阿里云 OSS / 腾讯云 COS / 私有云MINIO,成本极低。

  • 如果偶尔需要检索(如查三年前的订单):将历史数据同步到 Elasticsearch 或 ClickHouse,提供只读查询接口。

图片


四、落地实战:历史数据平滑归档方案

绝不能写个 DELETE 脚本直接删,那样会导致主从延迟、锁表,甚至误删。

图片

步骤 1:数据归档任务(基于调度服务)

利用我们连载过的“基础服务层 - 调度服务”,每天凌晨低峰期触发归档任务。

核心逻辑:先复制、后删除。

@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
public void archiveColdData() {
    // 1. 确定要归档的截止时间(3个月前)
    LocalDateTime threshold = LocalDateTime.now().minusMonths(3);

    // 2. 分批查询符合条件的冷数据(每次查 1000 条,防止 OOM)
    while (true) {
        List<Order> coldOrders = orderMapper.selectColdData(threshold, 1000);
        if (coldOrders.isEmpty()) break;

        // 3. 批量写入冷库(归档表 / ClickHouse / 导出文件)
        archiveMapper.batchInsert(coldOrders);

        // 4. 记录日志,确认落盘成功
        log.info("成功归档 {} 条数据", coldOrders.size());

        // 5. 物理删除热库数据(按主键删除,防止锁全表)
        List<Long> ids = coldOrders.stream().map(Order::getId).collect(Collectors.toList());
        orderMapper.batchDeleteByIds(ids);

        // 6. 稍微休眠,避免把主库 IO 打满
        Thread.sleep(100);
    }
}

⚠️ 严禁写 DELETE FROM t_order WHERE create_time < '2023-01-01',这会造成巨大的长事务,主从延迟瞬间飙升,甚至拖垮整个数据库。

步骤 2:应用层冷热路由拦截

数据归档后,当业务员查询一个单号时,系统怎么知道去热库查,还是去冷库查?

方案 A:代码层判断(推荐)
先查热库,查不到再查冷库。

public OrderDTO getOrderByNo(String orderNo) {
    // 1. 查热库(基因法路由)
    OrderDTO order = orderMapper.selectByOrderNo(orderNo);
    if (order != null) return order;

    // 2. 热库没有,查冷库
    return archiveMapper.selectByOrderNo(orderNo);
}

方案 B:基于时间的路由拦截器
在 ShardingSphere 中配置,如果查询条件包含 create_time,且小于 3 个月,强制路由到归档数据源。


五、冷热分离的踩坑与红线

坑点 1:主从延迟急剧升高

如果归档任务执行得很快,MySQL 产生大量 binlog,从库回放跟不上,导致线上读请求读到了“正在被删除的数据”,引发幻觉。
规范:归档任务必须分批(Batch),并在每批之间 sleep 几十毫秒,限制 TPS。

坑点 2:冷数据查询超时

如果冷库是 ClickHouse 或 OSS,查询延迟必然比 MySQL 高。
规范:冷数据的查询接口,必须加超时控制(如 3 秒),且前端展示要增加 Loading 提示。同时,冷库查询要加 Sentinel 限流。

坑点 3:跨库查询与统计

一旦部分数据进了冷库,原来 SELECT COUNT(*) FROM t_order 就不准了。
规范:统计报表必须走数仓(离线 T+1)。绝对禁止在业务库里做跨热冷库的实时聚合。


六、本篇小结

数据是有生命周期的。让热数据留在最贵、最快的介质上,让冷数据流向廉价、大容量的存储中,是数据库架构设计的必然选择。

记住三句话:

  1. 冷热划分看状态和时间,已完结的尽早挪走。

  2. 归档要分批软删除,严禁长事务大 Delete。

  3. 热库查不到去冷库查,统计报表走数仓。

下篇预告:数据量的问题解决了,但如果你的 SQL 写得烂(比如没走索引、用了 SELECT *),再好的架构也救不了你。下一篇,我们讲述:慢 SQL 治理与数据库性能压舱石。拆解如何通过监控、Explain 分析、索引优化、连接池调优,守住数据库的最后一道防线

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值