Redis场景问题2:缓存击穿

news2025/4/1 21:11:53

Redis 缓存击穿是指在缓存系统中,大量请求(高并发访问)同时访问一个不存在于缓存中(一般是因为缓存过期或者数据未被加载到缓存)但在数据库中存在的热点数据,从而导致这些请求直接穿透缓存层,涌向数据库,可能造成数据库压力过大甚至崩溃的情况。以下是关于它的详细介绍:

  • 产生原因:一般是由于缓存中的某个热点数据过期,而此时有大量并发请求过来访问该数据。这些请求在发现缓存中没有对应数据后,都会去数据库中查询,从而形成对数据库的集中式访问压力。例如电商网站中某个热门商品的信息缓存过期,而此时大量用户同时访问该商品详情页,就可能引发缓存击穿问题。
  • 解决方案
    • 逻辑过期:不设置TTL,之前所说导致缓存击穿的原因就是该key的TTL到期了,所以我们在这就不设置TTL了,而是使用一个字段,例如:expire表示过期时间(逻辑上的)。当我们想让它 “ 过期 ” 的时候,我们可以直接手动将其删除(热点key,即只是在一段时间内,其被访问的频次很高。这种方案巧妙在于,异步的构建缓存,缺点在于在构建完缓存之前,返回的都是脏数据。
    • 加互斥锁(Mutex Lock):在缓存数据过期后,当第一个请求来访问时,先获取一个互斥锁,然后去数据库加载数据并更新到缓存中,其他请求则等待该锁释放后再从缓存中获取数据。通过这种方式,可以确保在同一时刻只有一个请求去数据库查询数据,避免大量请求同时穿透到数据库。例如在 Java 中可以使用 ReentrantLock 来实现互斥锁。以下是一个简单的示例代码:
import java.util.concurrent.locks.ReentrantLock;

public class CacheBreakthroughHandler {

    private static final ReentrantLock lock = new ReentrantLock();
    private static final RedisCache redisCache = new RedisCache(); // 假设这是一个操作Redis缓存的类

    public static Object getData(String key) {
        Object data = redisCache.get(key);
        if (data == null) {
            try {
                lock.lock();
                // 再次检查缓存,防止在获取锁的过程中其他线程已经更新了缓存
                data = redisCache.get(key);
                if (data == null) {
                    // 从数据库获取数据
                    data = getDataFromDatabase(key);
                    if (data != null) {
                        // 将数据放入缓存
                        redisCache.set(key, data);
                    }
                }
            } finally {
                lock.unlock();
            }
        }
        return data;
    }

    private static Object getDataFromDatabase(String key) {
        // 这里是从数据库获取数据的逻辑,根据实际情况实现
        return null;
    }
}

这两种解决方案对比:

  • 使用分布式锁(如 Redisson):在分布式系统环境下,可以使用分布式锁来替代互斥锁。分布式锁能够在多个节点之间实现互斥访问,确保同一时刻只有一个节点去数据库加载数据。例如使用 Redisson 框架来实现分布式锁,它基于 Redis 实现了各种分布式锁的功能,以下是一个简单的示例代码:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class CacheBreakthroughHandler {

    private static final RedissonClient redissonClient;
    private static final RedisCache redisCache = new RedisCache(); // 假设这是一个操作Redis缓存的类

    static {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        redissonClient = Redisson.create(config);
    }

    public static Object getData(String key) {
        Object data = redisCache.get(key);
        if (data == null) {
            RLock lock = redissonClient.getLock("lock:" + key);
            try {
                lock.lock();
                // 再次检查缓存,防止在获取锁的过程中其他线程已经更新了缓存
                data = redisCache.get(key);
                if (data == null) {
                    // 从数据库获取数据
                    data = getDataFromDatabase(key);
                    if (data != null) {
                        // 将数据放入缓存
                        redisCache.set(key, data);
                    }
                }
            } finally {
                lock.unlock();
            }
        }
        return data;
    }

    private static Object getDataFromDatabase(String key) {
        // 这里是从数据库获取数据的逻辑,根据实际情况实现
        return null;
    }
}

  • 缓存预热:在系统启动或者数据初始化阶段,提前将一些热点数据加载到缓存中,避免在系统运行过程中因为缓存未命中而导致缓存击穿。可以通过定时任务或者在系统启动时执行的初始化方法来实现缓存预热。例如,在电商系统启动时,将热门商品的信息提前加载到缓存中。
  • 二级缓存:采用二级缓存架构,例如在应用服务器内存中设置一级缓存,在 Redis 中设置二级缓存。当请求访问数据时,先从一级缓存中查找,如果未命中再从二级缓存中查找,若二级缓存也未命中,则去数据库查询并将数据依次放入二级缓存和一级缓存。这样可以在一定程度上减轻 Redis 缓存的压力,降低缓存击穿的风险。

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

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

相关文章

RocketMQ - 从消息可靠传输谈高可用

先稍微介绍下RocketMQ架构。 主从架构 Broker 集群:每个 Broker 分为 Master 和 Slave 角色,Master 负责读写,Slave 作为热备。 同步复制(SYNC_MASTER):消息写入 Master 后,需等待 Slave 同步完…

ES拼音分词自动补全实现

#测试拼音分词 POST /_analyze { "text":"如家酒店真不错", "analyzer": "pinyin" } #这里把拼音的首字母放到这里,也说明了这句话没有被分词,而是作为一个整体出现的 #还把每一个字都形成了一个拼音&#…

EFISH-SBC-RK3576 + 5G模组:无线工业相机与分布式AI质检‌

在智能制造与仓储物流场景中,传统有线工业相机存在部署成本高、灵活性差等痛点。‌eFish-SBC-RK3576‌ 通过 ‌5G无线传输 分布式NPU协同‌,实现跨产线、跨工厂的AI质检系统,检测效率提升300%,布线复杂度降低90%。 ‌1. 系统架构…

C/C++ 基础 - 回调函数

目录 前言 回调函数预备知识 函数指针 什么是函数指针 函数指针的语法 如何用函数指针调用函数 函数指针作为函数的参数 函数指针作为函数返回类型 函数指针数组 回调函数 什么是回调函数 为什么要用回调函数 怎么使用回调函数 总结 前言 在写项目的时候&#x…

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的消息队列:使用 RabbitMQ 实现异步处

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、开篇整…

DeepSeek分析仿写选题应该怎么做?

目录 选题分析&#xff1a;AIGC在学术写作中的应用及其与作者背景的关系 1. 选题背景与意义 2. 研究问题 3. 研究方法 4. 主要发现 5. 研究贡献 6. 研究局限与未来方向 7. 结论 8. 未来研究方向 大家好这里是AIWritePaper官方账号&#xff0c;官网&#x1f449;AIWrit…

19840 Dijkstra求最短路2

19840 Dijkstra求最短路2 相较于1&#xff0c;数据增强了&#xff0c;要用堆来优化&#xff0c;也就是优先队列。 ⭐️难度&#xff1a;中等 &#x1f31f;考点&#xff1a;Dijkstra、最短路问题 &#x1f4d6; &#x1f4da; import java.util.*;public class Main {static…

Redis-08.Redis常用命令-有序集合操作命令

一.有序集合操作命令 ZADD key score 1 member1 [score2 member2]&#xff1a; zadd zset 10.0 a 10.5 b ZRANGE key start stop [WITHSCORES]: zrange zset 0 -1 为何顺序为a&#xff0c;c&#xff0c;b&#xff1f; 因为 zrange zset 0 -1 withscores zrange key start …

LLaMA-Factory使用实战

LLaMA-Factory使用实战 项目介绍 项目地址&#xff1a;https://github.com/hiyouga/LLaMA-Factory 中文文档&#xff1a;安装 - LLaMA Factory 快速开始文档&#xff1a;https://zhuanlan.zhihu.com/p/695287607&#xff08;推荐参考&#xff09; 远程服务器通过本地代理加…

读一本书,骑行万里路:与维乐 Angel Rise+骑行看世界

最近读到了一本名为《自行车改变的世界&#xff1a;女性骑行的历史》的书&#xff0c;才发现原来女性的骑行自由来得并不轻易&#xff0c;激励着每一位女性勇敢地踏上骑行之路。而我一直在使用的维乐坐垫品牌&#xff0c;除了产品专业之外&#xff0c;也一直都非常关注女性骑行…

【大模型】SpringBoot整合LangChain4j实现RAG检索实战详解

目录 一、前言 二、LangChain4j 介绍 2.1 什么是LangChain4j 2.2 LangChain4j 主要特点 2.3 Langchain4j 核心组件 三、RAG介绍 3.1 什么是RAG 3.2 RAG工作流程 3.2.1 补充说明 3.3 Embedding模型 3.3.1 RAG实际使用步骤 3.3.2 什么是Embedding 3.3.3 Embedding 技…

流动的梦境:GPT-4o 的自回归图像生成深度解析

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

北大人工智能研究院朱松纯:“中国的AI叙事” 存在认知偏差

3月29日&#xff0c;在2025中关村论坛通用人工智能论坛上&#xff0c;北京通用人工智能学院院长&#xff0c;北京大学人工智能研究院、智能学院院长朱松纯表示&#xff0c;目前&#xff0c;行业对AI的讨论几乎被大模型能力所占据&#xff0c;而基础学科、原始创新与智能本质的研…

习题1.26

解释题&#xff0c;说简单也简单&#xff0c;难在如何表达清楚。 首先解释下代码的变化 (defn expmod[base exp m](cond ( exp 0) 1(even? exp) (mod (square (expmod base (/ exp 2) m)) m):else (mod (* base (expmod base (- exp 1) m)) m)))(defn expmod[base exp m](co…

FPGA调试笔记

XILINX SSTL属性电平报错 错误如下&#xff1a; [DRC BIVRU-1] Bank IO standard Vref utilization: Bank 33 contains ports that use a reference voltage. In order to use such standards in a bank that is not configured to use INTERNAL_VREF, the banks VREF pin mu…

基于Java(SSM)+Mysql实现移动大厅业务办理(增删改查)

基于 SSM 框架的移动业务大厅 数据库需要自行创建&#xff01; 一、 整体基本实现情况 对本学期的 Java 作业 1 的 SOSO 移动大厅进行改进&#xff0c; 基于 SSM、JSP、Maven、Tomcat、MySQL 等实现。 二、 实现详情 1、 工程结构图 2、 工程结构各部分实现 &#xff08;…

【字符设备驱动开发–IMX6ULL】(一)简介

【字符设备驱动开发–IMX6ULL】&#xff08;一&#xff09;简介 一、Linux驱动与裸机开发区别 1.裸机驱动开发回顾 ​ 1、底层&#xff0c;跟寄存器打交道&#xff0c;有些MCU提供了库。 spi.c&#xff1a;主机驱动&#xff08;换成任何一个设备之后只需要调用此文件里面的…

C++_STL之list篇

一、list的介绍 std::list是C标准模板库(STL)中的一个双向链表容器。与vector和deque不同&#xff0c;list不支持随机访问&#xff0c;但它在任何位置插入和删除元素都非常高效。 1.基本特性 (1)双向链表结构&#xff1a;每个元素都包含指向前驱和后继的指针 (2)非连续存储&…

Spring 声明式事务 万字详解(通俗易懂)

目录 Δ前言 一、声明式事务快速入门 1.为什么需要声明式事务&#xff1f; 2.定义&#xff1a; 3.应用实例&#xff1a; 二、声明式事务的传播机制 1.引出问题&#xff1a; 2.传播机制分类&#xff1a; 3.应用实例&#xff1a; 三、声明式事务的隔离机制 1.四种隔离级别&…

MySQL 当中的锁

MySQL 当中的锁 文章目录 MySQL 当中的锁MySQL 中有哪些主要类型的锁&#xff1f;请简要说明MySQL 的全局锁有什么用&#xff1f;MySQL 的表级锁有哪些&#xff1f;作用是什么&#xff1f;元数据锁&#xff08;MetaData Lock&#xff0c;MDL&#xff09;意向锁&#xff08;Inte…