高并发百万级热点key处理方案

背景

我们知道在面试中,面试官经常会问一些关于高并发的问题,其中热点key问题就是一个热门问题,热点key顾名思义就是访问非常频繁的key,再加上高并发访问条件,热点key缓存问题如何解决。接下来我们从以下三个方面来剖析一下:

1、热点key定义

2、如何发现热点key

3、解决方案

热点key定义

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

如何发现热点key

1、凭借业务经验,预估出那些访问频繁的热点key

优点:可行性高,例如秒杀商品业务中,秒杀的商品都是热点key

缺点:并非所有的业务都容易预估出热点key,例如商品推荐业务,你事先是无法料之客户的喜好的

2、客户端收集

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

缺点:对客户端代码造成入侵

3、在Proxy(代理层)收集

优点:proxy层统一入口做统计,对业务代码无入侵

缺点:要求缓存架构有proxy层结构才行,例如Proxy可以是Twemproxy

4、使用redis自带命令

4.1、monitor命令

monitor命令可以实时抓取出redis服务器接收到的命令,然后写代码统计出热key是啥。当然,也有现成的分析工具可以给你使用,比如redis-faina。

缺点:该命令在高并发的条件下,不仅有内存暴增的隐患,还会降低redis的性能

4.2、hotkeys参数

优点:redis 4.0.3提供了redis-cli的热点key发现功能,执行redis-cli时加上–hotkeys选项即可,操作方便

缺点:该参数在执行的时候,如果key比较多,执行起来比较慢

5、自己抓包分析

Redis客户端使用TCP协议与服务端进行交互,通信协议采用的是RESP。自己写程序监听端口,按照RESP协议规则解析数据,进行分析。

缺点:开发成本高,维护困难,有丢包可能性

以上五种发现热点key的方案,各有优缺点,这个要根据自己的业务场景选择最适合自己的就行

解决方案

1、使用二级缓存(极力推荐)

例如使用 guava-cache,或者 ehcache,或者最常用的集合 Hash 等,发现热点key之后,将这些热点key加载到JVM中(可以是堆内,也可以是堆外)作为本地缓存。访问这些key时直接从本地缓存获取即可,不会直接访问到redis层了,有效的保护了缓存服务器

2、备份热点key

不要让同一个key都存放到同一台redis机器上,我们把这个key在多个redis上都存一份。当有热key请求进来的时候,我们就在有备份的redis上随机选取一台,进行访问取值,返回数据。
假设redis的集群数量为N,步骤如下图所示:


缺点:缓存的维护代价非常大,假设有100个备份KEY,那么在删除或者更新时,也需要更新100个KEY,所以这种方案不是很推荐

热点key拓展(业内方案)

对于上面的发现热点key和解决方案了解后,我们想有办法在项目运行过程中,自动发现热点key,然后程序自动处理么?这个在业内是怎么做的呢?其实只有两步:

1、监控热点key

2、通知系统做处理

业务有赞出了一篇《有赞透明多级缓存解决方案(TMC)》,里头也有提到热点key问题,我们刚好借此说明学习一下

1)、监控热点key

有赞用的是方式二:在客户端进行收集

在《有赞透明多级缓存解决方案(TMC)》中有一句话提到:

TMC 对原生jedis包的JedisPool和Jedis类做了改造,在JedisPool初始化过程中集成TMC“热点发现”+“本地缓存”功能Hermes-SDK包的初始化逻辑

有赞改写了jedis原生的jar包,加入了Hermes-SDK包。那Hermes-SDK包用来干嘛?答案是做热点发现和本地缓存。从监控的角度看,该包对于Jedis-Client的每次key值访问请求,Hermes-SDK 都会通过其通信模块将key访问事件异步上报给Hermes服务端集群,以便其根据上报数据进行“热点探测”

除了这种方式之外,有的公司在监控方面用的是方式五: 自己抓包分析

具体是这么做的,就是先利用flink搭建一套流式计算系统。然后自己写一个抓包程序抓redis监听端口的数据,抓到数据后往kafka里丢。接下来,流式计算系统消费kafka里的数据,进行数据统计即可,也能达到监控热key的目的。

2)、通知系统做处理

有赞用的是上面的解决方案一:使用二级缓存

有赞在监控到热key后,Hermes服务端集群会通过各种手段通知各业务系统里的Hermes-SDK,告诉他们:"老弟,这个key是热key,记得做本地缓存。"于是Hermes-SDK就会将该key缓存在本地,对于后面的请求。Hermes-SDK发现这个是一个热key,直接从本地中拿,而不会去访问集群。

除了这种通知方式以外。我们也可以这么做,比如你的流式计算系统监控到热key了,往zookeeper里头的某个节点里写。然后你的业务系统监听该节点,发现节点数据变化了,就代表发现热key。最后往本地缓存里写,也是可以的

总结

对于热点key问题,我们只需要两步处理:

1、监控热点key

2、通知系统做处理

猜你喜欢

转载自blog.csdn.net/ywlmsm1224811/article/details/102736986