Redis内存爆了

一次基于redis做队列消费cannel的binlog导致内存被打爆的场景分析

问题复现流程图:

  • 100万次 SQL 更新 → 100万个 Binlog 事件
  • 100万个事件 → 100万个队列任务(都在同一个业务队列中)
  • 100万个任务 → 100万个监控 Key(Horizon 监控每个任务)

每次 MySQL UPDATE 都会产生一个 Binlog 事件 100万次 UPDATE = 100万个 Binlog 事件

  • Canal 为每个 Binlog 事件创建一个队列任务
php 复制代码
foreach ($binlogEvents as $event) {
    // 每个事件都创建一个任务,塞到同一个队列
    Redis::lpush('ai_vending_horizon', json_encode([
        'id' => generateUUID(),
        'event' => $event,
        'timestamp' => time()
    ]));
}

horizon:laravel框架的queue队列管理服务 支持队列中每个任务的监控和管理

  • 暂停/恢复队列
  • 重试失败任务
  • 清空队列
  • 查看任务详情`
  • 任务超时

等等

Laravel Horizon 本身是个很好的工具,但在事故中:

  • 监控开销过大:每个任务都创建多个监控 Key
  • 缺乏批量处理:没有针对大批量任务的优化
  • 内存管理缺失:没有监控 Key 数量的限制
  • 缺乏redis内存监控告警

Horizon都干了啥?

arduino 复制代码
// 每个任务创建6个监控Key
"ai_phone_horizon:task_001"           // 任务状态Key
"ai_phone_horizon:task_001:metrics"   // 任务指标Key  
"ai_phone_horizon:task_001:runtime"   // 运行时间Key
"ai_phone_horizon:task_001:memory"    // 内存使用Key
"ai_phone_horizon:task_001:failed"    // 失败信息Key
"ai_phone_horizon:task_001:retries"   // 重试次数Key

100万个任务 × 6个监控Key = 600万个监控Key

任务级别的监控的作用

diff 复制代码
// 需要知道每个任务的状态
- 任务是否成功执行?
- 任务执行了多长时间?
- 任务消耗了多少内存?
- 任务失败了吗?
- 任务重试了几次?

监控开销计算

100万个任务 × 每个任务6个监控Key = 600万个 Redis Key

同时业务逻辑消费慢,任务被阻塞,导致业务的任务队列数据数据越来越多,对应的key越来越大,变成一个吃内存的超级大key

在这里想到了golang的Asynq库同样可以实现队列的监控,这个玩意的监控策略和laravel Horizon有啥区别?

asynq: github.com/hibiken/asy...

Asynq 的 Key 结构

arduino 复制代码
// 每个任务创建1个存储Key
"asynq:default:t:task_001" = {任务数据}
"asynq:default:t:task_002" = {任务数据}
// 100万个任务 × 1个存储Key = 100万个存储Key

// 监控Key(固定数量,不随任务数量增长)
"asynq:queues:default"           // 队列统计
"asynq:queues:default:processed" // 已处理数
"asynq:queues:default:failed"    // 失败数
"asynq:stats:processed"          // 总处理数
"asynq:stats:failed"            // 总失败数
// 总共约10-20个固定监控Key

关键差异: Asynq 的优势在于不创建任务级别的监控Key,只创建系统级别的统计Key

优化、优化,调整

相关推荐
高频因子挖掘机1 分钟前
量化回测应该保存不复权数据吗?从数据口径到收益计算的工程实践
后端·github·api
高频因子挖掘机1 小时前
实时行情为什么不应该逐只股票请求?批量查询与标的池管理实践
后端·github·api
程序猿DD6 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
余槐i9 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8269 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
凤山老林10 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne11 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF11 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
pride.li12 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
upala12 小时前
【仓颉语言入门 · 第二篇 第 6 课】
后端