1
为什么需要缓存
如果没有缓存,那么所有业务请求会直接指向数据库,以MySQL为例的数据库基本都是基于磁盘的,而磁盘I/O开销大,面对大规模请求时,会降低系统性能。
对一些热点数据,将其从数据库中抽离出来放进缓存,每次查询时先走缓存,缓存命中则直接返回结果,能提高效率。
2
缓存带来的问题
有三个经典问题:
缓存击穿:缓存中热点key突然失效,原本走缓存的大量请求直接打向了数据库,就好像在缓存中击穿了一个洞。
3
应对方案
这里主要介绍缓存穿透的解决方案,先看两幅原理图。
用户发出请求后先查缓存,缓存命中则直接返回;
缓存不命中就查数据库,查到后将数据写入缓存并返回给用户。
此时缓存基本失去了作用。
常见的解决思路:
将用户请求的不存在的数据也放进缓存,并将值置为null,这样请求走缓存的时候发现结果为null,直接返回即可。
但是需要给缓存中的key设置一个合适的过期时间,否则数据库中有了这样的数据,就会出现数据不一致问题。
更好的解决思路:
使用布隆过滤器(Bloom Filter)。
在上篇文章 如何在海量数据中判断某个数据是否存在? 我们介绍了布隆过滤器,它可用于快速判断数据是否存在于某个集合中,借助这个功能,我们可用它来应对缓存穿透。
回顾一下布隆过滤器的两条重要特性:
1.布隆过滤器判定数据存在,那么它可能存在也可能不存在。
2.布隆过滤器判定数据不存在,那么它一定不存在。
用户请求数据,若Bloom Filter返回false,则直接过滤该请求或返回null;若Bloom Filter返回true,则查缓存,缓存命中则返回,不命中则查数据库。
Bloom Filter就好像是加在缓存前的一道屏障,过滤了几乎所有不符合要求的请求。虽然有一定的误判率,即可能有少数通过了Bloom Filter的请求在数据库和缓存中也还是不命中,但相比之下,整个系统性能已经大大提升,且Bloom Filter的默认误判率只有0.03.
顺带提一下缓存击穿和缓存雪崩的解决方案。
缓存击穿:
在被查询的数据上加互斥锁,一条请求线程拿到锁后其它线程只能等待。
缓存雪崩:
事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。
事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉。
事后:利用 redis 持久化机制保存的数据尽快恢复缓存。
参考自中华石彬老师