目录
缓存击穿
未加锁的情况
首页 数据库 Redis Redis分布式锁如何防止缓存击穿

Redis分布式锁如何防止缓存击穿

Jun 03, 2023 pm 07:04 PM
redis

缓存击穿

和缓存穿透不同的是,缓存击穿是指:缓存中没有,但是数据库中存在的热点数据。

例如:首页的热点新闻,并发访问量非常大的热点数据,如果缓存过期失效,服务器会去查询DB,这时候如果大量的并发去查询DB,可能会瞬间压垮DB。

画了个简图,如下所示:

Redis分布式锁如何防止缓存击穿

解决方案:DB查询加分布式锁

未加锁的情况

解决问题之前,先看一下不做处理的代码和运行情况。

根据商品ID查询商品详情代码

Redis分布式锁如何防止缓存击穿

清空Redis缓存,开启5个线程去并发访问测试,测试代码如下:

Redis分布式锁如何防止缓存击穿


我们预期希望DB只查询一次,后面4个查询从Redis缓存中取就行,但是结果:
Redis分布式锁如何防止缓存击穿
没有加分布式锁,结果也在意料之中,但是这样容器给DB造成很大压力。

如果是单台服务器,直接使用Java的同步锁即可

Redis分布式锁如何防止缓存击穿

遗憾的是,通常后端是会部署集群的,Java的同步锁可没办法实现分布式锁。

Redis分布式锁解决缓存击穿

Java的内置锁只能应用在单台机器上,无法实现分布式,可以巧用Redis来实现分布式锁

加了分布式锁后的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

//根据ID查询商品

@GetMapping("/{id}")

public R id(@PathVariable String id){

    //先查Redis缓存

    Object o = redisTemplate.opsForValue().get(id);

    if (o != null) {

        //命中缓存

        System.err.println("id:"+id+",命中redis缓存...");

        return R.success(o);

    }

 

    //缓存未命中 查询数据库

    String lockKey = "lock" + id;

    //加锁,10s后过期

    for (;;) {

        if (redisTemplate.opsForValue().setIfAbsent(lockKey, System.currentTimeMillis(), 10L, TimeUnit.SECONDS)) {

            //加锁成功的线程,再次检查

            o = redisTemplate.opsForValue().get(id);

            if (o != null) {

                //命中缓存

                System.err.println("Thread:" + Thread.currentThread().getName() + ",id:"+id+",命中redis缓存...");

                //释放锁

                redisTemplate.delete(lockKey);

                return R.success(o);

            }

 

            //仍未命中

            System.err.println("Thread:" + Thread.currentThread().getName() + ",id:" + id + ",查询DB...");

            Goods goods = goodsMapper.selectById(id);

            //结果存入Redis

            redisTemplate.opsForValue().set(id, goods);

            //释放锁

            redisTemplate.delete(lockKey);

            return R.success(goods);

        }

        //竞争不到锁,暂时让出CPU资源

        Thread.yield();

    }

}

登录后复制

启动5个线程,并发访问,结果如下图:

Redis分布式锁如何防止缓存击穿

以上是Redis分布式锁如何防止缓存击穿的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门文章

仓库:如何复兴队友
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 周前 By 尊渡假赌尊渡假赌尊渡假赌

热门文章

仓库:如何复兴队友
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 周前 By 尊渡假赌尊渡假赌尊渡假赌

热门文章标签

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Windows11安装10.0.22000.100跳出0x80242008错误解决办法 Windows11安装10.0.22000.100跳出0x80242008错误解决办法 May 08, 2024 pm 03:50 PM

Windows11安装10.0.22000.100跳出0x80242008错误解决办法

redis如何修改密码 redis如何修改密码 Apr 20, 2024 am 03:00 AM

redis如何修改密码

剖析 PHP 函数瓶颈,提升执行效率 剖析 PHP 函数瓶颈,提升执行效率 Apr 23, 2024 pm 03:42 PM

剖析 PHP 函数瓶颈,提升执行效率

redis是内存缓存吗 redis是内存缓存吗 Apr 20, 2024 am 05:26 AM

redis是内存缓存吗

Golang API缓存策略与优化 Golang API缓存策略与优化 May 07, 2024 pm 02:12 PM

Golang API缓存策略与优化

redis是非关系型数据库吗 redis是非关系型数据库吗 Apr 20, 2024 am 05:36 AM

redis是非关系型数据库吗

PHP开发中的缓存机制与应用实战 PHP开发中的缓存机制与应用实战 May 09, 2024 pm 01:30 PM

PHP开发中的缓存机制与应用实战

erlang和golang性能哪个好? erlang和golang性能哪个好? Apr 21, 2024 am 03:24 AM

erlang和golang性能哪个好?

See all articles