Redis中的某一热点数据缓存过期了,此时有大量请求访问怎么办?

news2025/2/13 3:03:48

1、提前设置热点数据永不过期

2、分布式中用redis分布式锁(锁可以在多个 JVM 实例之间协调)、单体中用synchronized(锁只在同一个 JVM 内有效)

 编写服务类
import com.redisson.api.RLock;
import com.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class CacheService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    private static final String HOT_DATA_KEY = "hotData";
    private static final String LOCK_KEY = "hotDataLock";

    public String getHotData() {
        // 尝试从 Redis 中获取热点数据
        String hotData = redisTemplate.opsForValue().get(HOT_DATA_KEY);
        if (hotData == null) {
            // 获取分布式锁
            RLock lock = redissonClient.getLock(LOCK_KEY);
            try {
                // 尝试加锁,最多等待100ms,锁的过期时间为30秒
                if (lock.tryLock(100, 30, TimeUnit.SECONDS)) {
                    try {
                        // 再次检查缓存是否过期(双重检查)
                        hotData = redisTemplate.opsForValue().get(HOT_DATA_KEY);
                        if (hotData == null) {
                            // 缓存确实过期,从数据库加载数据
                            hotData = loadHotDataFromDatabase();
                            // 将数据存入 Redis,设置过期时间为10分钟
                            redisTemplate.opsForValue().set(HOT_DATA_KEY, hotData, 10, TimeUnit.MINUTES);
                        }
                    } finally {
                        // 释放锁
                        lock.unlock();
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        return hotData;
    }

    private String loadHotDataFromDatabase() {
        // 模拟从数据库加载数据
        return "Hot Data from Database";
    }
}
模拟多个请求
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
public class CacheTestRunner implements CommandLineRunner {

    @Autowired
    private CacheService cacheService;

    @Override
    public void run(String... args) throws Exception {
        // 模拟 10 个请求同时访问热点数据
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.submit(() -> {
                String hotData = cacheService.getHotData();
                System.out.println("Thread " + Thread.currentThread().getId() + " got hot data: " + hotData);
            });
        }
        executorService.shutdown();
    }
}

Thread 12 got hot data: Hot Data from Database
Thread 13 got hot data: Hot Data from Database
Thread 14 got hot data: Hot Data from Database
...

所有线程最终都会获取到相同的数据,但只有第一个线程会去加载数据,避免了缓存击穿问题。

单体应用

在单体应用中,所有请求都运行在同一个 JVM 实例中,因此可以使用 synchronized 来同步线程。

java复制

@Service
public class CacheService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String HOT_DATA_KEY = "hotData";
    private static final Object lock = new Object(); // 用于同步的锁对象

    public String getHotData() {
        // 尝试从 Redis 中获取热点数据
        String hotData = redisTemplate.opsForValue().get(HOT_DATA_KEY);
        if (hotData == null) {
            synchronized (lock) { // 使用 synchronized 同步
                // 再次检查缓存是否过期(双重检查)
                hotData = redisTemplate.opsForValue().get(HOT_DATA_KEY);
                if (hotData == null) {
                    // 缓存确实过期,从数据库加载数据
                    hotData = loadHotDataFromDatabase();
                    // 将数据存入 Redis,设置过期时间为10分钟
                    redisTemplate.opsForValue().set(HOT_DATA_KEY, hotData, 10, TimeUnit.MINUTES);
                }
            }
        }
        return hotData;
    }

    private String loadHotDataFromDatabase() {
        // 模拟从数据库加载数据
        return "Hot Data from Database";
    }
}

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

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

相关文章

自动化xpath定位元素(附几款浏览器xpath插件)

在 Web 自动化测试、数据采集、前端调试中&#xff0c;XPath 仍然是不可或缺的技能。虽然 CSS 选择器越来越强大&#xff0c;但面对复杂 DOM 结构时&#xff0c;XPath 仍然更具灵活性。因此&#xff0c;掌握 XPath&#xff0c;不仅能提高自动化测试的稳定性&#xff0c;还能在爬…

PromptSource官方文档翻译

目录 核心概念解析 提示模板&#xff08;Prompt Template&#xff09; P3数据集 安装指南 基础安装&#xff08;仅使用提示&#xff09; 开发环境安装&#xff08;需创建提示&#xff09; API使用详解 基本用法 子数据集处理 批量操作 提示创建流程 Web界面操作 手…

2025年软件测试五大趋势:AI、API安全、云测试等前沿实践

随着软件开发的不断进步&#xff0c;测试方法也在演变。企业需要紧跟新兴趋势&#xff0c;以提升软件质量、提高测试效率&#xff0c;并确保安全性&#xff0c;在竞争激烈的技术环境中保持领先地位。本文将深入探讨2025年最值得关注的五大软件测试趋势。 Parasoft下载https://…

js的DOM一遍过

一、获取元素 1.根据id获取 document.getElementById(id);2.根据标签名获取 使用 getElementsByTagName() 方法可以返回带有指定标签名的对象的集合。 document.getElementsByTagName(标签名);获取某个元素(父元素)内部所有指定标签名的子元素。 element.getElementsByTag…

Machine Learning:Introduction

文章目录 Machine LearningTrainingStep 1.Contract Function with Unknown ParametersStep 2.Define Loss from Training DataStep 3.Optimization Linear ModelPiecewise Linear CurveBeyond Piecewise Liner?FunctionLossOptimization Model Deformation Machine Learning …

Excel 笔记

实际问题记录 VBA脚本实现特殊的行转列 已知&#xff1a;位于同一Excel工作簿文件中的两个工作表&#xff1a;Sheet1、Sheet2。 问题&#xff1a;现要将Sheet2中的每一行&#xff0c;按Sheet1中的样子进行转置&#xff1a; Sheet2中每一行的黄色单元格&#xff0c;为列头。…

基于 GEE 利用插值方法填补缺失影像

目录 1 完整代码 2 运行结果 利用GEE合成NDVI时&#xff0c;如果研究区较大&#xff0c;一个月的影像覆盖不了整个研究区&#xff0c;就会有缺失的地方&#xff0c;还有就是去云之后&#xff0c;有云量的地区变成空值。 所以今天来用一种插值的方法来填补缺失的影像&#xf…

如何在浏览器中搭建开源Web操作系统Puter的本地与远程环境

文章目录 前言1.关于Puter2.本地部署Puter3.Puter简单使用4. 安装内网穿透5.配置puter公网地址6. 配置固定公网地址 前言 嘿&#xff0c;小伙伴们&#xff01;是不是每次开机都要像打地鼠一样不停地点击各种网盘和应用程序的登录按钮&#xff0c;感觉超级麻烦&#xff1f;更让…

使用EVE-NG-锐捷实现单臂路由

一、基础知识 1.三层vlan vlan在三层环境中通常用作网关vlan配上ip网关内部接口ip 2.vlan创建步骤 创建vlan将接口划分到不同的vlan给vlan配置ip地址 二、项目案例 1、项目拓扑 2、项目实现 PC1配置 配置PC1IP地址为192.168.1.10/24网关地址为192.168.1.1 ip 192.168.1…

二、通义灵码插件保姆级教学-IDEA(使用篇)

一、IntelliJ IDEA 中使用指南 1.1、代码解释 选择需要解释的代码 —> 右键 —> 通义灵码 —> 解释代码 解释代码很详细&#xff0c;感觉很强大有木有&#xff0c;关键还会生成流程图&#xff0c;对程序员理解业务非常有帮忙&#xff0c;基本能做到哪里不懂点哪里。…

HAL库外设宝典:基于CubeMX的STM32开发手册(持续更新)

目录 前言 GPIO&#xff08;通用输入输出引脚&#xff09; 推挽输出模式 浮空输入和上拉输入模式 GPIO其他模式以及内部电路原理 输出驱动器 输入驱动器 中断 外部中断&#xff08;EXTI&#xff09; 深入中断&#xff08;内部机制及原理&#xff09; 外部中断/事件控…

HarmonyOS 5.0应用开发——ContentSlot的使用

【高心星出品】 文章目录 ContentSlot的使用使用方法案例运行结果 完整代码 ContentSlot的使用 用于渲染并管理Native层使用C-API创建的组件同时也支持ArkTS创建的NodeContent对象。 支持混合模式开发&#xff0c;当容器是ArkTS组件&#xff0c;子组件在Native侧创建时&#…

[AI]Mac本地部署Deepseek R1模型 — — 保姆级教程

[AI]Mac本地部署DeepSeek R1模型 — — 保姆级教程 DeepSeek R1是中国AI初创公司深度求索&#xff08;DeepSeek&#xff09;推出大模型DeepSeek-R1。 作为一款开源模型&#xff0c;R1在数学、代码、自然语言推理等任务上的性能能够比肩OpenAI o1模型正式版&#xff0c;并采用MI…

群晖NAS如何通过WebDAV和内网穿透实现Joplin笔记远程同步

文章目录 前言1. 检查群晖Webdav 服务2. 本地局域网IP同步测试3. 群晖安装Cpolar工具4. 创建Webdav公网地址5. Joplin连接WebDav6. 固定Webdav公网地址7. 公网环境连接测试 前言 在数字化浪潮的推动下&#xff0c;笔记应用已成为我们记录生活、整理思绪的重要工具。Joplin&…

CSS3+动画

浏览器内核以及其前缀 css标准中各个属性都要经历从草案到推荐的过程&#xff0c;css3中的属性进展都不一样&#xff0c;浏览器厂商在标准尚未明确的情况下提前支持会有风险&#xff0c;浏览器厂商对新属性的支持情况也不同&#xff0c;所有会加厂商前缀加以区分。如果某个属性…

C++ list介绍

文章目录 1. list简介2. list的实现框架2.1 链表结点2.2 链表迭代器2.3 链表 3. list迭代器及反向迭代器设计3.1 list迭代器3.2 list反向迭代器3.3 list迭代器失效 4. list与vector比较 1. list简介 list&#xff0c;即链表。 链表的种类有很多&#xff0c;是否带头结点&#…

Java - 在Linux系统上使用OpenCV和Tesseract

系统环境 确保Linux系统安装了cmake构建工具&#xff0c;以及java和ant&#xff08;这两者如果没有&#xff0c;可能会影响到后面编译opencv生成.so和.jar文件&#xff09;。 sudo apt-get update sudo apt-get install build-essential sudo apt install cmake build-essen…

自有服务与软件包

—— 小 峰 编 程 目录 ​编辑 一、自有服务概述 二、systemctl管理服务命令 1、显示服务 2、查看启动和停止服务 3、服务持久化 三、常用自有服务&#xff08;ntp,firewalld,crond) 1、ntp时间同步服务 1&#xff09;NTP同步服务器原理 2&#xff09;到哪里去找NPT服务…

Python 鼠标轨迹 - 防止游戏检测

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…

chrome-mojo C++ Bindings API

概述 Mojo C 绑定 API 利用C 系统 API提供一组更自然的原语&#xff0c;用于通过 Mojo 消息管道进行通信。结合从Mojom IDL 和绑定生成器生成的代码&#xff0c;用户可以轻松地跨任意进程内和进程间边界连接接口客户端和实现。 本文档通过示例代码片段提供了绑定 API 用法的详…