Redis常见缓存问题

目录

缓存穿透

造成缓存穿透的原因

缓存穿透问题解决方案

1、缓存空对象返回

2、布隆过滤器

缓存失效(击穿)

缓存雪崩

热点缓存key重建优化

缓存与数据库双写不一致

1、双写不一致情况

2、读写并发不一致

解决方案


缓存穿透

        缓存穿透是指查询一个根本不存在的数据, 缓存层和存储层都不会命中, 通常出于容错的考虑, 如果从存储层查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次请求都要到存储层去查询, 失去了缓存保护后端存储的意义。

造成缓存穿透的原因

1. 自身业务代码或者数据出现问题。

2.  一些恶意攻击、 爬虫等造成大量空命中。

缓存穿透问题解决方案
1、缓存空对象返回
String get(String key) {
    // 从缓存中获取数据
    String cacheValue = cache.get(key);
    // 缓存为空
    if (StringUtils.isBlank(cacheValue)) {
        // 从存储中获取
        String storageValue = storage.get(key);
        cache.set(key, storageValue);
        // 如果存储数据为空, 需要设置一个过期时间(300秒)
        if (storageValue == null) {
            cache.expire(key, 60 * 5);
        }
        return storageValue;
    } else {
        // 缓存非空
        return cacheValue;
    }
}
2、布隆过滤器

       对于恶意攻击,向服务器请求大量不存在的数据造成的缓存穿透,可以用布隆过滤器先做一次过滤,对于不存在的数据布隆过滤器一般都能够过滤掉,不让请求再往后端发送。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。

       向布隆过滤器中添加key时,会使用多个hash函数对key进行hash算得一个整数索引值然后对位数组长度进行取模运算得到一个位置,每个hash函数都会算得一个不同的位置。再把位数组的这几个位置都置为1就完成了add操作。

        向布隆过滤器询问key是否存在时,跟add一样,也会把hash的几个位置都算出来,看看位数组中这几个位置是否都为1,只要有一个位为0,那么说明布隆过滤器中这个key不存在。如果都是 1,这并不能说明这个key就一定存在,只是极有可能存在,因为这些位被置为1可能是因为其它的 key存在所致。如果这个位数组长度比较大,存在概率就会很大,如果这个位数组长度比较小,存在概率就会降低。

         这种方法适用于数据命中不高、 数据相对固定、 实时性低(通常是数据集较大) 的应用场景, 代码维护较为复杂, 但是缓存空间占用很少。

redisson实现布隆过滤器,引入依赖

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.6.5</version>
</dependency>
package com.redisson;

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

public class RedissonBloomFilter {

    public static void main(String[] args) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        //构造Redisson
        RedissonClient redisson = Redisson.create(config);

        RBloomFilter<String> bloomFilter = redisson.getBloomFilter("bFileter");
        //初始化布隆过滤器:预计元素为100000000L,误差率为3%,根据这两个参数会计算出底层的bit数组大小
        bloomFilter.tryInit(100000000L,0.03);
        //将zhuge插入到布隆过滤器中
        bloomFilter.add("zhangsan");

        //判断下面号码是否在布隆过滤器中
        System.out.println(bloomFilter.contains("lisi"));//false
        System.out.println(bloomFilter.contains("wangwu"));//false
        System.out.println(bloomFilter.contains("zhangsan"));//true
    }
}

        使用布隆过滤器需要把所有数据提前放入布隆过滤器,并且在增加数据时也要往布隆过滤器里放,布隆过滤器缓存过滤伪代码:

//初始化布隆过滤器
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("bFileter");
//初始化布隆过滤器:预计元素为100000000L,误差率为3%
bloomFilter.tryInit(100000000L,0.03);
        
//把所有数据存入布隆过滤器
void init(){
    for (String key: keys) {
        bloomFilter.put(key);
    }
}

String get(String key) {
    // 从布隆过滤器这一级缓存判断下key是否存在
    Boolean exist = bloomFilter.contains(key);
    if(!exist){
        return "";
    }
    // 从缓存中获取数据
    String cacheValue = cache.get(key);
    // 缓存为空
    if (StringUtils.isBlank(cacheValue)) {
        // 从存储中获取
        String storageValue = storage.get(key);
        cache.set(key, storageValue);
        // 如果存储数据为空, 需要设置一个过期时间(300秒)
        if (storageValue == null) {
            cache.expire(key, 60 * 5);
        }
        return storageValue;
    } else {
        // 缓存非空
        return cacheValue;
    }
}

注意:布隆过滤器不能删除数据,如果要删除得重新初始化数据。


缓存失效(击穿)

       由于大批量缓存在同一时间失效可能导致大量请求同时穿透缓存直达数据库,可能会造成数据库瞬间压力过大甚至挂掉,对于这种情况我们在批量增加缓存时最好将这一批数据的缓存过期时间设置为一个时间段内的不同时间。

String get(String key) {
    // 从缓存中获取数据
    String cacheValue = cache.get(key);
    // 缓存为空
    if (StringUtils.isBlank(cacheValue)) {
        // 从存储中获取
        String storageValue = storage.get(key);
        cache.set(key, storageValue);
        //设置一个过期时间(300到600之间的一个随机数)
        int expireTime = new Random().nextInt(300)  + 300;
        if (storageValue == null) {
            cache.expire(key, expireTime);
        }
        return storageValue;
    } else {
        // 缓存非空
        return cacheValue;
    }
}

缓存雪崩

       缓存雪崩指的是缓存层支撑不住或宕掉后, 流量会像奔逃的野牛一样, 打向后端存储层。由于缓存层承载着大量请求, 有效地保护了存储层, 但是如果缓存层由于某些原因不能提供服务(比如超大并发过来,缓存层支撑不住,或者由于缓存设计不好,类似大量请求访问bigkey,导致缓存能支撑的并发急剧下降), 于是大量请求都会打到存储层, 存储层的调用量会暴增, 造成存储层也会级联宕机的情况。

预防和解决缓存雪崩问题

1. 保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cluster。

2. 依赖隔离组件为后端限流熔断并降级。比如使用Sentinel或Hystrix限流降级组件。

3. 在项目上线前,充足测试,在此基础上做一些预案设定。


热点缓存key重建优化

String get(String key) {
    // 从Redis中获取数据
    String value = redis.get(key);
    // 如果value为空, 则开始重构缓存
    if (value == null) {
        // 只允许一个线程重建缓存, 使用nx, 并设置过期时间ex
        String mutexKey = "mutext:key:" + key;
        if (redis.set(mutexKey, "1", "ex 180", "nx")) {
             // 从数据源获取数据
            value = db.get(key);
            // 回写Redis, 并设置过期时间
            redis.setex(key, timeout, value);
            // 删除key_mutex
            redis.delete(mutexKey);
        }// 其他线程休息50毫秒后重试
        else {
            Thread.sleep(50);
            get(key);
        }
    }
    return value;
}

        利用互斥锁来解决,此方法只允许一个线程重建缓存, 其他线程等待重建缓存的线程执行完, 重新从缓存获取数据即可。

缓存与数据库双写不一致

1、双写不一致情况

                                

2、读写并发不一致

                      

解决方案

1、并发几率很小的数据(如个人维度的订单数据、用户数据等),这种几乎不用考虑这个问题,很少会发生缓存不一致,可以给缓存数据加上过期时间,每隔一段时间触发读的主动更新即可。

2、并发很高,如果业务上能容忍短时间的缓存数据不一致(如商品名称,商品分类菜单等),缓存加上过期时间依然可以解决大部分业务对于缓存的要求。

3、如果不能容忍缓存数据不一致,可以通过加分布式读写锁(Redisson)保证并发读写或写写的时候按顺序排好队,读读的时候相当于无锁。

4、可以用阿里开源的canal通过监听数据库的binlog日志及时的去修改缓存,但是引入了新的中间件,增加了系统的复杂度。

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

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

相关文章

通过代理如何调通openai的api

调通openai的api 一、前提二、通过curl调通openai的api三、通过python调通openai的api 一、前提 会魔法上网本地运行代理软件&#xff0c;知道端口号&#xff08;如1081&#xff09;。 127.0.0.1:1081二、通过curl调通openai的api 如果在国外&#xff0c;没有qiang&#xff…

AI大模型开发架构设计(3)——如何打造自己的大模型

文章目录 如何打造自己的大模型1 新时代职场人应用AIGC的5重境界2 人人需要掌握的大模型原理职场人都能听懂的大语音模型的训练过程职场人都能听得懂的大语言模型的Transformer推理过程 3 如何构建自己的大模型需要具备三个方面的能力LangChain是什么&#xff1f;LangChain主要…

【音视频】基于ffmpeg对视频的切割/合成/推流

背景 基于FFmpeg对视频进行切割、合成和推流的价值和意义在于它提供了一种高效、灵活且免费的方式来实现视频内容的定制、管理和分发。通过FFmpeg&#xff0c;用户可以轻松地剪辑视频片段&#xff0c;根据需要去除不必要的部分或提取特定时间段的内容&#xff0c;从而优化观看…

【数据库原理】(37)Web与数据库

随着网络的高速发展和网络服务的日趋完善&#xff0c;网络上的信息量呈几何级数增长。为了有效地组织、存储、管理和使用网上的信息&#xff0c;数据库技术被广泛地应用于网络领域。特别是在Internet上&#xff0c;已建立了数以万计的网站&#xff0c;其中大中型网站的后台大多…

链表中倒数第k个结点(附带源码)

目录 代码部分&#xff1a; 核心&#xff1a;看图 代码部分&#xff1a; struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {// write code here// write code hereif (k 0){return NULL;}else{struct ListNode* slow pListHead, * fast pListHead;//…

一个非常流行的R语言调色板:RColorBrewer

R 语言有许多非常优秀的调色板&#xff0c;本文就介绍一个非常流行的&#xff0c;我也经常在用的调色板 R 包&#xff1a;RColorBrewer。 安装 install.packages("RColorBrewer") 加载 library(RColorBrewer) library(knitr) 初探 ?RColorBrewer 在帮助页面可以看到…

雨云VPS使用我的世界整合包开服教程,Pokehaan Craft 2整合包服务器搭建教程

Minecraft整合包服务器搭建教程&#xff0c;宝可梦/神奇宝贝整合包&#xff08;Pokehaan Craft 2&#xff09;开服教程。 其他整合包也可以参考此教程。要看这个整合包的游戏截图可以翻到文章最底下。 5分钟免费开一个MC服&#xff01;雨云免费服务器领取教程&我的世界开…

开源项目盘点-学习类

1&#xff0c;freeCodeCamp 地址&#xff1a;https://github.com/freeCodeCamp/freeCodeCamp 描述&#xff1a;一个程序员学习网站&#xff0c;里面有全栈开发、机器学习的相关知识&#xff0c;是完全免费的&#xff0c;该网站有上千道编码挑战题来帮助你来练习你的技能。 提…

springboot集成easypoi

easypoi,主打的功能就是容易,通过简单的配置&#xff0c;就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出 pom导入依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-star…

9.4 Lambda表达式

9.4 Lambda表达式 1 Lambda语法2. 基于Lambda实现函数式编程3. Stream流式处理 1 Lambda语法 2. 基于Lambda实现函数式编程 3. Stream流式处理

各分地域如果流量大的情况下 使用什么组网方式最好?V批N还是SDWAN或者其他?

环境&#xff1a; V批N SDWAN MPLS 问题描述&#xff1a; 各分地域如果流量大的情况下 使用什么组网方式最好&#xff1f;V批N还是sdwan或者其他&#xff1f; 解决方案&#xff1a; 当各地域之间的流量较大时&#xff0c;选择合适的组网方式可以提供更好的网络性能和可靠…

快速玩转 Mixtral 8x7B MOE大模型!阿里云机器学习 PAI 推出最佳实践

作者&#xff1a;熊兮、贺弘、临在 Mixtral 8x7B大模型是Mixtral AI推出的基于decoder-only架构的稀疏专家混合网络&#xff08;Mixture-Of-Experts&#xff0c;MOE&#xff09;开源大语言模型。这一模型具有46.7B的总参数量&#xff0c;对于每个token&#xff0c;路由器网络选…

【数据结构初阶】——顺序表

本文由睡觉待开机原创&#xff0c;转载请注明出处。 本内容在csdn网站首发 欢迎各位点赞—评论—收藏 如果存在不足之处请评论留言&#xff0c;共同进步&#xff01; 这里写目录标题 1.数据结构2.顺序表线性表顺序表的结构 3.动态顺序表的实现 1.数据结构 数据结构的概念&…

2024年【中级消防设施操作员(考前冲刺)】考试题库及中级消防设施操作员(考前冲刺)免费试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 中级消防设施操作员&#xff08;考前冲刺&#xff09;考试题库参考答案及中级消防设施操作员&#xff08;考前冲刺&#xff09;考试试题解析是安全生产模拟考试一点通题库老师及中级消防设施操作员&#xff08;考前冲…

外呼机器人有什么优势?

外呼机器人有什么优势&#xff1f;值得受到大多数电销企业的追捧&#xff01; 1、电话外呼效率高&#xff1a; 每天可拨打的电话数量是人工的5-10倍&#xff0c;人工一天只能拨打200-300通电话&#xff0c;机器人每天能打3000通电话以上&#xff0c;无须休息&#xff0c;按照…

洛谷P1161 开灯

这倒也是水题&#xff0c;我们可以建立一个数组&#xff0c;数组的下标就是编号&#xff0c;我们要注意的是浮点数乘法的结果要转化成整数&#xff0c;才能当做下标&#xff0c;因为题目给的是整数编号。 # include <stdio.h> int main() {int a[1000000] { 0 }, n, t,…

使用定时器外设的输入捕捉功能及测量脉冲宽度

使用定时器外设的输入捕捉功能及测量脉冲宽度 文章目录 使用定时器外设的输入捕捉功能及测量脉冲宽度Introduction硬件定时器外设输入捕获功能的机制使用两个通道&#xff08;引脚&#xff09;的单边沿触发输入捕获使用单通道&#xff08;引脚&#xff09;的双边沿触发输入捕获…

16.5 参考文献——深度学习定位

16.5 一种高效鲁棒的多楼层室内环境指纹定位方法 同济大学 Zhao Y, Gong W, Li L, et al. An Efficient and Robust Fingerprint Based Localization Method for Multi Floor Indoor Environment[J]. IEEEa Internet of Things Journal, 2023. 2.相关工作 B.基于深度学习的…

SAI实例研究

实例1 creature.id 15937&#xff08;smart_script.entryorguid&#xff09;的SAI设置&#xff1a; 第1条(id 0&#xff09; 当 creature 进入战斗后&#xff08;event_type 0&#xff09;&#xff0c;creature 对当前目标&#xff08;target_type 2&#xff09;周期性施…

VS里那些实用的调试(debug)技巧

前言——————希望现在在努力的各位都能感动以后享受成功的自己&#xff01; 首先我们要来了解什么是bug——————bug本意是“昆虫”或“虫子”&#xff0c;现在⼀般是指在电脑系统或程序中&#xff0c;隐藏着的⼀些未被发现的缺陷或 问题&#xff0c;简称程序漏洞。 “…