目录标题
- 一、什么是热Key?
- 二、热点key危害?
- [三、如何发现热点 key?](#三、如何发现热点 key?)
- 四、热点key应对措施
一、什么是热Key?
热 key 问题就是突然有几十万的请求去访问 redis 上的某个特定 key,那么这样会造成流量过于集中,达到物理网卡上限,从而导致这台 redis 服务器直接宕机。
Redis 中的热点 key 是指被大量请求访问的某些键,通常是由于这些键存储了热门数据,如热门商品、秒杀场景、热门文章、用户会话等。热点 key 的出现可能会带来一些问题和危害,以下是其介绍和应对方法:
- 请求集中:热点 key 会导致大量请求集中在少数几个 key 上,增加了对这些 key 的访问压力。
- 性能下降:由于请求集中,热点 key 的访问频率较高,可能会导致 Redis 服务器的性能下降,甚至造成 Redis 集群的崩溃。
- 缓存击穿:如果某个热点 key 在缓存中过期,且被大量请求访问,那么这些请求可能会直接落到数据库上,导致数据库负载剧增,甚至可能导致数据库宕机。
- 数据不一致:如果热点 key 的数据被频繁修改,那么可能会导致数据不一致的问题,尤其是在进行分布式部署时。
- 主从同步延迟:如果Redis处于主从模式,热点Key的频繁访问会导致主节点压力增加,进而导致主从同步延迟,产生数据不一致的风险。这种情况在高并发场景下尤为明显。
二、热点key危害?
- 服务可用性下降:热点 key 可能会导致 Redis 服务器的性能下降,甚至造成 Redis 服务不可用,从而影响整个系统的服务可用性。
- 系统稳定性受损:热点 key 的存在可能会导致系统出现性能波动,从而影响系统的稳定性和可靠性。
- 用户体验差:由于热点 key 可能导致请求响应时间变长,从而影响用户的体验,导致用户流失或不满意。
三、如何发现热点 key?
- 凭借业务经验,进行预估哪些是热 key。比如某些商品要做秒杀,则商品 key 就可以判断为热 key,但并非所有业务都能预估出热 key。
- 在客户端进行收集。比如在 redis 客户端执行 redis 命令之前,加入一行代码进行命令数据收集,然后通过网络将收集的命令发送出去,缺点是对客户端代码有入侵。
- 在 Proxy 层做收集,但是并非所有的 redis 集群都有 proxy。
- 用 redis 自带命令,monitor 命令可以实时抓取出 redis 服务器接收到的命令,然后写代码统计出热 key 是啥,不过高并发条件下,有内存暴增的隐患,影响 redis 的性能。Facebook 开源的 redis-faina(Python),提供了对 Monitor 的一些分析与定位。Monitor 命令本身会影响 Redis 的性能,特别是在高负载环境中。它会占用部分 Redis 服务器的 CPU 资源和网络带宽。
- redis4.0.3 提供了客户端热点 key 发现功能,如果 key 比较多,执行比较慢。对性能要求不是太高的业务场景下,建议使用该进行 Hotkey 的定位与分析。使用前需要先配置 Redis 的内存淘汰策略
- 自己抓包评估,redis 客户端使用 TCP 协议与服务端进行交互,通信协议采用 RESP,自己写程序监听端口,按照 RESP 协议规则解析数据进行分析,不过开发成本较高,不易维护。ELK 提供了一个名为 packetbeat 的抓包插件,可以对 Redis 的 TCP 报文进行抓包与分析。但往往需要搭配 ELK 一起使用,单独使用 packetbeat 插件的话也需要额外做一些定制化变更。
四、热点key应对措施
- 数据分片:将热点 key 的数据进行分片存储,将请求均匀分布到不同的节点上,从而降低单个节点的压力。
- 缓存预热:在系统启动时,预先加载热点数据到缓存中,避免大量请求落到数据库上。
- 缓存失效策略:合理设置缓存的失效策略,避免所有缓存同时失效导致大量请求落到数据库上。
- 缓存击穿处理:使用互斥锁或者设置热点 key 的短期失效时间,避免大量请求同时落到数据库上。
- 监控与告警:实时监控热点 key 的访问情况,及时发现并处理潜在的问题。
- 负载均衡:使用负载均衡技术,将请求均匀地分发到不同的节点上,降低单个节点的压力。
- 增加二级缓存:发现热 key 以后,可以把热 key 数据加载到系统 JVM 并设置合适的缓存过期时间,针对热 key 的请求就会直接分散到各业务服务器上,防止所有请求同时访问同一台 redis。(如Guava Cache、Caffeine等)
- 多级缓存:可以对 Hotkey 灵活调整缓存策略,比如客户端本地+分布式缓存、全局缓存+局部缓存、本地缓存 + Redis + CDN等。
- 根据业务拆分子 key:该方式适用于 key 的数量较少且可以对 key 或 value 自身进行拆分的情况,令 Hotkey 尽量分散的落到不同的实例上。