如何解决 Redis 中的热点 key 问题?
如何解决 Redis 中的热点 key 问题?
回答重点
Redis 中的热点 Key 问题是指某些 Key 被频繁访问,导致 Redis 的压力过大,进而影响整体性能甚至导致集群节点故障。
解决热点 Key 问题的主要方法包括:
- 热点 key 拆分:将热点数据分散到多个 Key 中,例如通过引入随机前缀,使不同用户请求分散到多个 Key,多个 key 分布在多实例中,避免集中访问单一 Key。
- 多级缓存:在 Redis 前增加其他缓存层(如 CDN、本地缓存),以分担 Redis 的访问压力。
- 读写分离:通过 Redis 主从复制,将读请求分发到多个从节点,从而减轻单节点压力。
- 限流和降级:在热点 Key 访问过高时,应用限流策略,减少对 Redis 的请求,或者在必要时返回降级的数据或空值。
扩展知识
热点 key 的定义
热点 Key 与 big key 一样,没有一个很明确的定义来约定什么样的 key 叫做热点 key。
我们可以参考阿里云 Redis 对热 key 的定义:
可以看到,如果一个 key 的访问频率占比过大,或带宽占比过大,都属于热点 key。
由于 Redis 的读写是单线程执行的,所以热点 key 可能会影响 Redis 的整体效率,消耗大量的 CPU 资源,从而降低 Redis 的整体吞吐量。集群环境下会使得流量不均衡,从而导致读写热点倾斜问题的发生。
如何发现热 key?
1)根据业务经验进行分析
这个主要就是依据业务场景进行分析,通过经验判断哪些 key 可能成为热门 key,比如某明星的花边新闻、秒杀活动,演唱会门票等。
- 优点:这个方案实现起来简单直接,只有直接进行判断就可以了,基本没有什么成本。
- 缺点:这个主要依据业务能力,对于业务能力有一定的要求,并且不是所有的业务都能判断出来是否是热 key 的。且有些突发事情是无法预测的。
2)redis 集群监控
这种方式主要依据与 Redis 集群,我们只需要查看集群中哪个 Redis 出现 QPS 倾斜,而出现 QPS 倾斜的实例有极大的概率存在热点 Key。
- 优点:这种方案和上面差不多,由于企业的 Redis 大多数是集群部署,所以使用起来非常简单。
- 缺点:每次发生状况都需要排查,因为不一定所有的 QPS 倾斜都是热 Key 导致的。
3)使用 hotkey 监控
这个是 Redis 4.0 版本之后引入的一个新的指令,只需要在命令行执行 redis-cli 的时候加上 –hotkeys 的选项就可以了。它是通过 scan + object freq 实现的。
- 优点:因为这个命令是 Redis 自带的,使用起来简单快捷
- 缺点:需要扫描整个 keyspace,如果 Redis 中的 key 数量比较多的话,可能导致执行时间非常长,且实时性不好。
4)使用 monitor 命令
如下图所示,这个是 Redis 自 1.0 起就支持的功能。
当通过 MONITOR 命令开启监视器之后,Redis 只需要在执行之后结合一些日志和相关的分析工具就可以进行统计。
- 优点:这个方案的优点在于这个是 Redis 原生支持的功能,使用起来简单快捷。
- 缺点:monitor 非常消耗性能,单个客户端执行 monitor 就会损耗 50% 的性能!不推荐这个方式!
以下为 redis 官网的 benchmark:
5)客户端收集
在操作 Redis 之前,通过加上统计 Redis 键值查询频次的逻辑,将统计数据发送给一个聚合计算平台进行计算,计算之后查看相对应的结果
- 优点:对性能损耗较低。
- 缺点:成本较大,企业如果没有聚合计算平台还需要引入。
6)代理层收集
在代理层进行统一的收集,因为有些服务在请求 Redis 之前都会请求一个代理服务,这种场景可以使用在代理层收集 Redis 热 Key 数据,和在客户端收集比较类似。
- 优点:客户端使用方便,不需要考虑 SDK 多语言异构差异和升级成本高的问题。
- 缺点:需要给 Redis 定制一个代理层,进行转发等操作,构建代理成本不低,且转发有性能损耗。
应用程序中的多级缓存
在应用程序中,一般结合使用一级缓存和二级缓存:
- 一级缓存:一般指的是应用程序本地缓存(如 JVM 内存中的缓存)。
- 二级缓存:则为 Redis 缓存。当数据不在一级缓存中时,才会请求二级缓存。
通过这种多级缓存架构,可以有效减少 Redis 的访问次数,从而避免单 Key 的热点问题。
热点 key 的拆分
我们可以按照不同场景做不同的“拆分“。有些场景可以全量拷贝,即将 mianshiya 这个 key 复制成 mianshiya_1、mianshiya_2、mianshiya_3 ,它们之间的数据是一致的,这样不同用户都访问到全量的数据。
有些场景直接进行 key 的拆分,mianshiya_1、mianshiya_2、mianshiya_3 各存一部分的数据,不同用户仅需访问不同数据即可,例如一些推流信息,因为一个热点往往有很多发布者,大家看一部分,后续热度稍微降低下来,可以替换数据。
不同用户可以进行 hash,将用户 id 哈希之后取余得到后缀,拼上 mianshiya_ 即可组成一个 key。