一、问题
- 当前 key 是一个热点 key( 同一个key,同一个时候有几十万请求),并发量非常
- 重建缓存不能在短时间完成,可能是一个复杂计算,例如复杂的 SQL、多次 IO、多个依赖等。
二、影响
在缓存失效的瞬间,有大量线程来重建缓存 ( 如下图),造成后端负载加大,甚至可能会让应用崩溃。
三、解决这些问题要实现的目标
减少重建缓存的次数
数据尽可能一致
较少的潜在危险
四、方案
4.1 分布式锁
只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可
方案优缺点
- 建缓存过程出现问题或者时间较长,可能会存在死锁和线程池阻塞的风
- 能够较好的降低后端存储负载
- 能够较好的数据一致性
4.2 、让热键永远不过期
- 缓存层面:不要设置key过期时间,不会出现热点key过期后产生的问题
- 功能层面:要设置value过期时间,当发现value过期后,会使用单独的线程去构建缓存
方案优缺点
- 有效杜绝了热点 key 产生的问题
- 重构缓存期间,会出现数据不一致的情况,这取决于应用方是否容忍这种不一致。
- 同时代码复杂度会增大。(下面是代码逻辑)
- 通过key获取value
- 通过value获取timeOut
- timeOut过期(对比当前时间)
- 分布式锁
- 更新value值
五、两种方案对比