前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >缓存雪崩,缓存穿透,缓存击穿是什么?我们要怎么解决这些问题?

缓存雪崩,缓存穿透,缓存击穿是什么?我们要怎么解决这些问题?

作者头像
Java进阶之路
发布2022-11-18 15:23:52
5210
发布2022-11-18 15:23:52
举报
文章被收录于专栏:分布式与微服务

一 前言

在开发过程中,为了减轻数据库的压力,我们经常会使用到缓存,所以相信大家对缓存雪崩,缓存穿透,缓存击穿这三个名词并不陌生。今天就和大家一起分享一下,到底什么是缓存雪崩,缓存穿透,缓存击穿,我们要怎么做才能解决这些问题。

二:缓存雪崩

1.什么是缓存雪崩?

缓存雪崩是指在同一时间,大量缓存都失效,而恰巧这个时候,大量的请求同时进来,都去访问数据库,而数据库的连接数不够,从而导致用户端请求超时,响应慢,服务不可用等问题。

2.如何解决缓存雪崩问题?

①:在设置缓存的过期时间时,我们可以增加一个随机数。

代码语言:javascript
复制
   /**
     * 如果不需要特别准确的过期时间的话 就加一个随机时间 防止缓存雪崩
     *
     * @param baseTime  原过期时间
     * @param isPrecise 是否需要准确的设置过期时间 true 是 false 否
     * @return
     */
    public static long getExpireTime(long baseTime, boolean isPrecise) {
        if (isPrecise) {
            return baseTime;
        }
        ThreadLocalRandom random = ThreadLocalRandom.current();
        return baseTime + random.nextInt(10 * 60);
    }

如果我们的缓存不依赖一个准确的过期时间,那么我们利用ThreadLocalRandom生成一个随机数,这样的话可以避免一部分缓存雪崩的情况。

注:如果你还对ThreadLocalRandom不了解的话,建议看我的另一篇文章:并发高的情况下,试试用ThreadLocalRandom来生成随机数,相信会对你有所帮助。

② 使用多级缓存

我们可以使用多级缓存,从而减少缓存雪崩的概率。例如我们可以用Caffeine作为本地缓存(一级缓存),redis作为二级缓存,一级缓存中找不到,再去二级缓存中找。这样的话可以大大减少缓存雪崩的概率。

③ 热key不设置过期时间

如果一个key查询特别频繁,但是修改的频率特别低,那么可以考虑不设置key的过期时间。这样也是可以解决缓存雪崩的问题,但是我并不推荐这么做,原因有以下几点:

1.缓存与数据库数据的一致性一直是一个无法彻底解决的问题,如果我们的缓存不设置过期时间,那么意味着一旦出现数据不一致的问题,影响的时候会特别长。

2.缓存并不是数据持久化的地方,我们不应该把缓存当做数据库来用。

④ 在高并发来之前,做一次缓存预热

如果我们知道什么时间段并发会特别高,那么我们可以提前将数据在缓存一遍,并且重新设置好过期时间,这样就可以避免在高并发的情况下,而我们的缓存刚好大面积失效的问题。

缓存雪崩这个问题,恰巧我们在生产环境中遇到过,因为我们是直播教学系统,大部分直播都是在晚上8点开始,所以导致8点左右的时候请求量会突然变多很多。有一次发现数据库突然报警,但是发现数据库连接特别多,但是我们都是有加redis缓存的,经过排查,发现是缓存过期了。虽然数据库顶住了,但是还是很慌。后续我们也是采用了方法①,②,④来处理的。

三:缓存击穿

1.什么是缓存击穿?

缓存击穿是指,在某一个时刻,一个热key突然失效了,这时候恰巧有很多请求需要访问这个key,导致大量的请求访问到数据库,从而导致数据库压力过大,最后导致服务不可用。

2.如何解决缓存击穿问题?

① 热点key不设置过期时间

热点key不设置过期时间,可以很大程度上避免缓存击穿问题,但是还是那句话,我并不推荐这么做,原因在前文已经叙述,这么就不再过多赘述。

② 使用多级缓存

多级缓存不仅可以很大程度上避免缓存雪崩,也可以很大程度上解决缓存击穿的问题,所以其实多级缓存还是很有必要的,利用caffeine做一个本地缓存,redis做二级缓存,这样的话还可以减少redis的压力。

③ 使用锁机制

我们可以使用分布式锁来限制只有一个线程去访问数据库,这样我们就不用担心大量请求打到数据库,从而导致数据库压力过大的问题了。如果我们使用Spring cache的@Cacheable注解来实现缓存,那么就更简单了,只需要设置注解的sync属性为true就可以了。

代码语言:javascript
复制
@Cacheable(cacheNames= "cache",sync = true)
public User test(String name) {
  ...
  return user;
}

四:缓存穿透

1.什么是缓存穿透

缓存穿透是指用户端一直请求数据库中不存在的数据,而导致我们的缓存一直不生效,请求一直打到数据库,从而导致数据库压力过大,从而导致服务器不可用的问题。

2.缓存穿透的问题如何处理

① 针对业务,对一些参数进行校验

在查询缓存和数据库之前,可以根据我们的业务逻辑进行一些参数的校验,例如id 我们可以校验是否大于0,通常我们都会集成Validation注解做参数校验。这样可以避免一部分缓存穿透的问题。

② 如果数据库中查询结果为空,缓存一个空对象

如果数据库查询出来的结果是空的,如果是空集合,那么我们可以选择缓存一个空集合或者空对象到redis中,并设置一个较短的过期时间。但是如果遭到恶意的攻击,通常会导致我们缓存中都是一些无用缓存,而真正需要缓存的数据却被缓存淘汰策略所淘汰。

③ 建立黑名单,验证码等一系列安全机制,减少恶意请求

面对大量的恶意请求,我们应该建立一系列的安全措施,包括黑名单,验证码等等,这里就不做过多的举例了。

④ 使用布隆过滤器

使用布隆过滤器建立位图,通过布隆过滤器过滤掉大部分的不存在的数据。虽然布隆过滤器有一定的误判率,无法做到彻底拦截不存在的数据,但是也可以大大降低缓存穿透的概率了。

五 最后

今天和大家一起分析了缓存雪崩,缓存穿透,缓存击穿的问题,以及它们的一些解决方案。如果有什么疑问或者好的建议,欢迎在下方留言评论。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java进阶之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis®
腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档