缓存雪崩
缓存雪崩:缓存在某一个时间点突然失效了;示例:以redis作为缓存,redis突然挂掉,即表示缓存雪崩;缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
解决办法:
-
事前:使用集群缓存,保证缓存服务的高可用 这种方案就是在发生雪崩前对缓存集群实现高可用,如果是使用 Redis,可以使用 主从 + 哨兵 ,Redis Cluster 来避免 Redis 全盘崩溃的情况。
-
事中:使用 ehcache 本地缓存 + Hystrix 限流 & 降级,避免 MySQL 被打死的情况发生。 使用 ehcache 本地缓存的目的也是考虑在 Redis Cluster 完全不可用的时候,ehcache 本地缓存还能够支撑一阵。
使用 Hystrix 进行 限流 & 降级 ,比如一秒来了 5000 个请求,我们可以设置假设只能有一秒 2000 个请求能通过这个组件,那么其他剩余的 3000 请求就会走限流逻辑,然后去调用我们自己开发的降级组件(降级)。比如设置的一些默认值呀之类的。以此来保护最后的 MySQL 不会被大量的请求给打死。
- 事后:开启 Redis 持久化机制,尽快恢复缓存集群 一旦重启,就能从磁盘上自动加载数据恢复内存中的数据。
缓存穿透
缓存穿透:一个时间点大量请求应用,但是这些请求无法命中缓存,这些请求立马冲向数据库;也称之为缓存击穿。
缓存穿透解决方案
1、 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
布隆过滤器:
- 一个很长的二进制向量 (位数组)
- 一系列随机函数 (哈希)
- 空间效率和查询效率高
- 不会漏判,但是有一定的误判率(哈希表是精确匹配)
以上图为例,具体的操作流程:假设集合里面有3个元素{x, y, z},哈希函数的个数为3。首先将位数组进行初始化,将里面每个位都设置位0。对于集合里面的每一个元素,将元素依次通过3个哈希函数进行映射,每次映射都会产生一个哈希值,这个值对应位数组上面的一个点,然后将位数组对应的位置标记为1。查询W元素是否存在集合中的时候,同样的方法将W通过哈希映射到位数组上的3个点。如果3个点的其中有一个点不为1,则可以判断该元素一定不存在集合中。反之,如果3个点都为1,则该元素可能存在集合中。注意:此处不能判断该元素是否一定存在集合中,可能存在一定的误判率。可以从图中可以看到:假设某个元素通过映射对应下标为4,5,6这3个点。虽然这3个点都为1,但是很明显这3个点是不同元素经过哈希得到的位置,因此这种情况说明元素虽然不在集合中,也可能对应的都是1,这是误判率存在的原因。
2、 如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴!
参考文章