目录
读缓存时可能遇到的问题
老生常谈的话题了,我这里写不是为了别的,也没有什么独特的见解(也许以后会有),我只是想总结下,整理下这部分的实践点,知识点,便于以后遇到此类问题,有个方便查看的解决方案。所以该文章会详细,全面的分析三读缓存的问题,并在下篇文章会详细分析写缓存的问题。
一、缓存穿透:
1、问题出现场景
什么情况下会出现缓存穿透呢?其实很多文章都会先说一下,嗯不例外我也会描述。哈哈哈!!!
缓存穿透是指查询一个一定不存在的数据,因为在缓存中也无该数据的信息,则系统会跳过缓存直接访问数据库,而对于高并发,高吞吐量的系统来说,无疑缓存失效了,同时对数据库上了一个高负载的debuff,显而易见的是数据库的读效率是比不过缓存的,那么很有可能造成数据库崩溃从而影响系统发生故障。当然,一般情况下,数据库的架构一般会搭建HA数据库,怕的就是恶意攻击。
2、解决方案
①、布隆过滤器(Bloom Filter)
②、空值缓存
3、解决方案详细实践
①、BloomFilter
- 实现原理:假设有10条url,我们可以创建一个100bit位的数组,将URL分别用5个hash算法进行hash,将得到的5个hash值存入数组,如果我们需要判断url是否已经存在,则可通过一次判断url这5此hash算法的hash值是否为1,如果都为一,则说明url已存在,反之如果有任何一个不为1,那么说明这个url不存在。但是当数据量大到一定程度,会存在url的5次hash结果都为1,但其实该url不存在的场景。
- 算法核心思想:
- 使用多个hash算法,从而减少hash的碰撞率,此处可以借鉴HashMap的hash算法;
- 扩大数组范围,使hash值分布均匀,减少hash碰撞率。
②、空值缓存:
一种比较简单的解决办法,在第一次查询完不存在的数据后,将该key与对应的空值也放入缓存中,只不过设定为较短的失效时间,例如几分钟,这样则可以应对短时间的大量的该key攻击,设置为较短的失效时间是因为该值可能业务无关,存在意义不大,且该次的查询也未必是攻击者发起,无过久存储的必要,故可以早点失效。
二、缓存雪崩:
1、问题出现场景
在普通的缓存系统中一般例如redis、memcache等中,我们会给缓存设置一个失效时间,但是如果所有的缓存的失效时间相同,那么在同一时间失效时,所有系统的请求都会发送到数据库层,数据库可能无法承受如此大的压力导致系统崩溃。
2、解决方案
解决问题的方法,就是针对问题所在给出合理方案,雪崩的问题在于缓存失效的时间段,大量的并发对持久层造成了严重负载,导致系统崩溃,那么针对缓存失效,可以给出以下一些方案:
- 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
- 可以通过缓存reload机制,预先去更新缓存,在即将发生大并发访问前手动触发加载缓存。
- 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
- 做二级缓存,或者双缓存策略。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。
三、缓存击穿:
1、问题出现场景
缓存击穿实际上是缓存雪崩的一个特例,大家使用过微博的应该都知道,微博有一个热门话题的功能,用户对于热门话题的搜索量往往在一些时刻会大大的高于其他话题,这种我们成为系统的“热点“,由于系统中对这些热点的数据缓存也存在失效时间,在热点的缓存到达失效时间时,此时可能依然会有大量的请求到达系统,没有了缓存层的保护,这些请求同样的会到达数据库从而可能引起故障。击穿与雪崩的区别即在于击穿是对于特定的热点数据来说,而雪崩是全部数据。
2、解决方案