Redis缓存使用中的热key问题

何为热key问题?

从名字上可以理解,Redis中的热key就是在Redis中频繁被访问的数据,例如热点新闻,热点评论,双十一商品等等。当某一热key的请求到Server主机时,这样会造成流量过于集中,达到物理网卡上限,从而导致这台redis的主机资源不足,甚至宕机。那接下来这个key的请求,就会直接怼到你的数据库上,导致你的服务不可用。
热点数据对服务器来说,是一个巨大的隐患,以redis-cluster 来说,它可能会造成整体流量不均衡,个别ops过大的情况,极端的情况下,可能直接超过redis本事的承受能力。

热key问题产生的原因

  1. 用户消费的数据远远大于生产的数据,比如热卖商品、热点新闻、热点评论等,这些典型的读多写少的场景会产生热点问题。
    2.在请求分片集中,超过单Server的性能极限,比如固定名称的key,hash落入一台Server,在访问量极大的情况下,超过Server极限时,就会导致热点问题的产生。

热key问题的危害

  1. 流量过于集中,达到物理网卡上限,从而导致这台redis的主机资源不足,甚至宕机
  2. 请求过多,缓存分片服务被打垮,不能通过扩容解决,且不能发挥集群多分片的优势
  3. 可能会造成缓存雪崩和缓存穿透

如何发现热key?

  1. 客户端代码统计
    即在操作redis之前,加入一行代码进行数据统计。这个数据统计的方式有多种,也可以是给外部的通讯系统发送一个通知信息。但是缺点是有代码入侵,且维护成本较高,大规模落地肯定不合适,万一热key多了,还有可能oom。

  2. 凭借业务经验,进行预估
    例如提前知道了某个活动的开启,那么就将此Key作为热点Key。但不是每个人都有这个经验的。

  3. 如果服务端有代理层,可以在代理层进行收集上报
    在代理层做收集上报的话,首先,得用了代理,例如codis之类的。因此缺点也很明显,并非所有的redis集群架构都有proxy,而且需要做二次开发,肯定得投入人力改proxy源码,不论难不难,都要考虑一个稳定性和维护成本。

  4. 用redis自带命令

    • hotkeys参数,redis于4.0.3版本开始正式支持基于LFU的热点key发现机制,执行redis-cli时加上–hotkeys选项即可。但是该参数在执行的时候,如果key比较多,执行起来比较慢,且只适用于缓存淘汰策略是lfu的时候。
      (可以参考https://yq.aliyun.com/articles/278922
    • monitor命令,该命令可以实时抓取出redis服务器接收到的命令,然后写代码统计出热key是啥。当然,也有现成的分析工具可以给你使用,比如redis-faina。但是monitor命令在高并发的场景下,会存在内存暴增,影响redis的性能,只适合短时间的统计,不适合一直使用,只能统计单节点的热点key,对于集群需要进行汇总统计。
  5. TCP消息抓包
    Redis客户端使用TCP协议与服务端进行交互,通信协议采用的是RESP。如果站在机器的角度,可以通过对机器上所有Redis端口的TCP数据包进行抓取完成热点key的统计。但是依然存在3个问题:

    • 需要一定的开发成本,但是一些开源方案实现了该功能,例如ELK(ElasticSearch Logstash Kibana)体系下的packetbeat[2] 插件,可以实现对Redis、MySQL等众多主流服务的数据包抓取、分析、报表展示;
    • 对于高流量的机器抓包,对机器网络可能会有干扰,同时抓包时候会有丢包的可能性;
    • 维护成本过高。

如何解决热key问题?

  1. 拆分复杂数据结构: 如果当前key的类型是一个二级数据结构,例如哈希类型。如果该哈希元素个数较多,可以考虑将当前hash进行拆分,这样该热点key可以拆分为若干个新的key分布到不同Redis节点上,从而减轻压力。
  2. 备份热点key:不要让key走到同一台redis上就行了,把热点key在多个redis上都存一份,有热key请求进来的时候,我们就在有备份的redis上随机选取一台,进行访问取值,返回数据。
    假设redis的集群数量为N,步骤如下图所示:

    不一定是2N,你想取3N,4N都可以,看要求。
  3. 本地缓存加通知机制:可以将热点key放在业务端的本地缓存中,针对这种热key请求,会直接从JVM中去,而不通过redis层。因为是在业务端的本地内存中,处理能力要高出Redis数十倍,但当数据更新时,此种模式会造成各个业务端和Redis数据不一致,通常会使用发布订阅机制来解决类似问题。
    (亦可参考https://www.iteye.com/blog/carlosfu-2269687
posted @ 2020-08-06 15:32  heaven096  阅读(1326)  评论(0编辑  收藏  举报