缓存雪崩、击穿、穿透及解决方案_保证缓存和数据库一致性
文章目录
- 缓存雪崩、击穿、穿透
- 1.缓存雪崩
- 造成缓存雪崩
- 解决缓存雪崩
- 2. 缓存击穿
- 造成缓存击穿
- 解决缓存击穿
- 3.缓存穿透
- 造成缓存穿透
- 解决缓存穿透
- 更新数据时,如何保证数据库和缓存的一致性?
- 1. 先更新数据库?先更新缓存?
- 解决方案
- 2. Cache Aside策略
- ① 先更新数据库,再删除缓存
- 保证更新数据库、删除缓存都执行成功
- ② 先删除缓存,再更新数据库
- 解决方案
缓存雪崩、击穿、穿透
一般用户数据存储于磁盘,读写速度慢。
使用redis作为缓存,相当于数据缓存在内存,大大提高系统性能
redis作为缓存,就会有缓存异常的三个问题
1.缓存雪崩

缓存都设置了过期时间
造成缓存雪崩
-
大量缓存数据在同一时间过期
-
redis故障宕机
若此时有大量用户请求,无法在redis处理,都直接访问数据库 => 数据库压力骤增(严重造成数据库宕机) => 形成一系列连锁反应 => 整个系统崩溃
解决缓存雪崩
=> 大量缓存数据在同一时间过期时:
-
均匀设置过期时间(对缓存数据的过期时间加上随机数,保证数据不会在同一时间过期)
-
互斥锁(当业务线程在处理用户请求时,如果发现访问的数据不在redis里,加互斥锁,保证同一时间内只有一个请求来构建缓存(从数据库读取数据,再将数据更新到redis),当缓存构建完成后,再释放锁。)
注:互斥锁设置超时时间,否则若出现请求发生意外阻塞,导致其他请求也一直拿不到锁 -
后台更新缓存(让缓存“永久有效”,将更新缓存的工作交由后台线程定时更新)
当系统内存紧张时,有些缓存数据被“淘汰”,在“淘汰”和下次更新时间内,业务线程读取失败就以为是数据丢失,解决方法:-
后台线程负责定时更新缓存,同时频繁地检测缓存是否失效,若失效,可进行构建缓存
检测时间间隔不能太长,太长导致用户获取的数据是空值而不是真正的数据,检测时间间隔最好是毫秒级,用户体验一般
-
业务线程发现缓存数据失效后,通过消息队列发送一条消息通知后台线程更新缓存。后台线程收到消息后,更新前判断缓存是否存在,不存在则进行构建缓存。
缓存更新及时,用户体验好
**注:**后台更新缓存机制适合进行缓存预热(业务刚上线时,提前缓存数据,不是等待用户访问才来触发缓存构建)
-
=> Redis故障宕机时:
-
服务熔断或请求限流机制
服务熔断:暂停业务应用对缓存服务的访问,直接返回错误,不再继续访问数据库,直到redis恢复正常。
请求限流机制:只将少部分请求发送到数据库进行处理,再多的请求就在入口直接拒绝服务,等到Redis恢复正常 并把缓存预热完后。
-
构建redis缓存高可靠集群
通过主从节点的方式构建,若redis缓存的主节点宕机,从节点可以切换成为主节点,继续提供缓存服务
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字节流后,转换为便于读取的结构化数据,供下游程序订阅使用
- 重试机制 => 引入消息队列,将删除缓存操作的数据加入消息队列,由消费者操作数据
② 先删除缓存,再更新数据库
出现并发问题,造成缓存、数据库数据不一致
解决方案
延迟双删
- 删除缓存
- 更新数据库
- 睡眠
- 再删除缓存
请求A在睡眠时,B能够完成读取数据库数据,并把缺失数据写入缓存,A睡眠完后删除缓存。
请求A的睡眠时间 > 请求B的从数据库读取数据+写入缓存的时间
该方案尽可能保持一致性,建议采用先更新数据库,再删除缓存
互斥锁vs分布式锁
互斥锁:单机情况下,内存中的一个互斥锁就能控制一个程序的线程并发
分布式锁:适用于分布式场景,集群架构,需要“全局锁”实现控制多个程序/多个机器上的线程并发
小林coding图解Redis — 七
相关文章:
缓存雪崩、击穿、穿透及解决方案_保证缓存和数据库一致性
文章目录 缓存雪崩、击穿、穿透1.缓存雪崩造成缓存雪崩解决缓存雪崩 2. 缓存击穿造成缓存击穿解决缓存击穿 3.缓存穿透造成缓存穿透解决缓存穿透 更新数据时,如何保证数据库和缓存的一致性?1. 先更新数据库?先更新缓存?解决方案 2…...
仿 美图 / 饿了么,店铺详情页功能
前言 UI有所不同,但功能差不多,商品添加购物车功能 正在写,写完会提交仓库。 效果图一:左右RecyclerView 联动 效果图二:通过点击 向上偏移至最大值 效果图三:通过点击 或 拖动 展开收缩公告 效果图四&…...
Redis Cluster主从模式详解
在软件的架构中,主从模式(Master-Slave)是使用较多的一种架构。主(Master)和从(Slave)分别部署在不同的服务器上,当主节点服务器写入数据时,同时也会将数据同步至从节点服…...
Linux技能篇-非交互式修改密码
今天的文章没有格式,简单分享一个小技能,就是标题所说–非交互式修改密码。 一、普通方式修改用户密码 最普通的修改密码的命令就是passwd命令 [rootlocalhost ~]# passwd root Changing password for user root. New password: Retype new password:…...
记一次docker服务启动失败解决过程
环境:centos 7.6 报错:start request repeated too quickly for docker.service 由于服务器修复了内核漏洞,需要重启,没想到重启后,docker启动失败了 查看状态 systemctl status docker如下图 里面有一行提示&…...
npm ERR! node-sass@4.13.0 postinstall: `node scripts/build.js`
npm ERR! node-sass4.13.0 postinstall: node scripts/build.js npm config set sass_binary_sitehttps://npm.taobao.org/mirrors/node-sass npm install npm run dev Microsoft Windows [版本 10.0.19045.2965] (c) Microsoft Corporation。保留所有权利。C:\Users\Administr…...
Java定时任务 ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor 的创建 ScheduledThreadPoolExecutor executorService new ScheduledThreadPoolExecutor(1, // 核心线程数new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d") // 线程命名规则.daemon(true) // 设置线程为…...
Android Studio 显示build variants工具栏
工具栏: 如下图所示 依次点击View-->ToolWindows-->Build Variants。 在此记个笔记...
c++八股文记录
八股文 1.类和结构体的区别 在 C 中,类(class)和结构体(struct)在语法上几乎是相同的,唯一的区别是默认的访问权限。在结构体中,默认的访问权限是公有的(public)&#x…...
C++ 指针进阶:动态分配内存
工作原理 malloc 是 stdlib.h 库中的函数,声明为 void *__cdecl malloc(size_t _Size); 原理: malloc 函数沿空闲链表(位于内存 堆空间 中)申请一块满足需求的内存块,将所需大小的内存块分配给用户剩下的返回到链表上; 并返回指向该内存区的首地址的指针,意该指针的类型…...
点大商城V2.5.3分包小程序端+小程序上传提示限制分包制作教程
这几天很多播播资源会员反馈点大商城V2.5.3小程序端上传时提示大小超限,官方默认单个包都不能超过2M,总分包不能超20M。如下图提示超了93KB,如果出现超的不多情况下可采用手动删除一些images目录下不使用的图片,只要删除超过100KB…...
AUTOSAR汽车电子嵌入式编程精讲300篇-基于机器学习的车载 CAN 网络入侵检测
目录 前言 国内外研究现状 CAN 总线概述及其安全分析 2.1 CAN 总线相关概念 2.1.1...
Jetson orin(Ubuntu20.04)不接显示器无法输出VNC图像解决办法以及vnc安装记录
sudo apt install vino 好像Jetpack 5.0中已经自带了。。 配置VNC server: gsettings set org.gnome.Vino prompt-enabled false gsettings set org.gnome.Vino require-encryption false 编辑org.gnome,增加一个“enabled key”的参数: cd /usr/share/glib-2…...
LeetCode Hot100 108.将有序数组转为二叉搜索树
题目: 给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。 方法: class Solution {public…...
微机原理_3
一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案,请将选定的答案填涂在答题纸的相应位置上。) 在 8086 微机系统中,完成对指令译码操作功能的部件是()。 A. EU B. BIU C. SRAM D. DRAM 使计算机执行某…...
4.操作系统常见面试题(2)
3.4 虚拟内存 直接使⽤物理内存会产⽣⼀些问题 1. 内存空间利⽤率的问题:各个进程对内存的使⽤会导致内存碎⽚化,当要⽤ malloc 分配⼀块很⼤的内存空间时,可能会出现虽然有⾜够多的空闲物理内存,却没有⾜够⼤的连续空闲内存这种…...
springboot 开启和关闭kafka消费
关闭kafka自动消费 配置自定义容器工厂 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.config.C…...
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
密码,加密,解密 spring-security-crypto-5.7.3.jar /** Copyright 2002-2011 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with t…...
系统安全测试要怎么做?
进行系统安全测试时,可以按照以下详细的步骤进行: 1、信息收集和分析: 收集系统的相关信息,包括架构、部署环境、使用的框架和技术等。 分析系统的安全需求、威胁模型和安全策略等文档。 2、威胁建模和风险评估: …...
Golang并发模型:Goroutine 与 Channel 初探
文章目录 goroutinegoexit() channel缓冲closerangeselect goroutine goroutine 是 Go 语言中的一种轻量级线程(lightweight thread),由 Go 运行时环境管理。与传统的线程相比,goroutine 的创建和销毁的开销很小,可以…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
