超级面试题:如何优化缓存中百万级并发的KEY
: 不一定是2N,你想取4N,8N都可以,看要求。伪代码如下:
const M = N * 2
//生成随机数
random = GenRandom(0, M)
//构造备份新key
bakHotKey = hotKey + “_” + random
data = redis.GET(bakHotKey)
if data == NULL {
data = GetFromDB()
redis.SET(bakHotKey, expireTime + GenRandom(0,5))
}
说明:这种方案有一个很明显的缺点,就是缓存的维护代价非常大。假设有100个备份KEY,那么在删除或者更新时,也需要更新100个KEY,所以这种方案不是很推荐。
业内方案
OK,其实看完上面的内容,大家可能会有一个疑问。
有办法在项目运行过程中,自动发现热点key,然后程序自动处理么?
嗯,好问题,那我们来讲讲业内怎么做的。其实只有两步:
-
监控热点key
-
通知系统做处理
正巧,前几天有赞出了一篇《有赞透明多级缓存解决方案(TMC)》,里头也有提到热点key问题,我们刚好借此说明。
(1) 监控热点key
在监控热点key方面,有赞用的是方式二:在客户端进行收集。
在《有赞透明多级缓存解决方案(TMC)》中有一句话提到
TMC 对原生jedis包的JedisPool和Jedis类做了改造,在JedisPool初始化过程中集成TMC“热点发现”+“本地缓存”功能Hermes-SDK包的初始化逻辑。
也就说人家改写了jedis原生的jar包,加入了Hermes-SDK包。
那Hermes-SDK包用来干嘛?
OK,就是做 热点发现 和 本地缓存 。
从监控的角度看,该包对于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问题。
【阿飞的博客】 公众号二维码
↓↓↓↓