Redis-预热雪崩击穿穿透

news2024/11/18 1:26:27

预热雪崩穿透击穿

缓存预热

缓存雪崩

有这两种原因

  1. redis key 永不过期or过期时间错开
  2. redis 缓存集群实现高可用
    1. 主从哨兵
    2. Redis Cluster
    3. 开启redis持久化aof,rdb,尽快恢复集群
  3. 多缓存结合预防雪崩:本地缓存 ehcache + redis 缓存
  4. 服务降级:Hystrix 或者 sentinel 限流降级
  5. 人民币玩家:阿里云给了你多少广告?笑

缓存穿透

恶意请求不存在的数据

  1. guava BloomFilter

  • 误判问题,但是概率小可以接受,不能从布隆过滤器删除 -> 布隆过滤器可能会错误地判断某个元素存在于集合中(称为误报),但不会错误地判断一个存在的元素不存在
  • 全部合法的key都需要放入 Guava布隆过滤器+redis里面,不然数据就是返回null

案例

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
</dependency>
@Service
@Slf4j
public class GuavaBloomFilterService {

    // 1.定义一个常量
    public static final int _1W = 10000;
    // 2.定义我们guava布隆过滤器,初始容量
    public static final int SIZE = 100 * _1W;
    // 3.误判率,它越小误判的个数也越少(思考:是否可以无限小? 没有误判岂不是更好)
    public static double fpp = 0.0000000000003;  // 这个数越小所用的hash函数越多,bitmap占用的位越多  默认的就是0.03,5个hash函数   0.01,7个函数
    // 4.创建guava布隆过滤器
    private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), SIZE, fpp);

    public void guavaBloomFilter() {
        // 1. 往 bloomFilter 中添加数据
        for (int i = 0; i < SIZE; i++) {
            bloomFilter.put(i);
        }
        // 2. 故意取10w个不在范围内的数据进行测试,来进行误判率演示
        List<Integer> list = new ArrayList<>(10 * _1W);

        // 3. 验证
        for (int i = SIZE; i < SIZE + (10 * _1W); i++) {
            if (bloomFilter.mightContain(i)) {
//                log.info("被误判了:{}", i);
                list.add(i);
            }
        }
        log.info("误判总数量:{}", list.size());
        log.info("误判率:{}", list.size() / (10 * _1W));
    }
}

@SpringBootTest
public class GuavaTest {

    @Resource
    GuavaBloomFilterService guavaBloomFilterService;

    /**
     * guava版本布隆过滤器,helloworld 入门级演示
     */
    @Test
    public void testGuavaWithBloomFilter() {
        System.out.println("testGuavaWithBloomFilter");
        // 1. 创建 guava版布隆过滤器
        BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 100);

        //2. 判断指定的元素是否存在
        System.out.println(bloomFilter.mightContain(1));
        System.out.println(bloomFilter.mightContain(2));

        // 2. 添加数据
        bloomFilter.put(1);
        bloomFilter.put(2);

        System.out.println(bloomFilter.mightContain(1));
        System.out.println(bloomFilter.mightContain(2));
    }

    @Test
    public void testGuavaWithBloomFilter2() {
        guavaBloomFilterService.guavaBloomFilter();
    }

}

fpp 默认 0.03

fpp要求越高,bit位数越多,hash函数越多

guava 黑名单使用

缓存击穿

对比穿透和击穿

互斥更新->对于更新的方法

聚划算案例

功能分析

数据结构使用 list

代码

@ApiModel(value = "聚划算活动product信息")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Product {
    // 产品id
    private Long id;
    // 产品名称
    private String name;
    // 产品价格
    private Integer price;
    // 产品详情
    private String detail;
}
@Service
@Slf4j
public class JHSTaskService {

    private static final String JHS_KEY = "jhs";
    private static final String JHS_KEY_A = "jhs:a";
    private static final String JHS_KEY_B = "jhs:b";

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 模拟从数据库读取20件特价商品
     * @return 商品列表
     */
    private List<Product> getProductsFromMysql() {
        List<Product> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            Random random = new Random();
            int id = random.nextInt(1000);
            Product product = new Product((long) id, "product" + i, i, "detail");
            list.add(product);
        }
        log.info("模拟从数据库读取20件特价商品完成{}", list);
        return list;
    }

    @PostConstruct
    public void initJHSAB() {
        log.info("启动AB的定时器 天猫聚划算模拟开始===========");
        new Thread(() -> {
            while (true) {
                // 2.模拟从mysql查到数据,加到 redis 并返回给页面
                List<Product> list = getProductsFromMysql();

                redisTemplate.delete(JHS_KEY);
                redisTemplate.opsForList().leftPushAll(JHS_KEY, list);
                redisTemplate.expire(JHS_KEY, 86410L, TimeUnit.SECONDS);


                // 5.暂停一分钟,间隔1分钟执行一次,模拟聚划算一天执行的参加活动的品牌
                try {
                    Thread.sleep(1000* 60);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "t1").start();
    }

}

测试类

@SpringBootTest
@Slf4j
public class JhsTest {

    private static final String JHS_KEY = "jhs";
    private static final String JHS_KEY_A = "jhs:a";
    private static final String JHS_KEY_B = "jhs:b";

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void find() {
        int page = 1;
        int size = 10;

        List<Product> list = null;

        long start = (page - 1) * size;
        long end = start + size - 1;

        try {
            list = redisTemplate.opsForList().range(JHS_KEY, start, end);

            if (CollectionUtils.isEmpty(list)) {
                // TODO 走 mysql 查询
            }

            log.info("参加活动的商家={}", list);
        } catch (Exception e) {
            // 出异常了,一般 redis 宕机了或者redis网络抖动导致timeout
            log.error("jhs exception{}", e);
            e.printStackTrace();
            //  ..... 重试机制 再次查询 mysql
        }

        log.info(list.toString());

    }

}

测试方法,先跑主启动类(后台更新聚划算商品信息),然后手动执行测试类测试查询

问题分析

delete 执行间隙,这一瞬间缓存击穿,打到mysql

解决

@PostConstruct
    public void initJHSAB() {
        log.info("启动AB的定时器 天猫聚划算模拟开始===========");
        new Thread(() -> {
            while (true) {
                // 2.模拟从mysql查到数据,加到 redis 并返回给页面
                List<Product> list = getProductsFromMysql();

//                redisTemplate.delete(JHS_KEY);
//                redisTemplate.opsForList().leftPushAll(JHS_KEY, list);
//                redisTemplate.expire(JHS_KEY, 86410L, TimeUnit.SECONDS);

                // 3.先更新B缓存并且让B缓存过期时间超过A时间,如果A突然失效了还有B兜底,防止击穿
                redisTemplate.delete(JHS_KEY_B);
                redisTemplate.opsForList().leftPushAll(JHS_KEY_B, list);
                redisTemplate.expire(JHS_KEY_B, 86410L, TimeUnit.SECONDS);

                // 4.再更新A缓存
                redisTemplate.delete(JHS_KEY_A);
                redisTemplate.opsForList().leftPushAll(JHS_KEY_A, list);
                redisTemplate.expire(JHS_KEY_A, 86400L, TimeUnit.SECONDS);

                // 5.暂停一分钟,间隔1分钟执行一次,模拟聚划算一天执行的参加活动的品牌
                try {
                    Thread.sleep(1000* 60);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "t1").start();
    }
@Test
    public void findAB() {
        int page = 1;
        int size = 10;

        List<Product> list = null;

        long start = (page - 1) * size;
        long end = start + size - 1;

        try {
            list = redisTemplate.opsForList().range(JHS_KEY_A, start, end);

            if (CollectionUtils.isEmpty(list)) {
                log.info("---------A缓存已经过期或活动结束了,记得人工修补,B缓存继续顶着");

                // A 没有来找 B
                list = redisTemplate.opsForList().range(JHS_KEY_B, start, end);

                if (CollectionUtils.isEmpty(list)) {
                    // TODO 走 mysql 查询
                }
            }

            log.info("参加活动的商家={}", list);
        } catch (Exception e) {
            // 出异常了,一般 redis 宕机了或者redis网络抖动导致timeout
            log.error("jhs exception{}", e);
            e.printStackTrace();
            //  ..... 重试机制 再次查询 mysql
        }

        log.info(list.toString());

    }

小总结

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

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

相关文章

iPhone/iPad技巧:如何解锁锁定的 iPhone 或 iPad

“在我更新 iPhone 上的软件后&#xff0c;最近我遇到了iPhone 被锁定到所有者的消息&#xff0c;该如何解决&#xff1f;” 根据我们的研究&#xff0c;许多用户在 iOS 18 更新或恢复出厂设置后都会遇到同样的问题。只要出现问题&#xff0c;您就无法使用 iPhone 或 第 1 部分…

jenkins微服务

如果vim进去某个文件里&#xff0c;可以按键盘的向下键查阅其它部分 记得每天备份虚拟机的项目 一.在linux安装jenkins 1.上传文件 我们采用安装包的方式安装。 先用SShclient在/usr/local/下创建jenkins文件夹&#xff0c;然后向其中导入两个包 2.安装jenkins 再在控制…

「STL::queue」标准库适配器:priority_queue(优先队列)介绍|自定义比较运算(C++)

目录 概述 创建销毁 内部理解 构造析构 自定义比较 赋值重构 数据访问 内存管理 数据控制 Tips 概述 priority_queue 是一种C标准模板库STL中定义的一种序列容器&#xff0c;它允许你在运行时动态地进行堆操作。 priority_queue 可以自动管理内存&#xff0c;这意味…

使用阿里云试用资源快速部署web应用-dofaker为例

本文介绍使用阿里云的试用资源部署dofaker的方法&#xff0c;本教程主要作学习在阿里云部署web应用之用&#xff0c;部署好应用之后&#xff0c;可以在任何地点通过公网ip访问web应用。 一、创建云主机 登录阿里云账户之后&#xff0c;点击控制台&#xff1a; 点击云服务器EC…

基于SSM的大学生心理素质测评及咨询平台系统设计与实现(源码+定制+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

vscode中配置python虚拟环境

python虚拟环境作用 Python虚拟环境允许你为每个独立的项目创建一个隔离的环境&#xff0c;这样每个项目都可以拥有自己的一套Python安装包和依赖&#xff0c;不会互相影响。实际使用中&#xff0c;可以在vscode或pycharm中使用虚拟环境。 1.创建虚拟环境的方法&#xff1a; …

天呐!关于PyCharm你竟然一无所知?

PyCharm 是一种专为 Python 开发而设计的集成开发环境&#xff08;IDE&#xff09;&#xff0c;由 JetBrains 开发。 以下是 PyCharm 的一些主要特点和常见的使用方法&#xff1a; 特点&#xff1a; 智能代码编辑&#xff1a;具有智能代码补全、语法检查、代码重构等功能&…

HISTCITE分析进阶

不可否认histcite是一个很好的文献分析的工具,他能很好的找到最重要的那几篇文章,同时也能找到研究的发文趋势、研究机构和著名的研究学者等。但是它是一个很老的软件,因而很多东西都没能跟上下载的分析。我在使用过程中,尝试做一些改变使其更好用,同时也做一些记录。 1.…

ROS学习笔记(三):VSCode集成开发环境快速安装,以及常用扩展插件配置

文章目录 前言VSCode集成开发环境1 安装VSCode2 VSCode扩展插件2.1 VSCode扩展插件模块介绍2.1 常用扩展插件配置一、语言支持类插件二、智能辅助类插件三、科学计算与数据分析类插件四、ROS开发相关插件 3 总结相关链接 前言 关于Ubuntu与ROS的常规安装&#xff0c;可以看这几…

数字经济与新质生产力:地理信息与遥感视角下的深度分析

在数字化浪潮的推动下&#xff0c;我们正见证着生产力的一次历史性飞跃。数字经济如何重塑生产力的三大要素&#xff1a;劳动对象、劳动资料和劳动者&#xff1f;让我们来深度分析数字经济如何推动新质生产力的发展。 一、数字经济与地理信息的融合 地理信息与遥感技术是数字…

如何在 Windows 10 上恢复未保存/删除的 Word 文档

您是否整夜都在处理重要的 word 文件&#xff0c;但忘记保存它&#xff1f;这篇文章是给你的。在这里&#xff0c;我们将解释如何恢复未保存的 word 文档。除此之外&#xff0c;您还将学习如何恢复已删除的 word 文档。 从专业人士到高中生&#xff0c;每个人都了解丢失重要 W…

【Android 14源码分析】WMS-窗口显示-流程概览与应用端流程分析

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

资源《Arduino 扩展板1-LED灯》说明。

资源链接&#xff1a;Arduino 扩展板1-LED灯 1.文件明细&#xff1a; 2.文件内容说明 包含&#xff1a;AD工程、原理图、PCB。 3.内容展示 4.简述 该文件为PCB工程&#xff0c;采用AD做的。 该文件打板后配合Arduino使用&#xff0c;属于Arduino的扩展板。 该文件主要有…

Pytorch实现RNN实验

一、实验要求 用 Pytorch 模块的 RNN 实现生成唐诗。要求给定一个字能够生成一首唐诗。 二、实验目的 理解循环神经网络&#xff08;RNN&#xff09;的基本原理&#xff1a;通过构建一个基于RNN的诗歌生成模型&#xff0c;学会RNN是如何处理序列数据的&#xff0c;以及如何在…

计算机毕业设计Spark+PyTorch股票预测系统 股票推荐系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI

《SparkPyTorch股票预测系统》开题报告 一、研究背景与意义 随着信息技术的飞速发展和全球金融市场的日益繁荣&#xff0c;股票投资已成为广大投资者的重要选择之一。然而&#xff0c;股票市场的复杂性和不确定性使得投资者在做出投资决策时面临巨大的挑战。传统的股票分析方…

防sql注入的网站登录系统设计与实现

课程名称 网络安全 大作业名称 防sql注入的网站登录系统设计与实现 姓名 学号 班级 大 作 业 要 求 结合mysql数据库设计一个web登录页面密码需密文存放&#xff08;可以采用hash方式&#xff0c;建议用sha1或md5加盐&#xff09;采用服务器端的验证码&#…

今天推荐一个文档管理系统 Dorisoy.Pan

Dorisoy.Pan 是一个基于 .NET 8 和 WebAPI 构建的文档管理系统&#xff0c;它集成了 Autofac、MediatR、JWT、EF Core、MySQL 8.0 和 SQL Server 等技术&#xff0c;以实现一个简单、高性能、稳定且安全的解决方案。 这个系统支持多种客户端&#xff0c;包括网站、Android、iO…

PID控制原理:看下这三个故事,你就明白了

一、PID的故事 小明接到这样一个任务&#xff1a;有一个水缸点漏水(而且漏水的速度还不一定固定不变)&#xff0c;要求水面高度维持在某个位置&#xff0c;一旦发现水面高度低于要求位置&#xff0c;就要往水缸里加水。 小明接到任务后就一直守在水缸旁边&#xff0c;时间长就觉…

Python | Leetcode Python题解之第450题删除二叉搜索树中的节点

题目&#xff1a; 题解&#xff1a; class Solution:def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:cur, curParent root, Nonewhile cur and cur.val ! key:curParent curcur cur.left if cur.val > key else cur.rightif cur i…

Linux学习笔记(四):组与权限、任务调度、磁盘管理、网络配置、进程管理

Linux学习笔记&#xff08;四&#xff09;&#xff1a;组与权限、任务调度、磁盘管理、网络配置、进程管理 1. 组与权限 1.1 文件所有者 查看文件所有者&#xff1a; 使用 ls -ahl 或 ll 命令可以查看文件的详细信息&#xff0c;其中包括文件所有者。 修改文件所有者&…