缓存击穿只会逻辑过期 OR 互斥锁?深入思考 == 鹤立鸡群

        网上但凡看得见的文章,大部分在说缓存穿透时都是无脑分布式锁 / 逻辑过期,分布式锁一点问题都没有么?逻辑过期一点问题都没有么?还能不能再进一步优化?

        在聊聊缓存击穿的双重判定锁之前,我们将按照循循渐进的方式讲解,什么是缓存击穿?常规解决方案的弊端是啥?缓存击穿解决方案能不能进一步优化?

什么是缓存击穿?

        缓存击穿是指一个缓存中的数据因为某种原因(通常是缓存中的数据过期或者被删除),在短时间内遭受大量的请求,导致这些请求直接穿透到数据库或其他后端存储系统,增加了后端系统的负载。

缓存击穿通常在以下情况下发生:

  1. 热点数据过期:当缓存中存储的热门数据过期时,大量的请求会同时查询后端数据库。
  2. 第一次请求:对于一个之前从未被请求过的数据,当它第一次被请求时,缓存中没有这个数据,从而导致请求穿透到后端存储。

image.png

常规解决方案的弊端

为了解决Redis缓存击穿问题,八股文都是直接采取以下方案:

  1. 设置热点数据永不过期:对于一些热点数据,可以将其永不过期,确保即使数据过期后,仍然可以从缓存中获取。
  2. 使用互斥锁:在获取数据时,使用分布式锁(如 Redis 的分布式锁)来控制同时只有一个请求可以去后端获取数据,其他请求需要等待锁释放。这样可以防止多个请求同时穿透到后端存储。

思考一

        设置热点数据永不过期属于是业务范围应该考虑的事情,这个数据是否应该永不过期?或者说活动时设置过期时间为 -1,活动后再执行程序删除。有一点可以确认,缓存数据不可能全部都是永不过期,因为缓存的存储压力会比较大,所以该方案无法作为通用方案。

那我们可以从互斥锁上面下下文章,如何通过互斥锁完成缓存击穿场景解决方案?

思考二

        在获取数据时,使用分布式锁(如 Redis 的分布式锁)来控制同时只有一个请求可以去后端获取数据,其他请求需要等待锁释放。这样可以防止多个请求同时穿透到后端存储。

image.png

伪代码如下:

public String selectTrain(String id) {
	String cacheData = cache.get(id);
	if (StrUtil.isBlank(cacheData)) {
        Lock lock = getLock(id);
        lock.lock();
        try {
            String dbData = trainMapper.selectId(id);
            if (StrUtil.isNotBlank(dbData)) {
        		cahce.set(id, dbData);
                cacheData = dbData;
            }
        } finally {
            lock.unlock();
        }
    }
	return cacheData;
}

        这种方案有效地避免了缓存穿透问题,因为只有一个线程能够在同一时间内查询数据库,其他线程需要等待,不会同时穿透到后端存储系统。但是!!!其实上面的方案还是有个小细节滴~~

双重判定锁

        上边还有一个问题就是,假如 100w 的请求读取一个缓存,100w 的请求全部卡在 lock.lock 获取分布式锁处,只有一个线程会执行逻辑请求数据库并放入缓存。问题来了,因为接下来的所有请求,99.99...w 还是会继续请求数据库,大家读一下上面的伪代码就明白了。(其实就是因为99.99...个请求都阻塞在Lock lock = getLock(id)这一步,而不是if (StrUtil.isBlank(cacheData))这一步。

这会造成两个实际的问题:

  1. 全部用户获取锁后查询数据库,会对数据库造成无用的性能浪费,因为这 100w 的请求,只有第一次是有效的。
  2. 查询数据库会造成用户响应时间变长,接口吞吐量下降。

双重判断:获取锁后,在查询数据库之前,再次检查一下缓存中是否存在数据。这是一个双重判断,如果缓存中存在数据,就直接返回;如果不存在,才继续执行查询数据库的操作。

image.png

伪代码如下:

public String selectTrain(String id) {
	String cacheData = cache.get(id);
	if (StrUtil.isBlank(cacheData)) {
        Lock lock = getLock(id);
        lock.lock();
        try {
            cacheData = cache.get(id);
            if (StrUtil.isBlank(cacheData)) {
                String dbData = trainMapper.selectId(id);
                if (StrUtil.isNotBlank(dbData)) {
            		cahce.set(id, dbData);
                    cacheData = dbData;
                }
            }
        } finally {
            lock.unlock();
        }
    }
	return cacheData;
}

下面是这种解决方案的一般步骤:

  1. 获取锁:在查询数据库前,首先尝试获取一个分布式锁。只有一个线程能够成功获取锁,其他线程需要等待。
  2. 查询数据库:如果双重判断确认数据确实不存在于缓存中,那么就执行查询数据库的操作,获取数据。
  3. 写入缓存:获取到数据后,将数据写入缓存,并设置一个合适的过期时间,以防止缓存永远不会被更新。
  4. 释放锁:最后,释放获取的锁,以便其他线程可以继续使用这个锁。

文末总结

        本文深入探讨了缓存击穿问题以及解决方案。首先,我们了解了缓存击穿是指一个缓存中的数据因为某种原因(通常是缓存中的数据过期或者被删除),在短时间内遭受大量的请求,从而直接查询数据库,对系统性能造成了巨大的压力。然后,我们介绍了解决缓存击穿问题的一种有效方式——分布式互斥锁,以及分布式互斥锁的升级版本——双重判定锁。

总结一下:

  • 缓存击穿问题是指某些请求查询缓存中不存在的数据,导致大量请求直接穿透到后端数据库,对系统性能造成严重影响。
  • 分布式互斥锁是一种解决缓存击穿的有效方式。它通过在查询缓存之前尝试获取锁,只有一个线程能够成功获取锁,其他线程需要等待。这确保了只有一个线程可以查询数据库,避免了大规模的穿透。
  • 双重判定锁是分布式互斥锁的升级版本。它在获取锁后,再次检查缓存中是否存在数据,以避免重复查询数据库。只有在确认缓存中不存在数据时,才继续查询数据库。

        这两种解决方案都能够有效地应对缓存击穿问题,但需要根据实际情况选择合适的方式。分布式互斥锁适用于大多数场景,而双重判定锁则提供了更高的效率,适用于一些特定的场景。选择合适的解决方案,可以保护系统免受缓存击穿问题的困扰,提高性能和可靠性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/111722.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

双十一首日捷报 | 德施曼率先破亿,再度蝉联智能锁品类第一

10月31日晚8:00,各大平台迎来了双十一第一波现货开售。其中,在智能锁类目中德施曼势头最为迅猛,此前,德施曼凭借“全民换锁季”主题活动,在预售期间就已经全面引爆消费者换锁热潮,随着此次现货开售&#xf…

cut 命令

cut [选项参数] filename #默认分隔符是制表符 选项参数: -d delimiter 分隔符 -f field 场地、领域(第几列) 命令使用: cut -d " " -f 1 cut.txt #空格为分隔符截取第1列cut -d " " -f 2,3 cut.txt #截…

百度上传自己个人简介攻略,个人介绍百度百科怎么做?

个人介绍要展示在百度百科上该怎么操作,我们都清楚百度百科词条是需要申请才能拥有的,但是没有百度上传自己个人简介的攻略,很多人是不知从何下手的。下面洛希爱做百科网带着大家一起来了解。 一、了解百度百科词条的创建规则 1. 词条名称规…

jdk官网下载(详细步骤)

jdk全部版本下载网址 Java Archive | Oraclehttps://www.oracle.com/java/technologies/downloads/archive/ 下载之前先建立oracle账号(免费创建),不用特意去搜,你点击下载jdk的时候会自动弹出来,自己建立一个账号就能下载了 找到自己要下载…

【产品体验】OA办公系统

一、演示地址 http://admin.dianshixinxi.com:90/index 二、办公管理功能 1.我的待办:当前登录用户,办理任务 2.通知公告:通知与公告,已发布通知公告会显示在首页 3.自定义表单:自定义表单,托拉拽的形式…

iZotope RX 10(音频修复和增强工具)

iZotope RX 10是一款音频修复和增强软件,主要特点包括: 声音修复:iZotope RX 10可以去除不良噪音、杂音、吱吱声等,使音频变得更加清晰干净。音频增强:iZotope RX 10支持对音频进行音量调节、均衡器、压缩器、限制器等…

IDEA 使用技巧

文章目录 语言支持简化编写 有问题,可暂时跳过 个人常用快捷键插件主题插件功能插件 碰到过的问题 除了一些在Linux上用vim开发的大佬,idea算是很友好的集成开发工具了,功能全面,使用也很广泛。 记录一下我的 IDEA 使用技巧&#…

解密人工智能:KNN | K-均值 | 降维算法 | 梯度Boosting算法 | AdaBoosting算法

文章目录 一、机器学习算法简介1.1 机器学习算法包含的两个步骤1.2 机器学习算法的分类 二、KNN三、K-均值四、降维算法五、梯度Boosting算法和AdaBoosting算法六、结语 一、机器学习算法简介 机器学习算法是一种基于数据和经验的算法,通过对大量数据的学习和分析&…

虹科示波器 | 汽车免拆检修 | 2013款大众途观车发动机加速无力

一、故障现象 一辆2013款大众途观车,搭载CGM发动机,累计行驶里程约为12.6万km。车主进厂反映,发动机加速无力。 二、故障诊断 接车后试车,发动机怠速运转正常;原地将加速踏板踩到底,发动机转速最高只能达到…

AQS面试题总结

一:线程等待唤醒的实现方法 二: 介绍一下LockSupport 三:AQS是什么 AQS使用一个volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列完成资源获取排队工作,将每条要去抢占资源的线程封装成一个NODE节点来…

抛开八股——实际业务下如何设计缓存与数据库一致性解决方案

前言 对于缓存与数据库一致性的八股文也是老生常谈了,但是所谓没有最好的方案,只有最合适的方案,如果我们一味的去硬啃八股文,很容易就丧失了对于业务的基本分析能力,更别说针对业务来设计出合理合适的解决方案&#x…

Flutter笔记:完全基于Flutter绘图技术绘制一个精美的Dash图标(下)

Flutter笔记 完全基于Flutter绘图技术绘制一个精美的Dart吉祥物Dash 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/arti…

2015年亚太杯APMCM数学建模大赛A题海上丝绸之路发展战略的影响求解全过程文档及程序

2015年亚太杯APMCM数学建模大赛 A题 海上丝绸之路发展战略的影响 原题再现 一带一路不是实体或机制,而是合作与发展的理念和主张。凭借现有有效的区域合作平台,依托中国与有关国家现有的双边和多边机制,利用古丝绸之路的历史象征&#xff0…

如何看待将本增效?

如何看待将本增效? 么是降本增效?就是公司里,增进收益的动作要多做,无效的动作要少做,甚至不做。什么叫有效?回到公司的经营目标上去,企业的管理就是目标管理。降本,需要卓越运营&a…

reese84

网址:https://beta.makeabooking.flyscoot.com/ 这个基本上会在航空网站上出现,国内的我也没见过,然后这个是我很早很早之前的老友分享的,然后昨天花时间去看了一下,之前经常听其他大佬说,但是我也出来没遇见过。 感觉…

损坏的视频不能观看,还能修复吗?

3-1 在日常的生活或者工作中,特别是做摄像工作的人,有一定的概率会遇到损坏的视频文件,比如相机突然断电、无人机炸机等,都有可能导致保存的视频文件损坏。 如果遇到这种情况,该如何修复这种损坏的视频文件&#xff…

Java入门必刷的基础题1(八道)

目录 1. 第一题 2. 判定一个数字是否是素数 3. 打印 1 - 100 之间所有的素数 4. 输出 1000 - 2000 之间所有的闰年 5. 输出乘法口诀表 6. 求两个正整数的最大公约数 7. 求二进制中 1 的个数 8.分别输出二进制中的奇数位和偶数位 下面的源码大多只有方法体,需…

k8s资源对象--pod

创建pod: kubectl get pod cp test_pod_1.yaml nginx_pod.yaml cah 查看详细信息: pod的状态处于pending可能的原因:一个或多个没有运行 由于当前所有节点没有可用节点(所有节点资源不足,所有节点) 查看所有&…

免费好用的DNS在线工具,DNS记录、域名被墙、Whois轻松查询

在互联网的世界中,DNS是一种非常重要的存在,它们是域名与IP地址之间的桥梁,用于实现用户访问网站。我们在搭建网站时,经常会用到一些DNS工具,以便了解网站的DSN情况。DNS记录查询工具、域名被墙检测工具以及Whois域名信…

【WinForm详细教程四】WinForm中的ProgressBar 、ImageList和ListView控件

文章目录 1.ProgressBar2. ImageList3.ListView控件 1.ProgressBar 用于显示某个操作的进度。 属性: Value: 表示当前进度条的值,其范围由Min和Max决定。Step: 设置每次调用PerformStep()方法时增加的步长。MarqueeAnimationSpeed: 在Style设置为Marq…