搜索
写经验 领红包
 > 自然

怎样应对缓存穿透问题(如何解决缓存穿透)

导语:怎样应对缓存穿透?

1为什么需要缓存

如果没有缓存,那么所有业务请求会直接指向数据库,以MySQL为例的数据库基本都是基于磁盘的,而磁盘I/O开销大,面对大规模请求时,会降低系统性能。对一些热点数据,将其从数据库中抽离出来放进缓存,每次查询时先走缓存,缓存命中则直接返回结果,能提高效率。

2缓存带来的问题

有三个经典问题:

缓存雪崩:指缓存大面积失效,导致大量查询落到了数据库上,使数据库挂掉。缓存击穿:缓存中热点key突然失效,原本走缓存的大量请求直接打向了数据库,就好像在缓存中击穿了一个洞。缓存穿透:用户一直请求缓存和数据库都不存在的数据,每次请求缓存不命中,数据库也不命中,就像缓存不存在一样,同时不断地请求也给数据库带来压力。

3应对方案

这里主要介绍 缓存穿透 的解决方案,先看两幅原理图。

用户请求大致原理图:

用户发出请求后先查缓存,缓存命中则直接返回;

缓存不命中就查数据库,查到后将数据写入缓存并返回给用户。

用户请求缓存和数据库都没有的数据(即缓存穿透,如请求id=-1的数据):

此时缓存基本失去了作用。

常见的解决思路:

将用户请求的不存在的数据也放进缓存,并将值置为null,这样请求走缓存的时候发现结果为null,直接返回即可。

但是需要给缓存中的key设置一个合适的过期时间,否则数据库中有了这样的数据,就会出现 数据不一致 问题。

更好的解决思路:

使用 布隆过滤器(Bloom Filter) 。 它可用于快速判断数据是否存在于某个集合中,借助这个功能,我们可用它来应对缓存穿透。

回顾一下布隆过滤器的两条重要特性:

1. 布隆过滤器判定数据存在,那么它可能存在也可能不存在。

2. 布隆过滤器判定数据不存在,那么它一定不存在。

加上布隆过滤器之后:

用户请求数据,若Bloom Filter返回false,则直接过滤该请求或返回null;若 Bloom Filter 返回true,则查缓存,缓存命中则返回,不命中则查数据库。

Bloom Filter 就好像是加在缓存前的一道 屏障 ,过滤了几乎所有不符合要求的请求。虽然有一定的误判率,即可能有少数通过了 Blo om Filter 的请求在数据库和缓存中也还是不命中,但相比之下,整个系统性能已经大大提升,且 Blo om Filter 的默认误判率只有0.03.

顺带提一下缓存击穿和缓存雪崩的解决方案。

缓存击穿:

在被查询的数据上加互斥锁,一条请求线程拿到锁后其它线程只能等待。

缓存雪崩:

事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。

事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉。

事后:利用 redis 持久化机制保存的数据尽快恢复缓存。

本文内容由小馨整理编辑!