【Redis】缓存+分布式锁
目录
缓存
Redis最主要的使用场景就是作为缓存
缓存的更新策略:
1.定期生成
2.实时生成
面试重点:
缓存预热(Cache preheating):
缓存穿透(Cache penetration)
缓存雪崩 (Cache avalanche)
缓存击穿 (Cache breakdown)
分布式锁
分布式锁的基本实现:
引入过期时间:
引入校验Id:
引入lua脚本:
引入watch dog(看门狗)
引入Redlock算法:
缓存
核心思路就是把⼀些常见的数据放到触手可及(访问速度更快)的地方, 方便随时读取.
访问速度特别的快,但由于存储空间是有限的,所有我们只能存储“热点数据”(频繁访问的数据)在Redis中
俗称“二八定律”:20%的热点数据,可以应对80%的应用场景,从而整体上的性能得到提升
Redis最主要的使用场景就是作为缓存
对应MySQL这种访问硬盘的数据库,Redis是内存数据库,Redis用做为MySQL的缓存
为什么MySQL性能不高?
1.首先数据存储在硬盘上,硬盘IO需要花费大量时间,尤其是随机访问;
2.如果查询中不能命中索引,那么将需要表的遍历,大大增加硬盘IO的次数
3.对应执行SQL需要一系列的解析,校验等等工作
4.如果是一些复杂查询,例如联合查询,笛卡尔积之类的操作效率会很低...............
如果数据库并发量特别高,那么它将会可能出现宕机(出现故障,罢工了,不做了)的情况
如何解决?
1.开源:增加多个设备,部署更多的数据库机器,构成数据库集群
2.节流:引入缓存,访问的时候尽量访问缓存内的数据,从而降低直接访问数据库的请求数量
实际开发中,往往是俩种方法结合起来使用
Redis为什么可以作为MySQL的缓存:
Redis访问速度比MySQL快很多,并且处理一个访问请求,Redis消耗的资源比MySQL少很多,因此Redis支持更大的并发量:
1.Redis数据在内存,并且访问速度比硬盘快很多
2.Redis只支持简单的KEY-VALUE 存储,不涉及很多复杂查询方法手段
业务服务器先查询 Redis, 看想要的数据是否在 Redis 中存在.
- 如果已经在 Redis 中存在了, 就直接返回. 此时不必访问 MySQL 了.
如果在 Redis 中不存在, 再查询 MySQL.
缓存的更新策略:
一个重要问题:那么多数据,哪些数据才是我们需要的热点数据呢?
1.定期生成
会将所有访问的数据,以日志的形式给记录下来,最后挑选出频率前%N的数据作为“热点数据”;
此处的数据,可以按照每天/周/月去更新热点数据
2.实时生成
- 如果在Redis查找到了,那么将直接返回
- 如果在Redis没有查找到,那么从数据库查找,查找完并且写入Redis中
那么经过这样一段时间内,缓存的数据肯定会存储满,那么Redis也引入了对应的策略--------------内存淘汰机制:
通用的淘汰机制有以下机制:
- FIFO (First In First Out) 先进先出
把缓存中存在时间最久的 (也就是先来的数据) 淘汰掉.
- LRU (Least Recently Used) 淘汰最久未使⽤的
记录每个 key 的最近访问时间. 把最近访问时间最⽼的 key 淘汰掉.
- LFU (Least Frequently Used) 淘汰访问次数最少的
记录每个 key 最近⼀段时间的访问次数. 把访问次数最少的淘汰掉.
- Random 随机淘汰
从所有的 key 中抽取幸运⼉被随机淘汰掉.
在Redis中已经实现好了以上类似机制:
整体来说 Redis 提供的策略和我们上述介绍的通用策略是基本⼀致的. 只不过 Redis 这里会针对 "过期 key" 和 "全部 key" 做分别处理.
面试重点:
缓存预热(Cache preheating):
1.定期生成的数据这种情况不涉及缓存预热;
2.实时生成:
Redis服务器首次接入连接之后是没有数据的,此时所有的请求将在MySQL中(就怕此时MySQL没有抗住这么多请求挂了),那么随之时间的推移,Redis上的数据慢慢越来越多,MySQL承担的压力就会小很多;
缓存预热就是解决上述问题:
将定期生成和实时生成结合一下,先通过“离线”的方式,通过统计的途径,先找到一些热点数据(这些数据并一定精准,有就行)导入到Redis中,就能帮助MySQL承担很大的压力,随之时间的推移,热点数据会逐渐调整,来使用当前情况;
缓存穿透(Cache penetration)
在查询某个key的时候,在Redis中没有,在MySQL中也没有,那么这么key肯定不会更新到Redis中~
但是这个查询没有,接连着查询了多次,依然会给MySQL造成一些压力;
为什么出现这种情况?
- 业务设计不合理. 比如缺少必要的参数校验环节, 导致非法的 key 也被进行查询了.
- 开发/运维误操作. 不小心把部分数据从数据库上误删了.
- 黑客恶意攻击.
解决:
- 针对要查询的参数进行严格的合法性校验. 比如要查询的 key 是用户的手机号, 那么就需要校验当前key 是否满足一个合法的手机号的格式.
- 针对数据库上也不存在的 key , 也存储到 Redis 中,比如 value 就随便设成一个 "". 避免后续频繁访问数据库
- 使用布隆过滤器先判定 key 是否存在, 再真正查询.
缓存雪崩 (Cache avalanche)
在短时间内,Redis上大规模的key失效,导致缓存命中率陡然下降,让MySQL的压力迅游变大,导致宕机~
为何产生?
1.Redis挂了
2.Redis没有挂,但是可能之前给很多key设置的过期时间相同,一下子全过期自动删除了
解决:
- 部署高可用的 Redis 集群, 并且完善监控报警体系.
- 不给 key 设置过期时间 或者 设置过期时间的时候添加随机时间因子.
缓存击穿 (Cache breakdown)
相当于缓存雪崩的特殊情况,针对Redis热点key全部过期了,导致大量的请求直接访问到MySQ中,引起数据库宕机
- 基于统计的方式发现热点 key, 并设置永不过期.
- 进行必要的服务降级. 例如访问数据库的时候使用分布式锁, 限制同时请求数据库的并发数.
分布式锁
在一个分布式系统当中,会涉及到多个节点访问同一个公共资源的情况下,此时就需要通过“锁”来进行互斥,避免出现“线程安全”的问题;
像Java中的synchronized 这种锁只能在当前进程中生效,在分布式这种多个进程多个主机的场景下就不能使用了‘;
分布式锁的基本实现:
实现思路:通过设置一个键值对来标识锁的状态
举例买票的例子:
此时客户端1查询001车 还有1张车票 在即将执行1->0 过程前
客户端2也执行查询余票 发现还有一张,那么客户端2也执行1->0
那么这出现“超卖” 的情况,俩个人都买到票
加锁:
此时, 如果 买票服务器1 尝试买票, 就需要先访问 Redis, 在 Redis 上设置⼀个键值对. 比如 key 就是车次, value 随便设置个值 (比如 1).
如果发现操作成功,那么就可以视为当前没有节点对001车次加锁,那么就可以进行数据库的读写,操作完成之后,就可以吧这个key删除(相当于解锁)
如果服务器1在操作数据库时候,服务器2也想买票,那么它在给Redis新增key的时候,就会发现此时车次的key已经存在,就可以认为其他服务器此时正在持有锁,那么服务器2就可以等待或者放弃~
Redis中的setnx刚刚好就行对应此场景:当key不存在才可以创建成功,如果存在那么将失败 ~
此时如果某个服务器加锁成功,但意外发生了,服务器崩溃了没有执行解锁操作(删除操作),那么就导致其他服务器没有获取到锁;
引入过期时间:
可以设置key的过期时间,让这个锁持有多久,如果超过一定时间,那么将自动释放;
使用set ex nx 命令,在设置锁的同时加入过期时间;
注意这是一条命令
不能写成 setnx
expire
此时是俩条命令,就有可能造成原子性,仍然会出现无法正确释放锁的问题
所谓的加锁就是在Redis上执行setnx生成一个key
解锁就是删除这个key
那么有没有可能会出现服务器1执行了加锁操作,而服务器2执行了解锁?
那么是有可能的
引入校验Id:
需要引入一点校验机制:
1.给服务器编号,每个服务器有一个自己的身份标识
2.进行加锁的时候,设置key-value 对应要针对的哪个资源加锁(比如车次),value存储刚才服务器的编号 例如“001:1” ->“001:服务器1”
这样就可以在删除key的时候,校验当前的key是否是当初加锁的服务器,避免删除错误~
在解锁的时候:
1.先查询判断是否删除 2. 才进行删除
此时这个是俩步操作,并不是原子的,就有可能出现问题
引入lua脚本:
很多程序里面都支持内嵌脚本语音.Redis支持Lua语音作为内嵌脚本~
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
1 2 3return 0
end;
过期时间续约问题可能存在,
在给key加锁的时候,设置它的过期时间,那么设置多久呢才是比较合适?
- 设置时间短,那么可能在业务逻辑还没执行完,就释放锁了
- 设置时间长,就可以导致锁释放不及时的可能
更好的是能够去进行“动态续约”
引入watch dog(看门狗)
本质上就是在加锁的服务器上的一个单独的线程,通过这个线程来对锁过期时间进行一个“续约”
❤ 举个具体的例子:
初始情况下设置过期时间为 10s. 同时设定看门狗线程每隔 3s 检测⼀次. 那么当 3s 时间到的时候, 看门狗就会判定当前任务是否完成.
- 如果任务已经完成, 则直接通过 lua 脚本的方式, 释放锁(删除 key).
如果任务未完成, 则把过期时间重写设置为 10s. (即 "续约")
使用Redis作为分布式锁,有没有可能Redis自身挂了?
那么是很有可能的!!!
Redis一般是以集群(至少也是主从的形式,而不是单机)的方式去部署的
服务器1向它的master节点就行加锁操作,这个数据刚写入主节点,主节点挂了,从节点就会新的主节点
由于主节点和从节点之间的数据是同步的,但是有延迟的
那么刚才写入的key还没有被新的主节点接收,此时相当于服务器1就没有成功进行加上锁
但是服务器2仍然可以进行去加上锁,
引入Redlock算法:
由于主节点和主节点之间数据都是一致的,相互是备份的关系
在进行加锁的时候,会按照一定的顺序,针对这组Redis都进行加锁
如果某个节点加不上锁,并没有关系,可能是Redis挂了,继续给下一个节点加锁即可
如果此时key加锁成功的节点个数占总的一半,那么可视为加锁成功
同时解锁的时候,会把上述的节点都需要解锁~
简而言之, Redlock 算法的核心就是, 加锁操作不能只写给⼀个 Redis 节点, 而要写个多个!! 分布式系统中任何⼀个节点都是不可靠的. 最终的加锁成功结论是 "少数服从多数的".
相关文章:

【Redis】缓存+分布式锁
目录 缓存 Redis最主要的使用场景就是作为缓存 缓存的更新策略: 1.定期生成 2.实时生成 面试重点: 缓存预热(Cache preheating): 缓存穿透(Cache penetration) 缓存雪崩 (Cache avalan…...
二分查找题目:寻找两个正序数组的中位数
文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题:寻找两个正序数组的中位数 出处:4. 寻找两个正序数组的中位数 难度 8 级 题目描述 要求 给定两个大…...

网络安全 | F5-Attack Signatures详解
关注:CodingTechWork 关于攻击签名 攻击签名是用于识别 Web 应用程序及其组件上攻击或攻击类型的规则或模式。安全策略将攻击签名中的模式与请求和响应的内容进行比较,以查找潜在的攻击。有些签名旨在保护特定的操作系统、Web 服务器、数据库、框架或应…...

Redis --- 分布式锁的使用
我们在上篇博客高并发处理 --- 超卖问题一人一单解决方案讲述了两种锁解决业务的使用方法,但是这样不能让锁跨JVM也就是跨进程去使用,只能适用在单体项目中如下图: 为了解决这种场景,我们就需要用一个锁监视器对全部集群进行监视…...
LeetCode100之全排列(46)--Java
1.问题描述 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案 示例1 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例2 输入:nums [0,1] 输出…...
goframe 博客分类文章模型文档 主要解决关联
goframe 博客文章模型文档 模型结构 (BlogArticleInfoRes) BlogArticleInfoRes 结构体代表系统中的一篇博客文章,包含完整的元数据和内容管理功能。 type BlogArticleInfoRes struct {Id uint orm:"id,primary" json:"id" …...

【JavaWeb06】Tomcat基础入门:架构理解与基本配置指南
文章目录 🌍一. WEB 开发❄️1. 介绍 ❄️2. BS 与 CS 开发介绍 ❄️3. JavaWeb 服务软件 🌍二. Tomcat❄️1. Tomcat 下载和安装 ❄️2. Tomcat 启动 ❄️3. Tomcat 启动故障排除 ❄️4. Tomcat 服务中部署 WEB 应用 ❄️5. 浏览器访问 Web 服务过程详…...

安卓日常问题杂谈(一)
背景 关于安卓开发中,有很多奇奇怪怪的问题,有时候这个控件闪一下,有时候这个页面移动一下,这些对于快速开发中,去查询,都是很耗费时间的,因此,本系列文章,旨在记录安卓…...

Kitchen Racks 2
Kitchen Racks 2 吸盘置物架 Kitchen Racks-CSDN博客...
嵌入式学习笔记-杂七杂八
文章目录 连续波光纤耦合激光器工作原理主要特点应用领域设计考虑因素 数值孔径(Numerical Aperture,简称NA)数值孔径的定义数值孔径的意义数值孔径的计算示例数值孔径与光纤 四象限探测器检测目标方法四象限划分检测目标的步骤1. 数据采集2.…...

14-7C++STL的stack容器
(一)stack容器的入栈与出栈 (1)stack容器的简介 stack堆栈容器,“先进后出”的容器,且stack没有迭代器 (2)stack对象的默认构造 stack采用模板类实现,stack对象的默认…...
Vue 3 中的响应式系统:ref 与 reactive 的对比与应用
Vue 3 的响应式系统是其核心特性之一,它允许开发者以声明式的方式构建用户界面。Vue 3 引入了两种主要的响应式 API:ref 和 reactive。本文将详细介绍这两种 API 的用法、区别以及在修改对象属性和修改整个对象时的不同表现,并提供完整的代码…...

物业巡更系统助推社区管理智能化与服务模式创新的研究与应用
内容概要 在现代社区管理中,物业巡更系统扮演着至关重要的角色。首先,我们先来了解一下这个系统的概念与发展背景。物业巡更系统,顾名思义,是一个用来提升物业管理效率与服务质量的智能化工具。随着科技的发展,传统的…...
windows蓝牙驱动开发-生成和发送蓝牙请求块 (BRB)
以下过程概述了配置文件驱动程序生成和发送蓝牙请求块 (BRB) 应遵循的一般流程。 BRB 是描述要执行的蓝牙操作的数据块。 生成和发送 BRB 分配 IRP。 分配BRB,请调用蓝牙驱动程序堆栈导出以供配置文件驱动程序使用的 BthAllocateBrb 函数。;初始化 BRB…...

Linux网络之序列化和反序列化
目录 序列化和反序列化 上期我们学习了基于TCP的socket套接字编程接口,并实现了一个TCP网络小程序,本期我们将在此基础上进一步延伸学习,实现一个网络版简单计算器。 序列化和反序列化 在生活中肯定有这样一个情景。 上图大家肯定不陌生&a…...

linux设置mysql远程连接
首先保证服务器开放了mysql的端口 然后输入 mysql -u root -p 输入密码后即可进入mysql 然后再 use mysql; select user,host from user; update user set host"%" where user"root"; flush privileges; 再执行 select user,host from user; 即可看到变…...
react-native网络调试工具Reactotron保姆级教程
在React Native开发过程中,调试和性能优化是至关重要的环节。今天,就来给大家分享一个非常强大的工具——Reactotron,它就像是一个贴心的助手,能帮助我们更轻松地追踪问题、优化性能。下面就是一份保姆级教程哦! 一、…...
erase() 【删数函数】的使用
**2025 - 01 - 25 - 第 48 篇 【函数的使用】 作者(Author) 文章目录 earse() - 删除函数一. vector中的 erase1 移除单个元素2 移除一段元素 二. map 中的erase1 通过键移除元素2 通过迭代器移除元素 earse() - 删除函数 一. vector中的 erase vector 是一个动态数组&#x…...
性能测试丨内存火焰图 Flame Graphs
内存火焰图的基本原理 内存火焰图是通过分析堆栈跟踪数据生成的一种图形化表现,能够展示应用程序在运行时各个函数的内存占用情况。火焰图的宽度代表了函数占用的内存量,而火焰的高度则显示了函数在调用栈中的层级关系。通过这种可视化方式,…...

AIGC的企业级解决方案架构及成本效益分析
AIGC的企业级解决方案架构及成本效益分析 一,企业级解决方案架构 AIGC(人工智能生成内容)的企业级解决方案架构是一个多层次、多维度的复杂系统,旨在帮助企业实现智能化转型和业务创新。以下是总结的企业级AIGC解决方案架构的主要组成部分: 1. 技术架构 企业级AIGC解决方…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...