Redis- 热key

热key

热key问题的本质

热Key问题是指在分布式缓存或数据库系统中,某些特定的Key在短时间内接收到大量的访问请求,导致这些Key所在的节点负载过高,形成系统瓶颈,甚至引发雪崩效应。这类似于现实世界中的'热点'现象,少数资源承受了大部分的访问压力.

从本质上看,热Key问题是资源分配不均衡的表现。在理想情况下,请求应该均匀分布在所有节点上,但实际业务中,数据访问通常遵循二八定律,即20%的数据承担了80%的访问量。当这种不均衡达到极端时,就形成了热Key.

例如:秒杀活动中的商品库存Key、双十一期间的热门商品信息Key、实时排行榜数据Key等,这些Key在特定时间段内会接收到远超系统平均水平的访问请求。

热key的危害

热Key问题会导致多方面的系统风险:

  • 首先,热Key所在节点可能因负载过高而响应变慢或崩溃;
  • 其次,当热Key节点不可用时,大量请求可能会穿透到后端数据库,引发连锁反应;
  • 最后,即使系统没有崩溃,热Key也会导致资源利用不均衡,降低整体系统效率

如何识别热key

要解决这种极热 key 的问题,首先要找出这些 Hot key 来。

识别热Key主要有三种方法:

  • 一是通过Redis自带的监控命令如MONITOR或INFO进行实时监控;
  • 二是使用第三方工具如Redis-faina或Redis-stat进行数据分析;
  • 三是在应用层进行采样统计,记录高频访问的Key。

在项目中,一般用多层次的热key识别策略:

  • 预防性识别:基于业务特性,提前预判可能的热Key。例如,新品发布、促销活动、热点新闻等场景下的相关Key。
  • 实时监控:我们开发了一个专门的热Key监控服务,通过在Redis代理层采样请求,并结合滑动窗口计数算法,实时识别访问频率突增的Key。
  • 日志分析:对Redis的慢查询日志和访问日志进行离线分析,识别历史上的热Key模式,用于优化未来的策略。
  • 自适应采样:在高峰期增加采样率,低峰期降低采样率,平衡监控精度和系统开销

解决方案

客户端缓存与本地缓存

在应用服务器上引入本地缓存,可以有效减轻Redis集群的热Key压力。常用的本地缓存方案包括Caffeine、Guava Cache等,通过合理设置过期时间和更新策略,可以在保证数据相对新鲜的同时,大幅降低对分布式缓存的访问频率。

对于商品详情这类读多写少的数据,可以在应用服务器上部署了两级缓存:

  • JVM本地缓存:使用Caffeine实现,针对超热Key设置较短的过期时间(如10秒)和较大的容量。
  • 分布式缓存:使用Redis集群,作为本地缓存未命中时的第二层防护
    同时,我们通过消息队列实现了缓存更新的准实时通知,当商品信息变更时,主动失效相关的本地缓存,保证数据的一致性。

热key分片

热Key分片是指将一个热Key的数据分散到多个子Key中,每个子Key负责一部分数据,从而将访问压力分散到多个节点。这种方法特别适用于可以进行数据分割的场景,如列表数据、计数器等.

比如,对于一个商品评论列表这类的热key,我们采用分片策略:

  • 数据分片:将评论数据按照时间或ID范围分成多个子列表,存储在不同的Key中,如product:10001:comments:1、product:10001:comments:2等。
  • 请求路由:客户端请求时,根据页码或时间范围计算出应访问的子Key,或者使用随机策略选择一个子Key。
  • 结果聚合:对于需要聚合结果的场景,如获取评论总数,我们预先计算并存储在单独的Key中,或者使用Redis的脚本功能在服务端进行聚合。
    这种分片策略使我们能够将单个热Key的访问压力分散到多个Redis节点,有效避免了单点瓶颈。

读写分离与副本漂移

利用Redis的主从复制机制,可以实现读写分离,将读请求分流到多个从节点,减轻主节点压力。对于特别热的Key,还可以实现'副本漂移',即为热Key创建更多的副本,提供更大的读取带宽。

项目中实现动态读写分离策略思路:

  • 基础读写分离:使用Redis Sentinel或Redis Cluster,将读请求默认路由到从节点,写请求路由到主节点。
  • 动态副本调整:监控系统实时检测热Key,当发现热Key时,自动为其创建额外的副本,并更新路由策略,将该Key的读请求优先路由到这些副本。
  • 一致性保证:对于强一致性要求的场景,我们实现了'读-写-读'模式,即先尝试从节点读取,如果数据过期或不存在,则回源到主节点,并更新从节点数据。
    这种动态调整的策略,使我们能够针对不同的Key提供不同级别的服务质量,既保证了热Key的访问性能,又避免了资源浪费。
相关推荐
C++chaofan2 分钟前
游标查询在对话历史场景下的独特优势
java·前端·javascript·数据库·spring boot
小蒜学长9 分钟前
springboot房地产销售管理系统的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端
这是谁的博客?19 分钟前
LangChain第三页【操作指南】_【如何缓存对话模型响应】翻译完成
缓存·langchain
_不会dp不改名_21 分钟前
leetcode_146 LRU缓存
算法·leetcode·缓存
执键行天涯21 分钟前
idea中已经被git缓存追踪的文件,如何让git重新忽略
git·缓存·intellij-idea
0wioiw038 分钟前
PostgreSQL(②基础命令)
数据库·postgresql
xcLeigh1 小时前
KingbaseES数据库:兼容 SQL 语法及 Oracle 过程化语言的语法基础
数据库
FinTech老王1 小时前
一场“无感换心”手术:金仓数据库如何让电子证照系统平滑告别MongoDB
数据库·mongodb
周杰伦的稻香1 小时前
MySQL中的空间碎片率计算分析
android·数据库·mysql
重启的码农1 小时前
kv数据库-leveldb (13) 缓存 (Cache)
数据库