搞定分布式系列:缓存 热key 问题解决方案

在分布式缓存中,面对高并发要求有两个问题非常重要:热key问题(hot key)大value(big key)问题。

  1. 热key问题:是指缓存集群中的某个key在瞬间被数万甚至十万的并发请求打爆。
  2. 大value问题:是指某个key对应的value可能有gb级别的大小,导致查询value的时候会引发网络相关的故障问题。

不管是hot key,还是big key都有可能是压垮服务的最后一根稻草。本节我们重点看下缓存的热key问题。

一、热key问题定义

热key问题是指:突然有几十万甚至更大的请求去访问redis上的某个特定key。这样会造成流量过于集中,达到Redis单实例瓶颈(一般是10W QPS级别),或者物理网卡上限,从而导致这台redis的服务器Hold不住,直到缓存服务器垮掉。

要解决缓存中的热key问题也简单,主要分两步:监控热key和处理热key。

二、发现热key

有效的发现热点key,对我们来说至关重要,主要有这么几个途径:

1、按业务场景,预估热点key(常用)

这步是必做的,没啥技术难度,主要是对业务的预估和理解。比如秒杀商品业务中,秒杀的商品都是热点key。缺点是预估往往有偏差,总会有想不到的地方成为热点,或者突发的状况。

2、客户端收集(常用)

在访问redis客户端之前加入一行代码进行数据统计,统计方式多种多样,有本地计数、发消息单独处理统计等。优点:实现简单方便;缺点:代码侵入大。

3、代理层收集

缓存层之前加一层proxy代理层(比如Twemproxy),代理层做缓存统一入口。优点:对代码无入侵;缺点:架构复杂,缓存架构需要代理层设计。

4、redis监控命令(常用)

redis本身提供了相应的监控命令,

  • monitor命令:可以实时抓取出redis服务器接收到的命令,然后写代码统计出热key是啥。缺点:该命令在高并发的条件下,不仅有内存暴增的隐患,还会降低redis的性能。
  • hotkeys命令:redis 4.0.3提供了redis-cli的热点key发现功能,执行redis-cli时加上–hotkeys选项即可,操作方便缺点:该参数在执行的时候,如果key比较多,执行起来比较慢。

5、网络抓包分析

Redis客户端使用TCP协议与服务端进行交互,通信协议采用的是RESP。自己写程序监听端口,按照RESP协议规则解析数据,进行分析。缺点就是开发成本高,维护困难,有丢包可能性。

6、基于大数据流式计算技术的缓存热点自动发现

基于大数据领域的流式计算技术来进行实时数据访问次数的统计,比如storm、spark streaming或flink,这些技术都是可以的。然后一旦在实时数据访问次数统计的过程中,比如发现一秒之内,某条数据突然访问次数超过了1000,就直接立刻把这条数据判定为是热点数据,可以将这个发现出来的热点数据写入比如zookeeper中。

三、解决方案

现在主流的解决方案分两步:监控热点key处理热点key

1、监控热点key

推荐这几种方式:按业务场景,预估热点key(必做);客户端收集。

2、处理热点key

使用本地缓存(二级缓存)。

搞定分布式系列:缓存 热key 问题解决方案_第1张图片

监控到热点数据后,处理热点key这一步,系统层就可以立马把相关的缓存数据从数据库加载出来,然后直接放在自己系统内部的本地缓存即可。这个本地缓存,用ehcach,hashmap都可以,具体看业务需求,主要就是要将缓存集群里的集中式缓存直接变成每个系统自己本地实现的缓存即可,每个系统自己本地是无法缓存过多数据的。因为一般这种普通系统单实例,部署机器可能就是一个4核8G的机器,留给本地缓存的空间是很少的,所以用来放这种热点数据的本地缓存是最合适的。

假设系统层集群部署了100台机器,这时这100台机器瞬间在本地都会有一份热点缓存的副本。然后接下来对热点缓存的读操作,直接系统本地缓存都出来就会返回了,不需要再走缓存集群了。这样的话,也不可能允许每秒20万的读请求到达缓存机器的一台机器上读一个热点缓存了,而是变成100台机器每台机器承载数千个请求,这数千请求直接从机器的本地缓存返回数据。

3、熔断限流保护

熔断限流也是极端情况下需要考虑的事情。面对高并发可以加一个对热点数据访问的限流熔断保护措施,限定缓存集群每秒最多的请求次数。防止缓存集群被干爆。

四、总结

上面的热key问题是面对高并发情况下,不得已的办法,涉及到两级缓存架构有点复杂了,实际情况主要看业务场景是否确实需要。比如每台redis上限10w/s QPS,redis5.0的话我们一般是集群部署3主6从,热key一般分布到一个哈希槽上面,也就是一个主redis+两个从redis,理论上能满足30w/s的QPS,我们预留一点buffer,10wQPS肯定没问题了。如果再高,比如百万的访问量,那除了扩展redis集群外,本地缓存也是必须的了。总之,架构时综合考虑实际场景来吧。

你可能感兴趣的:(搞定分布式系列)