缓存雪崩
如果缓存在一段时间内失效,就会出现大量的缓存穿透,所有的查询都会落到数据库上,造成缓存雪崩。
缓存雪崩如何解决
- 如果缓存经常在某个时间消失,就要考虑key的过期时间是否相同。可以随机检查过期时间,避免缓存过期时间一起失效。
- 取缓存时加锁,可以保证绝大部分数据不会被请求到缓存,但是并发是有限制的。
- 我们仍然需要确保缓存系统不会崩溃。比如你用redis,你可以让它高可用。可以使用master-slave+sentinel,RedisCluster来避免Rediscrash的情况。
- 如果你的系统可能第一次流量很大,可以考虑数据预热,即系统上线后,直接将相关缓存数据加载到缓存系统
缓存穿透
缓存穿透是指查询一定不存在的数据。由于缓存在未命中时是被动写入的,并且出于容错的考虑,如果从存储层找不到数据,则不会写入缓存。这样就会导致这种不存在的数据每次请求都得去存储层查询,就失去了缓存的意义。流量大的时候,DB可能会挂掉。如果有人使用不存在的密钥频繁攻击我们的应用程序,这就是一个漏洞。
如何解决缓存穿透
- 缓存空值,如果查询返回的数据为空(无论数据不存在还是系统故障),我们仍然缓存空结果,但是它的过期时间时间会很短。更好的是,让空结果为我们检查数据库。
- 使用BloomfilterBloomFilter,优点是占用内存空间小,按位存储;性能特别高,利用key的hash判断key是否存在,将所有可能的数据hash到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截,从而避免查询压力在底层存储系统上。在缓存之前加了一层BloomFilter,查询的时候先去BloomFilter中检查key是否存在,不存在则直接返回,如果存在则查询缓存,再查询如果数据库不在缓存中。< titlesplit >
缓存崩溃
在高并发的系统中,当大量请求同时查询一个key时,此时key恰好失效,会导致大量请求被发送到数据库。我们称这种现象为缓存崩溃。
如何解决缓存崩溃
- 添加互斥锁,redis类似
publicStringget(key){ 字符串值=redis.得到(钥匙); if(value==null){//表示缓存值已经过期 //设置超时时间3分钟,防止下次del操作失败时缓存过期无法加载db if(redis.setnx(key_mutex,1,3*60)==1){//表示设置成功 值=分贝。得到(钥匙); redis.set(key,value,expire_secs); redis.del(key_mutex); }else{//此时说明其他线程同时加载了db并设置回缓存。此时重试获取缓存值 睡觉(50); 得到(钥匙);//重试 } }别的{ 返回值; } }♬如何保证缓存和数据库双写一致
缓存和数据库是分开更新的,我们没办法保证这两者一直一致。但是我们可以追求最终一致性。现在常见的策略是不更新缓存。我们先删除缓存,再更新数据库。可能会发生的情况是在删除缓存和更新数据库之间存在数据读取缓存。这时候可以使用延迟双删。