缓存穿透解决方案:从基础到高级优化

缓存穿透解决方案:从基础到高级优化

缓存穿透是指由于请求无法命中缓存,导致大量请求直接打到数据库。当请求量较大时,可能会导致数据库承受过重压力,甚至崩溃。本文将详细探讨缓存穿透问题的几种常见解决方案,并提供代码示例帮助理解。

1. 缓存穿透问题的背景

通常情况下,缓存是为了提高数据访问速度,避免频繁查询数据库。但如果攻击者故意请求缓存中不存在的数据,或者由于缓存未能命中,就会导致请求直接访问数据库。当请求量过大时,这种情况可能导致数据库压力骤增,甚至崩溃。
为了解决缓存穿透问题,常见的解决方案包括空对象值缓存、使用分布式锁、布隆过滤器,以及多种方法的组合。

2. 解决方案一:空对象值缓存

当查询结果为空时,也将结果进行缓存,但设置一个较短的过期时间。这样,在接下来的一段时间内,如果再次请求相同的数据,就可以直接从缓存中获取,而不是再次访问数据库,从而一定程度上解决缓存穿透问题。

优点

  • 简单易实现。

缺点

  • 可能导致短时间内内存占用过大,特别是在存在大量恶意请求时。

伪代码示例

public String selectUser(String userId) {
    String cacheData = cache.get(userId);
    if (StrUtil.isBlank(cacheData)) {
        Boolean cacheIsNull = cache.hasKey("is-null_" + userId);
        if (cacheIsNull) {
            throw new RuntimeException();
        }
        String dbData = userMapper.selectId(userId);
        if (StrUtil.isNotBlank(dbData)) {
            cache.set(userId, dbData);
            cacheData = dbData;
        } else {
            cache.set("is-null_" + userId, 短过期时间);
            throw new RuntimeException();
        }
    }
    return cacheData;
}

这种方案适用于较简单的应用场景,但对于需要防御大量恶意请求的系统,可能需要更复杂的解决方案。

3. 解决方案二:使用分布式锁

当请求发现缓存不存在时,可以使用分布式锁机制,避免多个相同的请求同时访问数据库。这样,只让一个请求去加载数据,其他请求等待,从而减轻数据库压力。

优点

  • 有效防止多个相同请求同时打击数据库。

缺点

  • 存在“误杀”现象,用户等待时间可能较长。

伪代码示例

public String selectUser(String userId) {
    String cacheData = cache.get(userId);
    if (StrUtil.isBlank(cacheData)) {
        Lock lock = getLock("业务标识");
        lock.lock();
        try {
            cacheData = cache.get(userId);
            if (StrUtil.isBlank(cacheData)) {
                String dbData = userMapper.selectId(userId);
                if (StrUtil.isNotBlank(dbData)) {
                    cache.set(userId, dbData);
                    cacheData = dbData;
                }
            }
        } finally {
            lock.unlock();
        }
    }
    return cacheData;
}

在此方案中,锁标识选择“业务标识”而不是具体的userId,以防止锁的失效。

4. 解决方案三:布隆过滤器

布隆过滤器是一种数据结构,可以用于判断一个元素是否存在于一个集合中。它可以在很大程度上减轻缓存穿透问题,因为它可以快速判断数据是否可能存在于缓存中。

优点

  • 能有效过滤大多数不存在的请求,降低数据库压力。

缺点

  • 存在一定的误判概率,可能导致少量错误请求。

伪代码示例

public String selectUser(String userId) {
    String cacheData = cache.get(userId);
    if (StrUtil.isBlank(cacheData)) {
        if (!bloomFilter.contains(userId)) {
            throw new RuntimeException();
        }
        String dbData = userMapper.selectId(userId);
        if (StrUtil.isNotBlank(dbData)) {
            cache.set(userId, dbData);
            cacheData = dbData;
        }
    }
    return cacheData;
}

布隆过滤器在大数据量场景下表现良好,适合用来防止大规模缓存穿透。

5. 解决方案四:布隆过滤器+空对象+分布式锁

为了更加完善地解决缓存穿透问题,可以将布隆过滤器、空对象缓存和分布式锁组合使用。具体流程如下:

  • 当缓存不存在时,先通过布隆过滤器进行初步筛选。
  • 如果布隆过滤器判定数据可能存在,则检查是否存在空对象缓存。
  • 如果空对象缓存不存在,再使用分布式锁防止多个相同请求同时访问数据库。
  • 最后,如果数据库查询结果为空,将结果缓存为空对象,以防后续重复查询。

伪代码示例

public String selectUser(String userId) {
    String cacheData = cache.get(userId);
    if (StrUtil.isBlank(cacheData)) {
        if (!bloomFilter.contains(userId)) {
            throw new RuntimeException();
        }
        Boolean cacheIsNull = cache.hasKey("is-null_" + userId);
        if (cacheIsNull) {
            throw new RuntimeException();
        }
        Lock lock = getLock("业务标识");
        lock.lock();
        try {
            cacheData = cache.get(userId);
            if (StrUtil.isBlank(cacheData)) {
                String dbData = userMapper.selectId(userId);
                if (StrUtil.isNotBlank(dbData)) {
                    cache.set(userId, dbData);
                    cacheData = dbData;
                } else {
                    cache.set("is-null_" + userId, 短过期时间);
                    throw new RuntimeException();
                }
            }
        } finally {
            lock.unlock();
        }
    }
    return cacheData;
}

这种组合方式能够最大限度地防止缓存穿透问题,提高系统稳定性和性能。

结论

缓存穿透是一个常见的技术挑战,特别是在高并发和大数据环境下。本文通过详细讲解了几种常见的解决方案,包括空对象值缓存、使用分布式锁、布隆过滤器及其组合应用。通过合理选择和组合这些方案,能够有效防止缓存穿透问题,提高系统的稳定性和性能。

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

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

相关文章

EasyCVR视频汇聚平台构建远程安防监控:5大亮点解析,助力安防无死角

随着科技的飞速发展,远程安防监控系统已经成为现代社会中不可或缺的一部分,无论是在小区、公共场所还是工业领域,安防监控都发挥着至关重要的作用。而EasyCVR作为一款功能强大的视频监控综合管理平台,其在构建远程安防监控系统方面…

Qt 学习第六天:页面布局

如何设计页面? 有个类似沙盒模式的玩法,Qt Widget Designer可以更好的帮助我们设计页面 点击.ui文件进入 右上方可以看到四种常见的布局: 四种布局 (一)水平布局horizontalLayout:QHBoxLayout H 是 hori…

算法之工程化内容(3)—— Docker常用命令

目录 1. 配置docker镜像加速 2. 创建镜像docker-name 3. 查看正在运行的镜像 4. 拉取镜像 5. 运行镜像 6. 停止/启动指定 id 的容器 7. 删除指定 id 的镜像/容器 8. docker发布和部署 (推荐教程:🚚 发布和部署 - Docker 快速入门) 1. 配置docke…

【蓝桥杯集训100题】scratch时间计算 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第26题

目录 scratch时间计算 一、题目要求 编程实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、python资料 scratc…

【网络】UDP和TCP之间的差别和回显服务器

文章目录 UDP 和 TCP 之间的差别有连接/无连接可靠传输/不可靠传输面向字节流/面向数据报全双工/半双工 UDP/TCP API 的使用UDP APIDatagramSocket构造方法方法 DatagramPacket构造方法方法 回显服务器(Echo Server)1. 接收请求2. 根据请求计算响应3. 将…

AdMob聚合平台

Google Admob产品介绍 Google给开发者提供了3款用于流量变现的产品,分别是AdMob,通过应用内广告帮助App开发者变现;AdSense,通过网站广告帮助所有者变现;Google Ads Manager,通过全面管理和优化广告资源&a…

[ICLR-24] LRM: Large Reconstruction Model for Single Image to 3D

[pdf | proj | code] 本文首次提出大型重建模型(Large Reconstruction Model, LRM),实现5s内对单图物体的3D重建。在128张A100(40G)上训练30 epochs。 LRM包含三个部分,具体框架如下: 图片编码…

亚马逊测评号生存法则:如何抵御亚马逊封号风波?

距离黑五购物狂欢节还剩99天,相信各位商家都在紧锣密鼓的筹备相关事宜,然而,亚马逊的封号风波再次席卷而来。那如何在这场风暴中让亚马逊矩阵测评号安全航行亦或是脱颖而出呢?本文将给你一个答案,并帮助你的亚马逊店铺…

【java计算机毕设】足浴城消费系统小程序MySQL ssm vue uniapp maven项目设计源代码 编程语言 小组课后作业 寒暑假作业

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】足浴城消费系统小程序MySQL ssm vue uniapp maven项目设计源代码 编程语言 小组课后作业 寒暑假作业 2项目介绍 系统功能: 足浴城消费系统小程序包括管理员、用户、商家三种角色。 管理员功能&…

Transformer大模型在训练过程中所需的计算量

目录 简介计算需求参数与数据集的权衡计算成本的工程意义内存需求推理模型权重总推理内存训练模型参数优化器状态梯度激活值和批大小总训练内存分布式训练分片优化器3D 并行分片优化器 + 3D 并行参考简介 许多关于Transformer语言模型的基本且重要的信息都可以用相当简单的方式…

C++ 特殊类设计以及单例模式

目录 1 不能被拷贝 2 只能在堆上创建对象 3 只能在栈上创建对象 4 禁止在堆上创建对象 5 不能被继承的类 6 单例类 特殊类就是一些有特殊需求的类。 1 不能被拷贝 要设计一个防拷贝的类,C98之前我们只需要将拷贝构造以及拷贝赋值设为私有,同时只声明…

2024年入职/转行网络安全,该如何规划?_网络安全职业规划

前言 前段时间,知名机构麦可思研究院发布了 《2022年中国本科生就业报告》,其中详细列出近五年的本科绿牌专业,其中,信息安全位列第一。 网络安全前景 对于网络安全的发展与就业前景,想必无需我多言,作为…

探索802.1X:构筑安全网络的认证之盾

在现代网络安全的世界里,有一个极其重要但又常常被忽视的角色,它就是802.1x认证协议。这个协议可以被称作网络安全的守护者,为我们提供了强有力的防护。今天,我们就来深入探讨一下802.1x的原理、应用和测试,看看它是如…

干货|光伏开发全流程

在当今全球能源转型与应对气候变化的背景下,光伏产业作为可再生能源的重要组成部分,正以前所未有的速度发展。光伏开发,即从项目规划到并网发电的全过程,涉及多个环节,每个步骤都至关重要。而其中户用和工商业光伏开发…

DBAPI如何用SQL将多表关联查询出树状结构数据(嵌套JSON格式)

场景描述 假设数据库中有3张表如下: 客户信息表 订单表 订单详情表 一个客户有多个订单,一个订单包含多个产品信息,客户-订单-产品就构成了3级的树状结构,如何查询出如下树状结构数据呢? [{"customer_age"…

Notion使用详解

​ ​ 您好,我是程序员小羊! 前言 Notion是一款集笔记、任务管理、知识库、文档协作等多功能于一体的生产力工具。其灵活性和可定制性使得它在个人和团队协作中都非常受欢迎。本教程将详细介绍如何使用Notion的基本功能,帮助你快速上手并充分…

【云原生】Ingress控制器超级详解

Ingress资源对象 文章目录 Ingress资源对象一、Ingress1.1、Ingress是什么?1.2、Ingress术语1.3、Ingress类型 二、Ingress详细2.1、部署Nginx-Ingress控制器2.2、最小Ingress资源2.3、Ingress规则 三、一个域名多个访问路径多SVC四、多域名Ingress五、转发到默认Se…

【C语言小项目】五子棋游戏

目录 前言 一、游戏规则 1.功能分析 2.玩法分析 3.胜负判定条件 二、游戏实现思路 三、代码实现与函数封装 1.项目文件创建 2.头文件说明 3.函数封装 1)菜单实现 2)进度条实现 3)main函数实现 4)Game函数 5&#xff0…

【系统架构设计】软件架构设计(2)

【系统架构设计】软件架构设计(1) 软件架构概述架构需求与软件质量属性软件架构风格层次系统架构风格面向服务的架构SOA概述微服务微服务和SOA差异 软件架构概述 架构需求与软件质量属性 软件架构风格 层次系统架构风格 面向服务的架构 SOA概述 面…

C语言手撕实战代码_循环单链表和循环双链表

C语言手撕实战代码_循环单链表和循环双链表 循环单链表习题1.建立带头结点的循环链表2.设计一个算法,将一个带有头结点的循环单链表中所有结点的链接方向逆转3.设计一个算法,将一个循环单链表左移k个结点4.设计一个算法将循环单链表中的结点p的直接前驱删除5.设计算…