# 20 图 |6000 字 |实战缓存(上篇) (3)

缓存穿透指一个一定不存在的数据,由于缓存未命中这条数据,就会去查询数据库,数据库也没有这条数据,所以返回结果是 null。如果每次查询都走数据库,则缓存就失去了意义,就像穿透了缓存一样。

# 20 图 |6000 字 |实战缓存(上篇)

3.1.2 带来的风险

利用不存在的数据进行攻击,数据库压力增大,最终导致系统崩溃。

3.1.3 解决方案

对结果 null 进行缓存,并加入短暂的过期时间。

3.2 缓存雪崩

# 20 图 |6000 字 |实战缓存(上篇)

3.2.1 缓存雪崩的概念

缓存雪崩是指我们缓存多条数据时,采用了相同的过期时间,比如 00:00:00 过期,如果这个时刻缓存同时失效,而有大量请求进来了,因未缓存数据,所以都去查询数据库了,数据库压力增大,最终就会导致雪崩。

# 20 图 |6000 字 |实战缓存(上篇)

3.2.2 带来的风险

尝试找到大量 key 同时过期的时间,在某时刻进行大量攻击,数据库压力增大,最终导致系统崩溃。

3.2.3 解决方案

在原有的实效时间基础上增加一个碎挤汁,比如 1-5 分钟随机,降低缓存的过期时间的重复率,避免发生缓存集体实效。

3.3 缓存击穿 3.3.1 缓存击穿的概念

某个 key 设置了过期时间,但在正好失效的时候,有大量请求进来了,导致请求都到数据库查询了。

# 20 图 |6000 字 |实战缓存(上篇)

3.3.2 解决方案

大量并发时,只让一个请求可以获取到查询数据库的锁,其他请求需要等待,查到以后释放锁,其他请求获取到锁后,先查缓存,缓存中有数据,就不用查数据库。

四、加锁解决缓存击穿

怎么处理缓存穿透、雪崩、击穿的问题呢?

对空结果进行缓存,用来解决缓存穿透问题。

设置过期时间,且加上随机值进行过期偏移,用来解决缓存雪崩问题。

加锁,解决缓存击穿问题。另外需要注意,加锁对性能会带来影响。

这里我们来看下用代码演示如何解决缓存击穿问题。

我们需要用 synchronized 来进行加锁。当然这是本地锁的方式,分布式锁我们会在下篇讲到。

public List<TypeEntity> getTypeEntityListByLock() { synchronized (this) { // 1.从缓存中查询数据 String typeEntityListCache = stringRedisTemplate.opsForValue().get("typeEntityList"); if (!StringUtils.isEmpty(typeEntityListCache)) { // 2.如果缓存中有数据,则从缓存中拿出来,并反序列化为实例对象,并返回结果 List<TypeEntity> typeEntityList = JSON.parseObject(typeEntityListCache, new TypeReference<List<TypeEntity>>(){}); return typeEntityList; } // 3.如果缓存中没有数据,从数据库中查询数据 System.out.println("The cache is empty"); List<TypeEntity> typeEntityListFromDb = this.list(); // 4.将从数据库中查询出的数据序列化 JSON 字符串 typeEntityListCache = JSON.toJSONString(typeEntityListFromDb); // 5.将序列化后的数据存入缓存中,并返回数据库查询结果 stringRedisTemplate.opsForValue().set("typeEntityList", typeEntityListCache, 1, TimeUnit.DAYS); return typeEntityListFromDb; } }

1.从缓存中查询数据。

2.如果缓存中有数据,则从缓存中拿出来,并反序列化为实例对象,并返回结果。

3.如果缓存中没有数据,从数据库中查询数据。

4.将从数据库中查询出的数据序列化 JSON 字符串。

5.将序列化后的数据存入缓存中,并返回数据库查询结果。

五、本地锁的问题

本地锁只能锁定当前服务的线程,如下图所示,部署了多个题目微服务,每个微服务用本地锁进行加锁。

# 20 图 |6000 字 |实战缓存(上篇)

本地锁在一般情况下没什么问题,但是当用来锁库存就有问题了:

1.当前总库存为 100,被缓存在 Redis 中。

2.库存微服务 A 用本地锁扣减库存 1 之后,总库存为 99。

3.库存微服务 B 用本地锁扣减库存 1 之后,总库存为 99。

4.那库存扣减了 2 次后,还是 99,就超卖了 1 个。

那如何解决本地加锁的问题呢?

缓存实战(中篇):实战分布式锁。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwpzf.html