概述
如今许多互联网应用系统都重度依赖缓存来提高读操作的性能,对于这些系统来说如何正确地使用缓存至关重要。本文从缓存读取这个视角来讨论缓存架构设计上的一些思路。重点关注如何防止缓存雪崩。
1. 缓存读操作
引入缓存后,读数据的流程如下:
- (1)先读缓存,如果缓存中有数据(hit),则返回缓存中的结果;
- (2)如果缓存中没有数据(miss),则回源到database获取,然后把结果写入缓存再返回。
2. 缓存雪崩
在正常情况下,一旦miss就去查DB是没有问题的。但是如果大量缓存集中在某一时间段失效,将导致所有请求都去访问后端的DB,DB压力会很大,甚至被压垮,造成雪崩。
- 场景一
电商系统的某个大促活动的首页,首页有很多新上架的商品。活动开始前,技术团队对缓存做了预热,由于是脚本化预热,这些商品的Cache数据几乎都是同时创建好,并且过期时间都设置为5分钟。这就会导致这大量的商品数据在5分钟后集中失效。
- 场景二
cache系统刚上线(或者刚从崩溃中恢复过来),没有对cache进行预热。cache中什么也没有,这时瞬时大流量过来也会产生雪崩。
3. 解决思路
3.1 cache过期时间均匀分布
针对上面的场景一,可以对cache的过期时间做一个均匀分布的处理。比如1-5分钟内,随机分布。
3.2 排斥锁
针对场景二,可以考虑使用排斥锁(mutex)。即第一个线程过来读取cache,发现没有,就去访问DB。后续线程再过来就需要等待第一个线程读取DB成功,cache里的value变得可用,后续线程返回新的value。伪代码如下:
public Object getCache