缓存击穿只会逻辑过期 OR 互斥锁?深入思考 == 鹤立鸡群
网上但凡看得见的文章,大部分在说缓存穿透时都是无脑分布式锁 / 逻辑过期,分布式锁一点问题都没有么?逻辑过期一点问题都没有么?还能不能再进一步优化?
在聊聊缓存击穿的双重判定锁之前,我们将按照循循渐进的方式讲解,什么是缓存击穿?常规解决方案的弊端是啥?缓存击穿解决方案能不能进一步优化?
什么是缓存击穿?
缓存击穿是指一个缓存中的数据因为某种原因(通常是缓存中的数据过期或者被删除),在短时间内遭受大量的请求,导致这些请求直接穿透到数据库或其他后端存储系统,增加了后端系统的负载。
缓存击穿通常在以下情况下发生:
- 热点数据过期:当缓存中存储的热门数据过期时,大量的请求会同时查询后端数据库。
- 第一次请求:对于一个之前从未被请求过的数据,当它第一次被请求时,缓存中没有这个数据,从而导致请求穿透到后端存储。

常规解决方案的弊端
为了解决Redis缓存击穿问题,八股文都是直接采取以下方案:
- 设置热点数据永不过期:对于一些热点数据,可以将其永不过期,确保即使数据过期后,仍然可以从缓存中获取。
- 使用互斥锁:在获取数据时,使用分布式锁(如 Redis 的分布式锁)来控制同时只有一个请求可以去后端获取数据,其他请求需要等待锁释放。这样可以防止多个请求同时穿透到后端存储。
思考一
设置热点数据永不过期属于是业务范围应该考虑的事情,这个数据是否应该永不过期?或者说活动时设置过期时间为 -1,活动后再执行程序删除。有一点可以确认,缓存数据不可能全部都是永不过期,因为缓存的存储压力会比较大,所以该方案无法作为通用方案。
那我们可以从互斥锁上面下下文章,如何通过互斥锁完成缓存击穿场景解决方案?
思考二
在获取数据时,使用分布式锁(如 Redis 的分布式锁)来控制同时只有一个请求可以去后端获取数据,其他请求需要等待锁释放。这样可以防止多个请求同时穿透到后端存储。

伪代码如下:
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))这一步。
这会造成两个实际的问题:
- 全部用户获取锁后查询数据库,会对数据库造成无用的性能浪费,因为这 100w 的请求,只有第一次是有效的。
- 查询数据库会造成用户响应时间变长,接口吞吐量下降。
双重判断:获取锁后,在查询数据库之前,再次检查一下缓存中是否存在数据。这是一个双重判断,如果缓存中存在数据,就直接返回;如果不存在,才继续执行查询数据库的操作。

伪代码如下:
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;
}
下面是这种解决方案的一般步骤:
- 获取锁:在查询数据库前,首先尝试获取一个分布式锁。只有一个线程能够成功获取锁,其他线程需要等待。
- 查询数据库:如果双重判断确认数据确实不存在于缓存中,那么就执行查询数据库的操作,获取数据。
- 写入缓存:获取到数据后,将数据写入缓存,并设置一个合适的过期时间,以防止缓存永远不会被更新。
- 释放锁:最后,释放获取的锁,以便其他线程可以继续使用这个锁。
文末总结
本文深入探讨了缓存击穿问题以及解决方案。首先,我们了解了缓存击穿是指一个缓存中的数据因为某种原因(通常是缓存中的数据过期或者被删除),在短时间内遭受大量的请求,从而直接查询数据库,对系统性能造成了巨大的压力。然后,我们介绍了解决缓存击穿问题的一种有效方式——分布式互斥锁,以及分布式互斥锁的升级版本——双重判定锁。
总结一下:
- 缓存击穿问题是指某些请求查询缓存中不存在的数据,导致大量请求直接穿透到后端数据库,对系统性能造成严重影响。
- 分布式互斥锁是一种解决缓存击穿的有效方式。它通过在查询缓存之前尝试获取锁,只有一个线程能够成功获取锁,其他线程需要等待。这确保了只有一个线程可以查询数据库,避免了大规模的穿透。
- 双重判定锁是分布式互斥锁的升级版本。它在获取锁后,再次检查缓存中是否存在数据,以避免重复查询数据库。只有在确认缓存中不存在数据时,才继续查询数据库。
这两种解决方案都能够有效地应对缓存击穿问题,但需要根据实际情况选择合适的方式。分布式互斥锁适用于大多数场景,而双重判定锁则提供了更高的效率,适用于一些特定的场景。选择合适的解决方案,可以保护系统免受缓存击穿问题的困扰,提高性能和可靠性。
相关文章:
缓存击穿只会逻辑过期 OR 互斥锁?深入思考 == 鹤立鸡群
网上但凡看得见的文章,大部分在说缓存穿透时都是无脑分布式锁 / 逻辑过期,分布式锁一点问题都没有么?逻辑过期一点问题都没有么?还能不能再进一步优化? 在聊聊缓存击穿的双重判定锁之前,我们将按照循循渐进…...
从 Seq2Seq 到 Attention:彻底改变序列建模
探究Attention机制和意力的起源。 简介 在这篇博文[1]中,将讨论注意力机制的起源,然后介绍第一篇将注意力用于神经机器翻译的论文。由于上下文压缩、短期记忆限制和偏差,具有 2 个 RNN 的 Seq2Seq 模型失败了。该模型的 BLEU 分数随着序列长度…...
手机通讯类、ip查询、智能核验、生活常用API接口推荐
手机通讯类 手机号码归属地:提供三大运营商的手机号码归属地查询。 空号检测:通过手机号码查询其在网活跃度,返回包括空号、停机等状态。 手机在网状态:支持传入三大运营商的号码,查询手机号在网状态,返…...
1.6 基本安全设计准则
思维导图: 1.6 基本安全设计准则笔记 目标:理解和遵循一套广泛认可的安全设计准则,以指导保护机制的开发。 主要准则: 机制的经济性:安全机制应设计得简单、短小,便于测试和验证,减少漏洞和降…...
图扑 HT for Web 手机端运维管理系统
随着信息技术的快速发展,网络技术的应用涉及到人们生活的方方面面。其中,手机运维管理系统可提供数字化、智能化的方式,帮助企业和组织管理监控企业的 IT 环境,提高运维效率、降低维护成本、增强安全性、提升服务质量,…...
LiveGBS流媒体平台GB/T28181常见问题-国标级联海康国标级联大华国标级联华为等,配置了国标级联, 上级看不到通道该怎么办?
LiveGBS常见问题-国标级联海康国标级联大华国标级联华为等,配置了国标级联, 上级看不到通道该怎么办? 1、如何配置国标级联2、上级看不到通道排查2.1、是否共享通道2.3、通道编号是否满足上级要求 3、如何抓包分析4、搭建GB28181视频直播平台 1、如何配置国标级联 …...
数字频带传输——二进制数字调制及MATLAB仿真
文章目录 前言一、OOK1、表达式2、功率谱密度3、调制框图 二、2PSK1、表达式2、功率谱密度 三、2FSK1、表达式 四、MATLAB 仿真1、MATLAB 源码2、仿真及结果①、输入信号及频谱图②、2ASK 调制③、2PSK 调制④、2FSK 调制⑤、随机相位 2FSK 调制 五、资源自取 前言 数字频带信…...
Bitdu 150万美元投资MSG:Web3合作典范催动极致交易体验
在Web3时代,如何一键把握DEX领域的机遇,是摆在一众中心化交易所面前的难题。 近期,新锐加密资产交易所Bitdu向MsgSender(MSG)投资150万美元,引起了专业的交易者们的关注。大家普遍认为,这一事件…...
CentOS一键部署Docker
Docker官网:https://www.docker.com/ CentOS(7.6) Docker(18.06.1)一键安装脚本 #!/bin/bash echo "1、安装依赖..." yum -y install gcc yum -y install gcc-c##验证gcc版本 gcc -vecho "2、卸载老…...
Centos虚拟机安装配置与MobaXterm工具及Linux常用命令
目录 一、Centos操作系统 1.1 Centos介绍 1.2 Centos虚拟机安装 1.3 配置centos的镜像 1.4 虚拟机开机初始设置 1.4.1 查看网络配置 1.4.2 编辑网络配置 二、MobaXterm工具 2.1 MobaXterm介绍 2.2 MobaXterm安装 2.3 切换国内源 三、Linux常用命令和模式 3.1 查看网络配置 …...
springboot医院绩效考核系统源码
医院绩效考核系统是一种以人力资源管理为基础,选用适合医院组织机构属性的绩效理论和方法,基于医院战略目标,构建全方位的绩效考评体系,在科学、合理的绩效管理体系基础上,采用科学管理的方法,如平衡计分卡…...
Java--枚举类型
Java中枚举类型可以取代一般的常量定义方式,可以将常量封装在类或接口中;枚举类型本质上还是以类的形式存在的,枚举类型继承于java.lang.Enum类,定义一个枚举类型时,每一个枚举类型成员都可以看做是枚举类型的一个实例…...
有没有好用的配音工具?推荐这5款
为什么越来越多的短视频创作者愿意使用配音工具。 除了这些配音工具可以进行批量处理,实现大规模的音频制作,从而提高生产效率。还可以帮助其节约大量的人力,想一下,以前配音,不同的音色、角色需要不同的人来完成&…...
tomcat安装及配置教程
以下是 Tomcat 安装及配置的基本步骤: 下载 Tomcat 并解压缩:在 Apache Tomcat 的官网上下载最新版本的 Tomcat,然后解压缩到你想要安装的目录下(比如 /usr/local/tomcat)。 配置 PATH 环境变量:在终端中打…...
UNIPOSE: DETECTING ANY KEYPOINTS(2023.10.12)
文章目录 AbstractIntroduction现有的方法存在哪些不足基于此,我们提出了哒哒哒取得惊人的成绩Related Work MethodMULTI -MODALITY PROMPTS ENCODING(多模态提示编码)Textual Prompt Encoder(文本提示编码器)Visual P…...
如何用ChatGPT快速写出一份合格的PPT报告
我们【AI写稿专家】的小伙伴中有很多企业高管和公务员,大家经常有写报告写ppt的需求,下面小编给大家介绍一下我们新发布生成PPT的功能,很简单很方便,看完大家不到1分钟就能生成一份拿得出手的PPT报告,再也不用费尽心思…...
Linux内存管理的分页机制
分段机制的原理如下: 分段机制下的虚拟地址由两部分组成,段选择子和段内偏移量。段选择子就保存在段寄存器里面。段选择子里面最重要的是段号,用作段表的索引。段表里面保存的是这个段的基地址、段的界限和特权等级等。虚拟地址中的段内偏移量…...
Unity DOTS系列之托管/非托管Component的区别与性能分析
最近DOTS发布了正式的版本, 我们来分享一下DOTS里面托管与非托管Component的区别与性能分析,方便大家上手学习掌握Unity DOTS开发。托管与非托管的区别在于是不是基于自动垃圾回收的。托管是由垃圾回收器来负责自动回收,非托管需要我们手动来做相关内存管…...
elementui el-upload 上传文件
文章目录 前言一、Html2.上传 总结 前言 在使用element中的el-upload上传文件或者图片时,需要先把el-upload的自动上传改为手动上传:auto-upload“false”然后el-upload内部会调用this.$refs.upload.submit();方法,从而实现多个文件上传。 提示…...
Python图像处理【15】基于非锐化掩码锐化图像
基于非锐化掩码锐化图像 0. 前言1. 使用 scikit-image filters 模块执行非锐化掩码2. 使用 PIL ImageFilter 模块执行非锐化掩码3. 使用 SimpleITK 执行拉普拉斯锐化4. 使用 OpenCV 实现非锐化掩码小结系列链接 0. 前言 非锐化滤波器是一个简单的锐化算子,通过从原…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
