高并发场景下,缓存“穿透”了该怎么办?

通常情况下,被访问的数据即使不在缓存当中,请求也是可以访问数据库然后将结果回填到缓存中的。缓存“穿透”是指,访问的 key 并不存在(即业务系统中没有这个 key),之后请求“穿透”到数据库中,从数据库查询出来的是空值(NULL)。

用户访问一个不存在的 key,“穿透”到数据库中,数据库返回空值,并不会回填到缓存中,那么后续不管查询这个key多少次,都会缓存命中失败,直接“穿透”到数据库中。这样会严重影响数据库的性能。

如果是恶意破坏的请求,或者恶意地大量访问不存在的key,则会使系统的整体性能严重下降,并最终影响正常的用户请求。

1. 解决方案

大量的缓存“穿透”会对系统产生致命的影响,所以,对于缓存“穿透”需要重视起来。一般有以下两种解决方案。

(1)回种空值。

发生“穿透”的原因是,在数据库中根本不存在被访问的数据。这样无论访问多少次都获取不到这些数据,“穿透”会一直发生。

所以,在访问不存在的数据时,虽然第一次“穿透”到数据库获取的是空值(NULL),但可以用这个空值(NULL)回填缓存(称为“回种空值”)。

但是空值并不是真实的业务数据,如果有人恶意访问这些并不存在的 key,则会占用很大的内存空间,从而将正常的业务 key 给自动淘汰掉。所以,在将这些不存在 key 写入缓存时,可以加上一个很短的有效期以使其快速过期,伪代码如下:

Object nullValue = new Object();try {    // 从数据库中查询数据Object valueFromDB = selectFromDB(uid);if (valueFromDB == null {// 如果从数据库查询到空值,则把空值写入缓存,并设置较短的超时时间redisCache.set(uid, nullValue, 10);} else {redis.Cache.set(uid, valueFromDB, 1000);}} catch Exception(e) {    redisCache.set(uid, nullValue, 10)}

回种空值这种方案,会阻挡很大一部分的“穿透”请求。但是如果大批量地访问不存在的 key,则这种方案会造成缓存容量的紧张,甚至占满内存空间。

在具体实施过程中。如果要解决这种“穿透”,则需要额外增加很多的缓存节点,有点得不偿失,此时可以考虑使用第二种方案“实用布隆过滤器”。

(2)使用布隆过滤器

布隆过滤器用来检测一个元素是否在一个集合中。这种算法由一个二进制数组加上一个Hash算法组成。其基本原理如下:

  1. 数据结构: 布隆过滤器通常由一个位数组(Bit Array)和一组哈希函数组成。

  2. 位数组: 位数组是布隆过滤器的主要存储结构,它通常初始化为全部为0。每个元素在位数组中对应多个位,初始时都被设为0。

  3. 哈希函数: 布隆过滤器需要 k 个哈希函数。这些哈希函数可以将任意大小的数据映射到位数组的某个位置。对于每个元素,通过这 k 个哈希函数计算出 k 个哈希值,然后将对应的位数组位置设为1。

  4. 插入操作: 当向布隆过滤器中插入一个元素时,通过 k 个哈希函数计算出 k 个哈希值,并将对应的位数组位置设为1。

  5. 查询操作: 当查询一个元素是否存在于集合中时,同样通过 k 个哈希函数计算出 k 个哈希值,然后检查这 k 个位置的值。如果所有的位置都为1,则认为元素可能存在;如果有任何一个位置为0,则元素一定不存在。

由于哈希函数的存在,布隆过滤器有一定的误判率,即可能存在 "误判为存在" 的情况,但不存在 "误判为不存在" 的情况。

优点:

  • 布隆过滤器的查询时间复杂度是常量级别的,非常高效。
  • 空间效率较高,因为只需要存储位数组和少量哈希函数。

缺点:

  • 有一定的误判率。
  • 不支持删除操作,删除一个元素可能会影响其他元素的判断结果。

应用场景:

  • 缓存系统,用于快速判断某个数据是否在缓存中。
  • 防止缓存穿透,即防止查询不存在的数据频繁地访问数据库。
  • 分布式系统中的去重操作等。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常用的 MySQL 可视化客户端

数据库可视化客户端(GUI)让用户在和数据库进行交互时,能直观地查看、创建和修改对象,如:表、行和列。让数据库操作变得更方便了。 今天,我们来了解下目前市场上最常用的 MySQL 可视化客户端。 官方&#x…

数据结构期末复习(2)链表

链表 链表(Linked List)是一种常见的数据结构,用于存储一系列具有相同类型的元素。链表由节点(Node)组成,每个节点包含两部分:数据域(存储元素值)和指针域(指…

CSS Grid Level 2

CSS Grid Level 2 是对 CSS Grid Layout 的扩展和改进。下面是一些关于 CSS Grid Level 2 的说明、代码示例和使用场景: 说明: 子网格(subgrid):CSS Grid Level 2 允许子网格与父网格的行和列对齐,使得嵌…

Vue前后端跨域链接

前端更改访问方式 在vite.config.js文件设置映射的路径 export default defineConfig({plugins: [vue(),],resolve: {alias: {: fileURLToPath(new URL(./src, import.meta.url))}},server: {proxy: {/api: {target: http://localhost:8080,changeOrigin: true,rewrite: (pat…

vscode配置的C++环境

目录 1、下载并安装VScode 2、下载MinGW 3、配置MinGW 3.1添加环境变量 3.2 Vscode配置 3.3测试 1、下载并安装VScode Visual Studio Code - Code Editing. Redefined 2、下载MinGW 在MinGW官网MinGW-w64 - for 32 and 64 bit Windows - Browse /mingw-w64/mingw-w64-r…

List集合格式转换

最近遇到一个任务: 需要把A集合数据转成 B集合的形式: A集合: B集合: 代码: package com.example.juc.test;import com.example.juc.entity.Ld; import com.example.juc.entity.Student;import java.lang.reflect.F…

【Petalinux】制作SD卡 操作系统 启动

Vivado 添加 SD0 导出hdf 制作SD卡 https://mathd.blog.csdn.net/article/details/135217761 【Petalinux】下为空白SD卡建立BOOT,rootfs分区 Petalinux 生成 Petalinux 框架 petalinux-create --type project --template zynq --name sdtest进入 sdtest 文件…

Ksher H5页面支付实例指导 (PHP实现)

前文 背景介绍 前两天,公司的项目,为了满足泰国客户的支付需求,要求使用 Ksher (开时支付) 对接任务突然就给了鄙人,一脸懵 … 通过了解客户的使用场景、以及参考官网指导 发现:Ksher支付 最令人满意的便是 —— 提供了…

【网络安全/CTF】easyphp 江苏工匠杯

本题考察PHP语言相关绕过知识 正文 开门见山给代码 <?php highlight_file(__FILE__); $key1 0; $key2 0;$a $_GET[a]; $b $_GET[b];if(isset($a) && intval($a) > 6000000 && strlen($a) < 3){if(isset($b) && 8b184b substr(md5($b),…

【Java】如何给你的图片添加自定义水印(附完整代码)?

这是一篇关于怎么尽可能的用尽你电脑里的所有字体给你的图片加水印。。。。 先上效果~ 当然这只是其中一部分字体&#xff0c;&#xff0c;&#xff0c;我也是今天才发现我电脑里居然装了那么多字体 好了废话不多说直接上完整代码~ import io.swagger.models.auth.In;import …

循环生成对抗网络(CycleGAN)

一、说明 循环生成对抗网络&#xff08;CycleGAN&#xff09;是一种训练深度卷积神经网络以执行图像到图像翻译任务的方法。网络使用不成对的数据集学习输入和输出图像之间的映射。 二、基本介绍 CycleGAN 是图像到图像的翻译模型&#xff0c;就像Pix2Pix一样。Pix2Pix模型面临…

软件测试/测试开发丨Python 内置库 sys 学习笔记分享

sys 概述 是 Python 自带的内置模块是与 Python 解释器交互的桥梁 sys 使用 常用属性常用方法导入 sys 模块 # 导入sys模块 import sys# 查看sys模块帮助文档 help(sys)# 查看sys模块的属性和方法 print(dir(sys))sys 常用属性 sys.version&#xff1a;返回 Python 解释器…

软件测试/测试开发丨Python 面向对象编程思想

面向对象是什么 Python 是一门面向对象的语言面向对象编程&#xff08;OOP&#xff09;&#xff1a;Object Oriented Programming 所谓的面向对象&#xff0c;就是在编程的时候尽可能的去模拟真实的现实世界&#xff0c;按照现实世界中的逻辑去处理问题&#xff0c;分析问题中…

SpringBoot 实现订单30分钟自动取消的策略

简介 在电商和其他涉及到在线支付的应用中&#xff0c;通常需要实现一个功能&#xff1a;如果用户在生成订单后的一定时间内未完成支付&#xff0c;系统将自动取消该订单。 本文将详细介绍基于Spring Boot框架实现订单30分钟内未支付自动取消的几种方案&#xff0c;并提供实例…

【每日试题】java面试之ssm框架

以下是20道常见的SSM&#xff08;SpringSpring MVCMyBatis&#xff09;面试题目和答案&#xff1a; 什么是SSM框架&#xff1f; SSM是指SpringSpring MVCMyBatis的组合&#xff0c;它是Java Web开发中常用的轻量级框架集合。 介绍一下SSM框架各个组件的作用&#xff1f; Sprin…

AI电商时代开始:阿里能否反杀拼多多

“AI电商时代刚刚开始&#xff0c;对谁都是机会&#xff0c;也是挑战。” 针对阿里员工对于拼多多财报和电商等的讨论&#xff0c;马云在阿里内网罕见地参与了谈论并发言。 阿里巴巴一向雷厉风行&#xff0c;已打响了AI电商的“第一炮”。 根据《晚点LatePost》报道&#xff…

C# vs报错 id为XX的进程当前未运行

报错原因&#xff1a;虚拟目录端口被占用 解决方法&#xff1a;重新配置新的目录端口就行 1、选择项目属性 2、更改端口号&#xff0c;点击创建虚拟目录 3、重新生成项目

ISP 基础知识积累

Amber&#xff1a;现有工作必要的技术补充&#xff0c;认识需要不断深入&#xff0c;这个文档后续还会增加内容进行完善。 镜头成像资料 ——干货满满&#xff0c;看懂了这四篇文章&#xff0c;下面的问题基本都能解答 看完思考 1、ISP 是什么&#xff0c;有什么作用&#xff…

PHP实现多继承

php支持多继承吗 不可以,只支持单继承。 可以使用 interface 或 trait 实现 。 实现方法 https://www.php.cn/faq/430197.html https://blog.58heshihu.com/index.php/archives/2288/

C++实现定积分运算

文章目录 题目代码 题目 代码 #include <iostream> #include <cmath> #include <functional>using namespace std;// 定积分函数 double integrate(function<double(double)> func, double a, double b, int num_intervals) {double h (b - a) / num…