缓存雪崩、击穿、穿透及解决方案_保证缓存和数据库一致性

文章目录

  • 缓存雪崩、击穿、穿透
    • 1.缓存雪崩
      • 造成缓存雪崩
        • 解决缓存雪崩
    • 2. 缓存击穿
      • 造成缓存击穿
      • 解决缓存击穿
    • 3.缓存穿透
      • 造成缓存穿透
      • 解决缓存穿透
  • 更新数据时,如何保证数据库和缓存的一致性?
    • 1. 先更新数据库?先更新缓存?
      • 解决方案
    • 2. Cache Aside策略
      • ① 先更新数据库,再删除缓存
        • 保证更新数据库、删除缓存都执行成功
      • ② 先删除缓存,再更新数据库
        • 解决方案

在这里插入图片描述

缓存雪崩、击穿、穿透

一般用户数据存储于磁盘,读写速度慢。

使用redis作为缓存,相当于数据缓存在内存,大大提高系统性能

redis作为缓存,就会有缓存异常的三个问题

1.缓存雪崩

在这里插入图片描述

缓存都设置了过期时间

造成缓存雪崩

  • 大量缓存数据在同一时间过期

  • redis故障宕机

    若此时有大量用户请求,无法在redis处理,都直接访问数据库 => 数据库压力骤增(严重造成数据库宕机) => 形成一系列连锁反应 => 整个系统崩溃

解决缓存雪崩

=> 大量缓存数据在同一时间过期时:

  1. 均匀设置过期时间(对缓存数据的过期时间加上随机数,保证数据不会在同一时间过期)

  2. 互斥锁(当业务线程在处理用户请求时,如果发现访问的数据不在redis里,加互斥锁,保证同一时间内只有一个请求来构建缓存(从数据库读取数据,再将数据更新到redis),当缓存构建完成后,再释放锁。)
    注:互斥锁设置超时时间,否则若出现请求发生意外阻塞,导致其他请求也一直拿不到锁

  3. 后台更新缓存(让缓存“永久有效”,将更新缓存的工作交由后台线程定时更新)
    当系统内存紧张时,有些缓存数据被“淘汰”,在“淘汰”和下次更新时间内,业务线程读取失败就以为是数据丢失,解决方法:

    1. 后台线程负责定时更新缓存,同时频繁地检测缓存是否失效,若失效,可进行构建缓存

      ​ 检测时间间隔不能太长,太长导致用户获取的数据是空值而不是真正的数据,检测时间间隔最好是毫秒级,用户体验一般

    2. 业务线程发现缓存数据失效后,通过消息队列发送一条消息通知后台线程更新缓存。后台线程收到消息后,更新前判断缓存是否存在,不存在则进行构建缓存。

      ​ 缓存更新及时,用户体验好

    **注:**后台更新缓存机制适合进行缓存预热(业务刚上线时,提前缓存数据,不是等待用户访问才来触发缓存构建)

=> Redis故障宕机时:

  1. 服务熔断或请求限流机制

    ​ 服务熔断:暂停业务应用对缓存服务的访问,直接返回错误,不再继续访问数据库,直到redis恢复正常。

    ​ 请求限流机制:只将少部分请求发送到数据库进行处理,再多的请求就在入口直接拒绝服务,等到Redis恢复正常 并把缓存预热完后。

  2. 构建redis缓存高可靠集群

    ​ 通过主从节点的方式构建,若redis缓存的主节点宕机,从节点可以切换成为主节点,继续提供缓存服务

2. 缓存击穿

造成缓存击穿

被频繁访问的热点数据过期,此时大量的请求访问该热点数据,直接访问数据库,数据库很容易被高并发的请求冲垮

缓存击穿可以认为是缓存雪崩的一个子集(对应于大量缓存数据在同一时间过期)

解决缓存击穿

  1. 互斥锁
  2. 不给热点数据设置过期时间,由后台异步更新缓存 / 在热点数据准备过期前,提前通知后台线程更新缓存以及重新设置过期时间

3.缓存穿透

对于缓存雪崩、击穿,数据仍然在数据库,一旦缓存恢复相应的数据,就可以减轻数据库的压力

而对于缓存穿透:

​ 用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库,发现数据库也没有要访问的数据,没办法构建缓存来服务后续请求。当有大量的这样的请求时,数据库的压力骤增

造成缓存穿透

  • 业务误操作,缓存中数据和数据库数据都被误删除
  • 黑客恶意攻击,故意大量访问某些读取不存在数据的业务

解决缓存穿透

  1. 非法请求的限制

    判断请求参数是否含有非法值?请求字段是否存在?

  2. 缓存空值或默认值

    当线上业务发现缓存穿透时,针对查询的数据,在缓存中设置一个空值或默认值,后续请求可以从缓存中读取到数据,而不会继续查询数据库

  3. 使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在。

    写入数据库数据时,使用布隆过滤器做标记,当业务线程确认缓存失效后,可以通过查询布隆过滤器判断数据是否存在。(大量请求只会查询布隆过滤器和redis,而不会查询数据库)

注:布隆过滤器的实现

在这里插入图片描述

设此时有3个哈希函数,位图数组长度为8,数据库写入数据x:

将该数据x得到的三个哈希值 % 位图数据长度得到三个数组下标,填入1。

当业务线程查询数据是否存在于数据库时,查询 1、4、6下标的值是否为1,若有一个为0,则说明不存在

(存在哈希冲突,故若查询布隆过滤器说数据存在于数据库,此时数据不一定在数据库;但是查询到数据不存在时,数据一定不存在)

在这里插入图片描述
在这里插入图片描述

更新数据时,如何保证数据库和缓存的一致性?

1. 先更新数据库?先更新缓存?

在数据更新时,先更新数据库还是先更新缓存,都会存在并发问题,当两个请求并发更新同一条数据时,可能会出现缓存和数据库中数据不一致的现象。

解决方案

  • 更新缓存之前加分布式锁,保证同一时间只运行一个请求更新缓存,但对写入性能造成影响
  • 更新完缓存后,给缓存加上较短的过期时间,即使不一致,但也会很快过期

2. Cache Aside策略

旁路缓存策略: 在更新数据时,不更新缓存,更新数据库,删除缓存, 当读取数据发现缓存中无该数据时,再从数据库中读取数据,并且写入缓存。

(删除缓存,不更新缓存是懒加载思想的应用)

分为读策略、写策略

  • 写策略
    • 更新数据库中的数据
    • 删除缓存中的数据
  • 读策略
    • 若读取的数据命中缓存,则直接返回数据
    • 若读取的数据没有命中缓存,则从数据库中读取数据,再将该数据写入缓存,并且返回给用户

例:请求A读取数据,请求B更新数据

在这里插入图片描述

此时数据库中为21,缓存中为20

该情况出现概率不高,因为缓存的写入通常远远快于数据库的写入

① 先更新数据库,再删除缓存

先更新数据库,再删除缓存 可以保证“数据一致性”,并且对缓存加上过期时间,可以保证最终一致性

问题:

  • 先更新数据库,再删除缓存会导致缓存命中率降低。

    ​ 若对缓存命中率有要求,可以采用更新数据库+更新缓存,解决方案见1.

  • 这种方法保证数据一致性的前提是 更新数据库和删除缓存都能正常执行成功。

    (删除缓存失败时,可能出现缓存中为旧数据,数据库中为新数据)

    保证更新数据库、删除缓存都执行成功

    采用异步缓存,保证第二个操作执行成功

    • 重试机制 => 引入消息队列,将删除缓存操作的数据加入消息队列,由消费者操作数据
      • 如果删除缓存失败,从消息队列重新读取需要删除的数据,再次删除缓存(若多次删除失败,需要向业务层发送报错信息)
      • 如果删除缓存成功,把数据从消息队列移除,避免重复操作
    • 订阅 MySQL binlog,再操作缓存
      • 先更新数据库,再删除缓存,当更新数据库成功,就会产生一条变更日志,记录在binlog里。于是可以订阅binlog日志,拿到具体要操作的数据,再执行缓存删除。
      • Canal模拟MySQL的主从复制的交互协议,把自己伪装成从节点,向MySQL主节点发送dump请求,MySQL收到请求后,推送binlog给Canal,Canal解析Binlog字节流后,转换为便于读取的结构化数据,供下游程序订阅使用
        • 在这里插入图片描述

② 先删除缓存,再更新数据库

出现并发问题,造成缓存、数据库数据不一致

解决方案

延迟双删

  1. 删除缓存
  2. 更新数据库
  3. 睡眠
  4. 再删除缓存

请求A在睡眠时,B能够完成读取数据库数据,并把缺失数据写入缓存,A睡眠完后删除缓存。

请求A的睡眠时间 > 请求B的从数据库读取数据+写入缓存的时间

该方案尽可能保持一致性,建议采用先更新数据库,再删除缓存

互斥锁vs分布式锁

互斥锁:单机情况下,内存中的一个互斥锁就能控制一个程序的线程并发
分布式锁:适用于分布式场景,集群架构,需要“全局锁”实现控制多个程序/多个机器上的线程并发

小林coding图解Redis — 七

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

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

相关文章

虚拟机里为什么桥接模式可以广播,NAT模式不能广播?

虚拟机里为什么桥接模式可以广播,NAT模式不能广播? 我们在虚拟机里做调试的时候,进场会遇到NAT广播包发不出,而桥接模式可以。下面是找到的资料。 在虚拟机网络配置中,桥接模式(Bridged mode)允…

Android组件化搭建学习

什么是组件化? 为什么要用组件化?在项目的开发过程中,随着开发人员的增多及功能的增加,如果提前没有使用合理的开发架构,那么代码会越来臃肿,功能间代码耦合也会越来越严重,这时候为了保证项目…

Redisson分布式锁源码解析

一、使用Redisson步骤 Redisson各个锁基本所用Redisson各个锁基本所用Redisson各个锁基本所用 二、源码解析 lock锁 1) 基本思想: lock有两种方法 一种是空参 另一种是带参 * 空参方法:会默认调用看门狗的过期时间30*1000&…

JMeter压测常见面试问题

1、JMeter可以模拟哪些类型的负载? JMeter可以模拟各种类型的负载,包括但不限于Web应用程序、API、数据库、FTP、SMTP、JMS、SOAP / RESTful Web服务等。这使得JMeter成为一个功能强大且灵活的压力测试工具。 2、如何配置JMeter来进行分布式压力测试&a…

防爆智能安全帽、防爆手持终端,防爆智能矿灯守护安全,在煤矿安全生产远程可视化监管中的应用

煤矿安全新守护:如何通过防爆智能装备实现远程可视化监管 煤矿是国民经济的重要支柱产业,但长期以来,安全生产事故的频发一直是困扰煤矿行业发展的严峻问题。安全生产事故不仅危及矿工的生命安全,也对企业和地方经济造成了重大的…

驯服大数据的超强利器——PySpark数据处理引擎

你是否曾经为了处理大规模数据而烦恼?是否曾经为了解决日常的数据科学挑战而彻夜难眠?现在,Spark数据处理引擎正在向你敞开大门。这是一个惊人的分析工厂,输入原始数据,输出洞察。 PySpark,作为Spark的核心…

壹基金宣传进瑞金河背街社区 安全家园项目防灾减灾深入人心

11月16日下午,瑞金赋能公益、蓝天救援队等联合象湖镇河背街社区开展家庭安全计划社区活动包挑战赛活动暨壹基金安全家园项目防灾减灾宣传社区行活动。活动得到了救助儿童会北京代表处、壹基金、艾特公益、益心益意公益的指导,得到了阿里巴巴公益平台广大…

服务器 jupyter 文件名乱码问题

对于本台电脑,autodl服务器,上传中文文件时,从压缩包名到压缩包里的文件名先后会出现中文乱码的问题。 Xftp 首先是通过Xftp传输压缩包到Autodl服务器: 1、打开Xftp,进入软件主界面,点击右上角【文件】菜…

C++设计模式之工厂模式(上)——简单工厂模式

工厂模式 概述简单工厂模式介绍示例示例使用运行结果缺点 概述 工厂模式属于一种创建型设计模式。其可以分为简单工厂模式,工厂模式和抽象工厂模式。工厂模式分为上、中、下三篇,本篇主要介绍简单工厂模式。 简单工厂模式 介绍 简单工厂模式可以理解…

竞赛选题 题目: 基于深度学习的疲劳驾驶检测 深度学习

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 🔥 优…

二百零七、Flume——Flume实时采集5分钟频率的Kafka数据直接写入ODS层表的HDFS文件路径下

一、目的 在离线数仓中,需要用Flume去采集Kafka中的数据,然后写入HDFS中。 由于每种数据类型的频率、数据大小、数据规模不同,因此每种数据的采集需要不同的Flume配置文件。玩了几天Flume,感觉Flume的使用难点就是配置文件 二、…

【电路笔记】-星三角变换(Star-Delta Transformation)

星三角变换(Star-Delta Transformation) 文章目录 星三角变换(Star-Delta Transformation)1、概述1.1 单相配置1.2 多相配置 2、三相连接2.1 Y配置2.2 Δ配置 3、Y-Δ 和 Δ-Y 变换3.1 Y-Δ变换3.2 Δ-Y变换3.3 应用 4、总结 本文…

2023年DevOps国际峰会暨BizDevOps企业峰会(DOIS北京站)-核心PPT资料下载

一、峰会简介 在数字化转型的大背景下,企业选择实践 DevOps 来提升 IT 效能成为常态,BizDevOps 作为企业自身数字化变革的重要主题之一,需要全行业共同努力促进繁荣和发展。从 DevOps 到 BizDevOps,业务与技术如何融合&#xff1…

大模型的交互能力

摘要: 基础大模型显示出明显的潜力,可以改变AI系统的开发人员和用户体验:基础模型降低了原型设计和构建AI应用程序的难度阈值,因为它们在适应方面的样本效率,并提高了新用户交互的上限,因为它们的多模式和生…

Flink 替换 Logstash 解决日志收集丢失问题

在某客户日志数据迁移到火山引擎使用 ELK 生态的案例中,由于客户反馈之前 Logstash 经常发生数据丢失和收集性能较差的使用痛点,我们尝试使用 Flink 替代了传统的 Logstash 来作为日志数据解析、转换以及写入 ElasticSearch 的组件,得到了该客…

为何越来越多的程序员纷纷转行网络安全?

目前,我国IT行业的人才结构不断升级,公司对程序员的要求越来越高,出现了大量的裁员现象,导致很多的程序员纷纷想转行的想法。 可能对于早期的程序员而言,学好编程语言就能找到比较好的工作。而现在伴随着互联网的不断发…

十一 动手学深度学习v2计算机视觉 ——微调

一、网络架构 一个神经网络一般可以分成两块 特征抽取,将原始像素变成容易线性分割的特征。线性分类器来做分类。 二、训练 是一个目标数据集上的正常训练任务, 但使用更强的正则化 使用更小的学习率使用更少的数据迭代 源数据集远远复杂于目标数据集…

如何用Python爬取全国高校数据?

前言 Python是一门强大的编程语言,它可以用于爬取互联网上的各种数据。在这篇文章中,我们将学习如何使用Python爬取全国高校数据,并使用代理IP进行爬取。 本文主要分为以下几个部分: 数据来源及需求安装依赖包及导入模块爬取全…

Python 提高篇学习笔记(一):深拷贝和浅拷贝

文章目录 一、什么是对象的引用二、深拷贝和浅拷贝2.1 浅拷贝(Shallow Copy)2.2 深拷贝(Deep Copy)2.3 copy.copy和copy.deepcopy的区别 一、什么是对象的引用 在 Python 中,对象的引用是指变量指向内存中某个对象的地址或标识符。当你创建一个新的对象(比如一个整…

k8s无法删除pv,pvc问题

问题: 在k8s里面创建了pv,pvc删除时报错:error: resource(s) were provided, but no name was specified 解决: 正确的删除顺序:1.先删除pod2.再删除pv 3.在删除pvc 删除pv,pvc命令: kubect…