概述
什么是热key?
当一个key的访问量明显大于其他key的时候,他就可以被称为热key。
什么情况下产生热点Key问题?
比如瞬间有几十万的请求去访问redis上某个固定的key。
这种情况其实在日常工作生活中是常见的事件,例如:热门商品降价促销、热点新闻、热点评论、明星直播等,这些典型的读多写少的场景就会产生热点问题。
热Key问题
假如突然有几十万的请求去访问redis上的某个特定key。那么,这样会造成流量过于集中,达到物理网卡上限,从而导致这台redis的服务器宕机。
那接下来这个key的请求,就会直接怼到你的数据库上,导致你的服务不可用。
发现热Key
- 凭借业务经验,进行预估哪些是热key
其实这个方法还是挺有可行性的。比如某商品在做秒杀,那这个商品的key就可以判断出是热key。缺点很明显,并非所有业务都能预估出哪些key是热key。 - 在客户端进行收集
这个方式就是在操作redis之前,加入一行代码进行数据统计。那么这个数据统计的方式有很多种,也可以是给外部的通讯系统发送一个通知信息。缺点就是对客户端代码造成入侵。有赞的就是采用对原生jedis包的JedisPool和Jedis类做了改造,在JedisPool初始化过程中集成TMC“热点发现”+“本地缓存”功能从而实现热key发现和治理。 - 自己抓包评估
自己写程序监听redis端口,按照RESP协议规则解析数据,进行分析。缺点就是开发成本高,维护困难,有丢包可能性。 - 业务埋点分析
通过业务埋点日志进行统计分析,找出高频接口和热点参数,再结合业务分析出热key
解决方案
- 利用二级缓存
比如利用ehcache,或者一个HashMap都可以。在你发现热key以后,把热key加载到系统的JVM中。针对这种热key请求,会直接从jvm中取,而不会走到redis层。缺点就是需要考虑缓存一致性问题。常见框架:J2cache - 备份热key
采用redis集群模式,将同一份热key在集群中备份多份,具体实现可以采用固定前缀+随机数的方式将热key分散到集群中的多个节点,从而分散请求量
//伪代码示例
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))
}