如何解决Redis中的热点key问题
Redis中的热点Key问题
是指某些特定的Key被频繁访问,导致Redis中某个节点(或实例)承担过高的压力,可能引发性能瓶颈,甚至若缓存承受不住服务压力挂掉后,仍有大量请求时直接打到DB上,由于DB层相对缓存层查询性能更弱,在面临大请求时很容易发生DB雪崩现象,严重影响业务。
1. 什么样的Key被称为热点Key
通常以Key被请求频率来判定,目前没有具体的固定的数值来衡量,但有相关参考标准:
- QPS集中在特定的Key:如Redis实例的总QPS(每秒查询率)为2W,而其中一个Key的每秒访问量达到了1W以上
- 带宽使用率集中在特定的Key:对一个拥有上千个成员且总大小为1MB以上的HASH Key,每秒发送大量的HGETALL操作请求;
- CPU使用时间占比集中在特定的Key:对一个拥有数万个成员的Key(ZSET类型)每秒发送大量的ZRANGE操作请求;
2. 解决方案
- 热点key拆分
热点Key问题是由于某个(或某些)Key被频繁访问,因此最直接的解决方案是破坏热点Key的形成,将热点Key进行逻辑拆分,将一个热点key拆分为多个Key,通过逻辑分片的方式将请求分散到不同的Key上,从而避免集中访问。拆分方式有两种:全量拷贝和切片拷贝。
有些场景可以将热点Key进行全量拷贝,比如主从复制架构下,将hot_key拆分成hot_key1、hot_key_2、hot_key_3等,它们之间的数据是一致的,不同的请求都能访问到全量的数据。
有些场景可以将热点Key进行拆分,hot_key1、hot_key_2、hot_key_3各存储hot_key的一部分数据
实现方式如下:
数据写入时:
- 将热点 Key 拆分为
key_1
、key_2
、key_3
等多个 Key。 - 访问时通过随机选择、哈希映射等方式确定具体的分片 Key。
数据读取时:
聚合所有分片数据,返回合并后的结果。
- 使用二级缓存+Redis缓存
使用本地缓存,如利用ehcache、GuavaCache等,甚至是一个HashMap都可以。在发现热Key以后,把热Key加载到系统的JVM中,针对这种热Key请求,会直接从本地缓存中取,而不会直接请求redis;非热点Key直接走Redis缓存。
- 读写分离
在主从复制模式下,从库会存储主库的所有数据包括热点Key,因此通过主从的读写分离,将读请求负载均衡分发到不同的从节点上,从而降低单节点的压力。
- 高并发优化
对于频繁的写操作如计数器累加等,可以通过批量合并多个请求来减少Redis的访问频率。
- 限流和降级(兜底方案)
为防止发生热点Key问题时造成服务不可能等严重问题,可在热点Key访问过高时,进行应用限流,限制访问频率,减少对Redis的访问,甚至有必要时返回降级的数据(可通过配置文件自行定义)或空值。
3. 如何发现及预防热点Key
- 根据业务经验进行分析(推荐)
主要根据业务场景进行分析,通过经验来判断哪些Key可能会成为热点Key,比如秒杀活动、演唱会门口、热搜新闻等。但是并不是每个热key都能被准确的预测,如对于电商平台来说,商家什么时候会上架相对火爆的秒杀活动就很难预测了,但是可以借助对不同商家的历史活动的数据分析来做一定的参考。
- Redis集群监控(依赖于集群,较推荐)
该方案依赖于Redis集群,在Redis集群架构下,查看集群中的哪个Redis出现QPS倾斜,而出现QPS倾斜的实例有极大可能存在热点Key。
- 使用hotKey监控(不推荐)
该命令为Redis 4.0后新引入的一个指令,需要扫描所有的Key,如果Key较多的话执行时间会很长,效率低下。
- 客户端监控和收集(推荐)
这个方式就是在操作Redis之前,加入一行代码进行数据统计,异步上报行为,如类似日志采集,将单次Redis命令的操作/结果/耗时等统计,异步消息发送给采集消息队列,缺点就是对代码造成入侵,一般可以交给中间件加在自己包的redis二方包中;如果有做的好一点的Daas平台,可以在proxy层做监控,业务无需感知,统一在Daas平台查看redis监控;