当前位置: 首页 > news >正文

【大数据高并发核心场景实战】 - 数据持久化之冷热分离

大数据高并发核心场景实战 - 数据持久化之冷热分离

当云计算平台的业务后台处理工单突然接入客服系统的请求洪流,每日新增10万工单,3000万主表+1.5亿明细表的数据库开始呻吟——是时候请出「冷热分离」这剂退烧药了!


一、业务场景:工单表的生死时速

日均10万工单增长
主表3000万+
明细表1.5亿+
查询响应>2s
业务人员投诉暴增

核心痛点

  • 热数据(最近3个月工单)仅占总量20%,却承担80%读写
  • 历史工单(冷数据)像仓库积压货,拖慢整个系统效率

二、踩坑记:数据库分区的幻灭

曾天真地以为分区是银弹:

-- 按时间分区的美好设想
ALTER TABLE tickets PARTITION BY RANGE(YEAR(create_time)) (PARTITION p2023 VALUES LESS THAN (2024),PARTITION p2024 VALUES LESS THAN (2025)
);

现实暴击

  1. 致命限制:分区字段必须是主键组成部分 → 需将create_time加入复合主键
  2. 查询失灵:业务接口缺少统一分区字段过滤条件
  3. 运维黑洞:跨分区查询性能反而雪崩

💡 结论:当查询无法命中分区键时,分区如同给破车装火箭引擎——徒增复杂度!


三、冷热分离:给数据库做“冰箱冷冻术”

3.1 冷热判定法则

已关闭
>30天
工单状态
冷数据候选
最后处理时间
冷数据盖章

判定标准status='CLOSED' AND last_process_time < NOW()-30d


3.2 分离触发三剑客

方式优点缺点适用场景
修改业务代码实时精准耦合高,改造成本大新系统
监听Binlog解耦,近实时无法按时间触发高实时性要求
定时扫描零侵入,天然按时间延迟分钟级存量系统改造

我们选择定时扫描:凌晨低峰期执行,避免影响客服白天作战


3.3 分离操作原子三连

定时任务 热数据库 冷数据库 1. 锁定待迁移数据 返回锁定ID列表 2. 插入冷库(幂等操作) 插入成功 3. 删除热库数据 定时任务 热数据库 冷数据库

四、高并发迁移的三大生死关

4.1 批量处理的艺术

线程池配置

ThreadPoolExecutor executor = new ThreadPoolExecutor(10, // 常驻10个迁移战士10,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(100) // 等待队列容量
);

迁移策略

  • 单线程批量迁移 → 测试最佳batch size(我们测得500条/批最快)
  • 总量>5000时 → 唤醒线程池并发作战

4.2 锁的攻防战

加锁SQL的精妙设计

UPDATE tickets 
SET lock_thread = #{threadId}, lock_time = NOW() 
WHERE status = 'CLOSED' AND last_process_time < #{coldTime}AND (lock_thread IS NULL OR lock_time < #{timeout})

锁机制三原则

  1. 原子锁:利用UPDATE行锁特性
  2. 双检一致性:操作前二次验证锁持有者
  3. 超时兜底:设置5分钟超时,防线程僵死

⚠️ 血泪教训:某次未设超时,迁移线程OOM后→ 10万工单被锁死1小时!

背后的计算机原理

获取行锁
等待行锁释放
MVCC多版本控制
防止幻读
事务1
数据行X
事务2
InnoDB引擎
避免脏读
间隙锁
范围查询安全

锁机制三原则的底层逻辑

  1. 原子锁

    • 利用InnoDB的排他锁(X锁)机制
    • UPDATE语句执行时自动获取行锁,阻塞其他写操作
    • 通过WHERE条件实现CAS(Compare And Set)操作
  2. 双检一致性

    // 伪代码展示双重检查
    List<Long> lockedIds = executeUpdateLockSql(); // 步骤1:加锁
    List<Ticket> tickets = query("SELECT * WHERE id IN (:ids) AND lock_thread=currentId"); // 步骤2:验证
    if(tickets.size() != lockedIds.size()) {// 存在锁竞争失败的数据rollbackUnlockedTickets(); 
    }
    
  3. 超时兜底

    • 基于lock_time字段实现lease机制(租约锁)
    • 超时时间 = 平均处理时间 × 3 + 缓冲时间(我们设置5分钟)
    • 后台线程每分钟扫描lock_time < NOW()-5min的僵尸锁

4.3 失败重试的生存法则

保证最终一致性的三板斧

  1. 幂等插入INSERT INTO cold_table ... ON DUPLICATE KEY UPDATE
  2. 删除校验:删除热数据前检查冷库存在记录
  3. 异常监听:捕获失败工单,人工干预兜底

📌 真理时刻:冷热分离后,热表查询速度从2.1s→0.2s,业务人员笑容增加50%!


五、冷热分离二期:冷库迁入HBase

当冷数据突破亿级时,MySQL冷库开始颤抖 → 启用HBase方案

HBase作战地图

时间倒序+工单ID
工单数据
RowKey设计
Region分区
RegionServer1
RegionServer2
MemStore写缓存
MemStore写缓存
HFile持久化

列族设计禁忌

# 反面教材(导致Region分裂灾难)
create 'tickets', {NAME => 'base_info', VERSIONS => 1},   // 基础信息{NAME => 'process_log', VERSIONS => 10} // 处理日志 → 巨大字段!

优化为

  • 基础信息存HBase
  • 处理日志转存Elasticsearch

六、什么情况下别用冷热分离?

当遇到以下场景时请紧急刹车:

mindmaproot((慎用场景))工单频繁修改 → 冷热反复横跳需要跨冷热数据关联查询 → 性能黑洞实时统计全量数据 → 冷热双查不如直接OLAP

在这里插入图片描述


七、总结:冷热分离的生存法则

  1. 判断准:用业务状态+时间双标识锁定冷数据
  2. 触发稳:存量系统首选定时扫描触发
  3. 迁移快:并发批量处理+智能锁机制
  4. 存得省:亿级冷数据交给HBase/OSS
  5. 查得快:热库轻装上阵,冷库按需访问

🚀 终极奥义:让热数据在MySQL战场冲锋,送冷数据去HBase养老院安度晚年!

http://www.lryc.cn/news/572844.html

相关文章:

  • Android Kotlin 用法对比Java使用小结
  • 云计算与5G:如何利用5G网络优化云平台的性能
  • 搜索二维矩阵II
  • 《Go语言圣经》接口类型、动态类型、动态值、类型断言
  • 在spring boot中使用Logback
  • Llama 4模型卡片及提示词模板
  • #17 修改开源模型以适配新任务
  • 在VTK中捕捉体绘制图像并实时图像处理
  • 饼图:数据可视化的“切蛋糕”艺术
  • MySQL慢SQL优化全攻略:从诊断到调优
  • 阻止事件的触发
  • 如何导出和迁移离线 Conda 环境
  • 微信小程序扫码添加音频播放报错{errCode:10001, errMsg:“errCode:602,err:error,not found param“}
  • LeetCode 275.H指数 II
  • 邮件合并----批量从excel表中导出数据到word中
  • MySQL之事务深度解析
  • VS2022 C#【自动化文件上传】AutoFileUpload 新需求 V13
  • LVS vs Nginx 负载均衡对比:全面解析
  • [C/C++11]_[初级]_[使用正则表达式分组来获取动态字符串]
  • tkinter 的 grid() 布局管理器学习指南
  • Flowise工作流引擎的本地部署与远程访问实践
  • 算法-每日一题(DAY11)每日温度
  • King’s LIMS 系统引领汽车检测实验室数字化转型
  • 【Wi-Fi天气时钟】网络授时
  • uniapp评价组件
  • net程序-Serilog 集成 SQL Server LocalDB 日志记录指南
  • Vue框架深度解析:从Vue2到Vue3的技术演进与实践指南
  • C++11 右值引用(Rvalue Reference)
  • SM3算法C语言实现(无第三方库,带测试)
  • 全面掌握 C++ 基础:关键特性与进化