Spring Boot 本身不提供 Redis 热点 Key 自动探测能力,必须在应用层主动埋点+聚合分析+规则联动;@Cacheable 和 RedisTemplate 仅负责读写,不记录频次、不感知访问模式,Redis 的 allkeys-lru 仅基于最后访问时间被动淘汰,无法识别“product:10086 每秒2300次”等实时热度,也不支持业务规则联动与预热。

Spring Boot 本身不提供 Redis 热点 Key 自动探测能力,必须在应用层主动埋点 + 聚合分析 + 规则联动,否则所有依赖 @Cacheable 或 RedisTemplate 的代码都对“谁正变热”一无所知。
为什么 @Cacheable 和 RedisTemplate 都无法识别热点
它们只负责读写,不记录频次、不感知访问模式、不触发任何热度判断逻辑。即使你配置了 maxmemory-policy: allkeys-lru,那也只是 Redis 服务端的被动淘汰策略——它只看最后访问时间,不看每秒多少次;它不会告诉你“product:10086 刚被调用 2300 次/秒”,更不会通知 Spring Boot 去预热或降级。
常见错误现象:
- 监控显示 Redis CPU 飙高,但 Prometheus 里查不到具体哪个 key 在扛压
- 缓存穿透后数据库被打挂,回溯发现是某个未预热的活动页 key 突然爆量
- 用
redis-cli --hotkeys扫描,结果为空或延迟数分钟,错过黄金响应窗口
用 AOP + 自定义注解实现轻量级访问计数
在 service 层拦截真实业务 key,避免污染 controller,也绕过 Redis 客户端封装带来的 key 抽象丢失问题。
实操要点:
- 定义注解
@HotKey(track = "user:profile"),支持 SpEL 表达式(如#userId)解析成真实 key - AOP 切面中调用
MeterRegistry.counter("redis.hotkey.count", "key", realKey).increment() - 不要直接上报原始 key(如
user:12345),统一归一化为user:{id},防止指标爆炸 - 计数器需带时间窗口(如滑动 60 秒窗口),否则单次突发无法区分是常态还是热点
如何让 Prometheus 真正抓到可告警的热点指标
Actuator 默认不暴露 key 级访问频次,必须手动注册 metric 并启用对应 endpoint。
关键配置与检查点:
- 在
application.yml中开启:management.endpoints.web.exposure.include=health,metrics,prometheus - metric name 命名建议为
redis.key.access.{pattern},例如redis.key.access.user:{id} - Prometheus 查询示例:
rate(redis_key_access_user_id_count_total[1m]) > 100,用于告警 - 避免在
RedisTemplate的每个get()调用里 new Counter 实例——复用MeterRegistry实例,否则 GC 压力陡增
为什么不能只靠 Redis 内置 --hotkeys 或 MONITOR
它们要么延迟高、要么破坏性大,都不适合生产实时探测。
典型陷阱:
-
redis-cli --hotkeys要求 LFU 淘汰策略且需全量 scan,1000 万 key 场景下耗时可能超 30 秒 -
MONITOR会吃光 Redis 内存并拖慢吞吐,线上严禁长期开启 - 两者都无法关联业务语义:比如“商品详情页访问超 500 QPS 就自动加本地缓存”,这个规则只能在应用层表达
- 它们输出的是“过去发生了什么”,而你需要的是“接下来几秒要发生什么”的预测性干预能力
真正难的不是统计次数,而是把“高频访问”和“业务影响”挂钩——比如一个 key 每秒 200 次,对首页是热点,对后台管理接口可能只是常态。这个边界必须由业务方定义,并通过规则引擎(如 Etcd 配置或内存阈值)动态加载,而不是写死在代码里。


















