【Redis十二】Redis的典型应用(缓存和分布式锁)

目录

Redis作为缓存

1.什么是缓存?

2.缓存的更新策略

3.缓存预热,缓存穿透,缓存雪崩和缓存击穿

Redis作为分布式锁

1.什么是分布式锁?

2.分布式锁的实现过程


        Redis是目前后端开发中非常热门的组件之一,本篇文章主要介绍它在作为缓存以及分布式领域的作用。

Redis作为缓存

1.什么是缓存?

缓存 (cache) 是计算机中的⼀个经典的概念. 在很多场景中都会涉及到。
核⼼思路就是把⼀些常⽤的数据放到触⼿可及(访问速度更快)的地⽅, ⽅便随时读取。
对于计算机硬件来说, 往往访问速度越快的设备, 成本越⾼, 存储空间越⼩.
缓存是更快, 但是空间上往往是不⾜的. 因此⼤部分的时候, 缓存只放⼀些 热点数据 (访问频繁的数据),就⾮常有⽤了。
众所周知,咱们日常使用的关系型数据库比如MySQL是非常“娇嫩”的,操作他比起操作缓存是非常耗时的,而且很容易在一瞬间遭受到大量数据操作时,因忙不过来而宕机,数据库很多时候直接成为了整个程序的性能瓶颈。为了给MySQL减少压力,提高程序的效率和稳定性,业内通常使用Redis作为MySQL的缓存,这样就能大大减少MySQL的压力,提高程序性能和稳定性。
        之所以缓存只存热点数据就能大大降低数据库的访问压力,是因为这个世界存在普遍的“二八定律“,即 20% 的热点数据, 能够应对 80% 的访问场景。 因此只需要把这少量的热点数据缓存起来, 就可以应对⼤多数场景, 从⽽在整体上有明显的性 能提升. 

2.缓存的更新策略

接下来还有⼀个重要的问题, 到底哪些数据才是 "热点数据" 呢?
对于热点数据的挑选一般有两种方式:
  1. 定期生成
  2. 实时生成
定期生成:
        每隔⼀定的周期(⽐如⼀天/⼀周/⼀个⽉), 对于访问的数据频次进⾏统计. 挑选出访问频次最⾼的前 N%的数据。

以搜索引擎为例:

搜索引擎的服务器会把哪个⽤⼾什么时间搜了啥词, 都通过⽇志的⽅式记录的明明⽩ . 然后
每隔⼀段时间对这期间的搜索结果进⾏统计 (⽇志的数量可能⾮常巨⼤, 这个统计的过程可能
需要使用 hadoop等大数据挖掘技术完成). 从⽽就可以得到 "⾼频词表" 。
实时生成:
先给缓存设定容量上限(可以通过 Redis 配置⽂件的 maxmemory 参数设定).
接下来把⽤⼾每次查询:
  • 如果在 Redis 查到了, 就直接返回.
  • 如果 Redis 中不存在, 就从数据库查, 把查到的结果同时也写⼊ Redis.
如果缓存已经满了(达到上限), 就触发缓存淘汰策略, 把⼀些 "相对不那么热⻔" 的数据淘汰掉.
按照上述过程, 持续⼀段时间之后 Redis内部的数据⾃然就是 "热⻔数据" 了。
常用的缓存淘汰策略主要有以下几种:
  1. FIFO (First In First Out) 先进先出 把缓存中存在时间最久的 (也就是先来的数据) 淘汰掉.
  2. LRU (Least Recently Used) 淘汰最久未使⽤的 记录每个 key 的最近访问时间. 把最近访问时间最⽼的 key 淘汰掉.
  3. LFU (Least Frequently Used) 淘汰访问次数最少的 记录每个 key 最近⼀段时间的访问次数. 把访问次数最少的淘汰掉.
  4. Random 随机淘汰 从所有的 key 中抽取幸运⼉被随机淘汰掉

3.缓存预热,缓存穿透,缓存雪崩和缓存击穿

缓存预热

什么是缓存预热?
       使⽤ Redis 作为 MySQL 的缓存的时候, 当 Redis 刚刚启动, 或者 Redis ⼤批 key 失效之后, 此时由于Redis ⾃⾝相当于是空着的, 没啥缓存数据, 那么 MySQL 就可能直接被访问到, 从⽽造成较⼤的压⼒.因此就需要提前把热点数据准备好, 直接写⼊到 Redis 中. 使 Redis 可以尽快为 MySQL 撑起保护伞.热点数据可以基于之前介绍的统计的⽅式⽣成即可. 这份热点数据不⼀定⾮得那么 "准确", 只要能帮助MySQL 抵挡⼤部分请求即可. 随着程序运⾏的推移, 缓存的热点数据会逐渐⾃动调整, 来更适应当前情况。

缓存穿透

什么是缓存穿透?
       访问的 key 在 Redis 和 数据库中都不存在. 此时这样的 key 不会被放到缓存上, 后续如果仍然在访问该key, 依然会访问到数据库. 这就会导致数据库承担的请求太多, 压⼒很⼤. 这种情况称为 缓存穿透.

因为什么产生?

  • 业务设计不合理. ⽐如缺少必要的参数校验环节, 导致⾮法的 key 也被进⾏查询了.
  • 开发/运维误操作. 不⼩⼼把部分数据从数据库上误删了.
  • ⿊客恶意攻击.

如何解决? 

  • 针对要查询的参数进⾏严格的合法性校验. ⽐如要查询的 key 是⽤⼾的⼿机号, 那么就需要校验当前key 是否满⾜⼀个合法的⼿机号的格式.
  • 针对数据库上也不存在的 key , 也存储到 Redis 中, ⽐如 value 就随便设成⼀个 "". 避免后续频繁访问数据库.
  • 使⽤布隆过滤器先判定 key 是否存在, 再真正查询.

缓存雪崩

什么是缓存雪崩?
短时间内⼤量的 key 在缓存上失效, 导致数据库压⼒骤增, 甚⾄直接宕机。
为何产⽣?
⼤规模 key 失效, 可能性主要有两种:
  • Redis 挂了.
  • Redis 上的⼤量的 key 同时过期.

 如何解决?

  • 部署⾼可⽤的 Redis 集群, 并且完善监控报警体系.
  • 不给 key 设置过期时间 或者 设置过期时间的时候添加随机时间因⼦.

缓存击穿

什么是缓存击穿?
        相当于缓存雪崩的特殊情况. 针对热点 key , 突然过期了, 导致⼤量的请求直接访问到数据库上, 甚⾄引起数据库宕机.

 如何解决?

  • 基于统计的⽅式发现热点 key, 并设置永不过期.
  • 进⾏必要的服务降级. 例如访问数据库的时候使⽤分布式锁, 限制同时请求数据库的并发数.

Redis作为分布式锁

1.什么是分布式锁?

在⼀个分布式的系统中, 也会涉及到多个节点访问同⼀个公共资源的情况. 此时就需要通过 锁 来做互斥控制, 避免出现类似于 "线程安全" 的问题.
⽽ java 的 synchronized 或者 C++ 的 std::mutex, 这样的锁都是只能在当前进程中⽣效, 在分布式的这种多个进程多个主机的场景下就⽆能为力了。
       分布式锁本质上就是使⽤⼀个公共的服务器, 来记录 加锁状态。这个公共的服务器可以是 Redis, 也可以是其他组件(⽐如 MySQL 或者 ZooKeeper 等), 还可以是我们⾃⼰写的⼀个服务。

2.分布式锁的实现过程

1.首先我们可以使用Redis的键值对功能进行简单的加锁功能。

       如果服务器1 尝试买票操作, 就需要先访问 Redis, 在 Redis 上设置⼀个键值对. ⽐如 key 就是⻋ 次, value 随便设置个值 (比如 1).如果这个操作设置成功, 就视为当前没有节点对该 001 ⻋次加锁, 就可以进⾏数据库的读写操作. 操作完成之后, 再把 Redis 上刚才的这个键值对给删除掉. 如果在 买票服务器1 操作数据库的过程中, 买票服务器2 也想买票, 也会尝试给 Redis 上写⼀个键值对, key 同样是⻋次. 但是此时设置的时候发现该⻋次的 key 已经存在了, 则认为已经有其他服务器正在持有锁, 此时服务器2就需要等待或者暂时放弃.(可以使用setnx操作)。

2.在上述加锁过程中我们可以引入过期时间。

       当服务器1 加锁之后, 开始处理买票的过程中, 如果 服务器1 意外宕机了, 就会导致解锁操作 (删除该key) 不能执⾏. 就可能引起其他服务器始终⽆法获取到锁的情况. 为了解决这个问题, 可以在设置 key 的同时引⼊过期时间. 即这个锁最多持有多久, 就应该被释放。

3. 对于Redis写入的加锁键值对,其他节点也是可以删除的,此时我们需要引入校验id。

⽐如 服务器1 写⼊⼀个 "001": 1 这样的键值对, 服务器2 是完全可以把 "001" 给删除掉的. 当然, 服务器2 不会进⾏这样的 "恶意删除" 操作, 不过不能保证因为⼀些 bug 导致 服务器2 把锁误删除。
为了解决上述问题, 我们可以引⼊⼀个校验 id.
⽐如可以把设置的键值对的值, 不再是简单的设为⼀个 1, ⽽是设成服务器的编号. 形如 "001": "服务器 1"。这样就可以在删除 key (解锁)的时候, 先校验当前删除 key 的服务器是否是当初加锁的服务器, 如果是,才能真正删除; 不是, 则不能删除。

4.引入Redis的Lua脚本功能是锁操作具有原子性。 

        lua脚本是一个以.lua为后缀的文件,使用lua语法编辑,它可以由redis-cli或jedis等客户端加载,并发送给Redis服务器,由Redis服务器来执行这段逻辑。一个lua脚本会被Redis以原子的方式来执行

5.引入watch dog(看门狗)使过期时间更准确。

       上述⽅案仍然存在⼀个重要问题. 当我们设置了 key 过期时间之后 (⽐如 10s), 仍然存在⼀定的可能性, 当任务还没执⾏完, key 就先过期了. 这就导致锁提前失效。所谓 watch dog, 本质上是加锁的服务器上的⼀个单独的线程, 通过这个线程来对锁过期时间进⾏ "续约"。这样就不担⼼锁提前失效的问题了. ⽽且另⼀⽅⾯, 如果该服务器挂了, 看⻔狗线程也就随之挂了, 此时无人续约, 这个 key ⾃然就可以迅速过期, 让其他服务器能够获取到锁了.

6.引入Redlock算法,使用Redis集群参与分布式锁。

实践中的 Redis ⼀般是以集群的⽅式部署的 (⾄少是主从的形式, ⽽不是单机). 那么就可能出现以下⽐较极端的⼤冤种情况:

服务器1 向 master 节点进⾏加锁操作. 这个写⼊ key 的过程刚刚完成, master 挂了; slave 节点升级成了新的 master 节点. 但是由于刚才写⼊的这个 key 尚未来得及同步给 slave 呢, 此时就相当于 服务器1 的加锁操作形同虚设了, 服务器2 仍然可以进⾏加锁 (即给新的 master 写⼊ key. 因为新的 master 不包含刚才的 key).
为了解决这个问题, Redis 的作者提出了 Redlock 算法.

我们引⼊⼀组 Redis 节点. 其中每⼀组 Redis 节点都包含⼀个主节点和若⼲从节点. 并且组和组之间存储的数据都是⼀致的, 相互之间是 "备份" 关系(⽽并⾮是数据集合的⼀部分, 这点有别于 Redis cluster).加锁的时候, 按照⼀定的顺序, 写多个 master 节点. 在写锁的时候需要设定操作的 "超时时间". ⽐如50ms. 即如果 setnx 操作超过了 50ms 还没有成功, 就视为加锁失败.如果给某个节点加锁失败, 就⽴即再尝试下⼀个节点. 当加锁成功的节点数超过总节点数的⼀半, 才视为加锁成功. 这样的话, 即使有某些节点挂了, 也不影响锁的正确性.同理, 释放锁的时候, 也需要把所有节点都进⾏解锁操作. (即使是之前超时的节点, 也要尝试解锁, 尽量保证逻辑严密)。

 Redlock 算法的核⼼就是, 加锁操作不能只写给⼀个 Redis 节点, ⽽要写个多个!! 分布式系统中任何⼀个节点都是不可靠的. 最终的加锁成功结论是 "少数服从多数的"。

由于⼀个分布式系统不⾄于⼤部分节点都同时出现故障, 因此这样的可靠性要⽐单个节点来说靠谱不少.

❤️😍😍😍😍😍😍😍😍😍😍😍😍😍😍😍😍😍

🍔我是小皮侠,谢谢大家都能看到这里!!

🦚主页已更新Java基础内容,数据结构基础,数据库,算法,Redis相关内容。

🚕未来会更新Java项目,SpringBoot,docker,mq,微服务以及各种Java路线会用到的技术。

🎃求点赞!求收藏!求评论!求关注!

🤷‍♀️谢谢大家!!!!!!!!

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

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

相关文章

Git--简略

Git简介 Git 是一个 免费 的 开源 分布式版本控制系统, 容易学习,内存小,效率高。 Git流程图 Git常用的一些命令 这里的a.txt 只是一个文件名,并不是固定命令代码 git add a.txt 添加到缓存区 git commit a.txt 提交到…

Hive优化:Hive的执行计划、分桶、MapJoin、数据倾斜

文章目录 1. hive的执行计划1.1 为什么使用EXPLAIN1.2 使用EXPLAIN的步骤1.3 EXPLAIN在什么场合使用 2. 分桶2.1 为什么要使用分桶 3. Map Join3.1 Map Join3.1.1 大小表关联3.1.2 不等连接 3.2 Bucket-MapJoin3.2.1 作用3.2.2 条件 3.3 SMB Join3.3.1 作用 4. 数据倾斜4.1 表连…

计数型信号量

一,什么是计数型信号量? 计数型信号量相当于队列长度大于1 的队列,因此计数型信号量能够容纳多个资源,这在计数型信号量被创建的时候确定的。 计数型信号量相关 API 函数 函数描述xSemaphoreCreateCounting()使用动态方法创建计数…

鸿蒙HarmonyOS开发:应用权限的基本概念及如何申请应用权限详细介绍

文章目录 一、访问控制二、应用权限1、应用权限管控2、权限使用的基本原则3、授权方式4、权限等级 三、申请应用权限1、选择申请权限的方式2、声明权限3、声明样例4、二次向用户申请授权5、具体实现示例6、效果展示 四、应用权限列表1、system_grant(系统授权&#…

使用 KVM 在 Xubuntu 上创建 Windows 10 虚拟机

目录 前言说明注意准备 iso官网思博主(嘻嘻)拖动到虚拟机里面启动 virt-manager创建虚拟机选择本地安装介质选择 iso配置 内存 和 CPU选择 创建的虚拟机 保存的位置启动虚拟机看到熟悉的 Win10界面点击现在安装点击我没有产品密钥选择 Win10 专业工作站版勾选接受许可条款选择自…

前端中的拖拽知识

概述 本文主要介绍前端中拖拽相关的知识以及如何在 vue3 工程里实现拖拽指令。 前端中的拖拽 前端中的拖拽功能是一种交互设计,允许用户通过鼠标或触摸操作移动页面上的元素到不同的位置。这一功能的实现涉及 HTML、CSS 和 JavaScript 的综合运用。 HTML元素拖拽 拖拽元素…

MySQL增删改进阶

目录 1.数据库约束 1.1约束类型 1.2 not null约束 1.3 unique:唯一约束 1.4 default:默认约束 1.5 primary key:主键约束 1.6 foreign key:外键约束 1.7 check约束(了解) 2.表的设计 3.新增(进阶&…

C++【内存管理】(超详细讲解C++内存管理以及new与delete的使用和原理)

文章目录 1.C/C内存分布2.C语言中动态内存管理方式3.C内存管理方式3.1 new/delete操作内置类型3. 2new/delete操作自定义类型 4. operator new与operator delete函数(重点)5. new和delete的实现原理5.1 内置类型5.2 自定义类型5.2.1 自定义类型调用new[]…

基于Q学习迷宫寻路问题

迷宫由一个二维数组 self.maze 表示,其中: 0 表示可以行走的空白区域,1 表示障碍物,2 表示迷宫的起始位置,3 表示迷宫的目标位置。 动作定义了智能体可以执行的动作集合,在这个迷宫问题中,动…

最大输出功率的计算(直流电源)

本内容仅计算直流电源的最大输出功率​。 方法1: 图1 电源电路 根据欧姆定律列写电流公式,其中,U和r是常数,R为变量。 电阻R上消耗的功率:,代入上面的式子,可得: ,故…

5、JavaScript(二) 对象+DOM

17.对象 1、对象:⽤来存储多个数据的 是由多个键值对/key value对组成的 ⽤来描述⼀个事物的 相当于多个变量的集合 2、格式 :{key:value,key:value} 键/值对 属性名:属性值 3、对象的属性值是不限制数据类型的,甚至还可以是对…

【第二十二课】空间自分析——实例分析

一、前言 案例描述:现有全国 31个省市的矢量地图以及相关年份GDP 属性数据, 通过空间自相关分析我国省域经济的空间格局变化。 1、全局Morans I方法 (1)加载全国省域图层,并与相关年份GDP属性数据进行连接操作。 &…

Apache Seata Raft模式配置中心

本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。 本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。 Apache Seata Raft模式配置中心 title: Seata Raft模式配置中心 author: 蒋奕晨-清华大学&…

【计算机网络】HTTP报文详解,HTTPS基于HTTP做了哪些改进?(面试经典题)

HTTP协议基本报文格式 在计算机网络中,HTTP(超文本传输协议)是应用层的一种协议,用于客户端(通常是浏览器)和服务器之间的通信。HTTP报文分为请求报文和响应报文,以下是它们的基本格式。 1. H…

【R语言】gadm全球行政区划数据库

我R语言不熟、也不是学GIS的。仅用于记录。 文章目录 一、gadm 数据库简介二、R 语言示例三、sf 包的函数 一、gadm 数据库简介 GADM(全称Database of Global Administrative Areas)是一个高精度的全球行政区划数据库,它包含了全球所有国家和…

cs木马图形化界面出现问题处理

一个月多月没用cs木马了,发现打开客户端之后显示不出图形化界面,且出现下面这样的报错。 、 最后发现是java版本的问题,kali的java自动更新了。把原来的openjdk11改到了openjdk23。 解决方法: 输入: sudo update-…

vue的动态组件 keep-alive

1. 什么是动态组件 动态组件指的是 动态切换组件的显示与隐藏 2. 如何实现动态组件渲染 vue提供了一个内置的<component>组件&#xff0c;专门用来实现动态组件的渲染。 作用&#xff1a;组件的占位符is的值表示要渲染的组件 示例代码如下&#xff1a; Left.vue的代…

2024版AI大模型转行入门全攻略,零基础入门到精通,收藏这一篇就够了

引言 随着人工智能和大模型&#xff08;如GPT-4、BERT等&#xff09;技术的快速发展&#xff0c;越来越多的专业人士希望转行进入这一领域。大模型开发涉及复杂的技术体系和多样的应用场景&#xff0c;对从业者的知识和能力提出了较高要求。本文将详细解析转行大模型开发所需的…

1.C++经典实例-计算两个数的最大公约数

用户输入两个数字&#xff0c;然后通过程序计算出这两个数字的最大公约数&#xff1a; 最大公约数&#xff08;greatest common divisor&#xff0c;简写为 gcd &#xff1b;或highest common factor&#xff0c;简写为hcf)&#xff0c;指某几个整数共有因子中最大的一个 #in…

RHCE——例行性工作

准备工作 [rootlocalhost ~]# cat /etc/yum.repos.d/aliyun.repo [ali-app] nameali-app baseurlhttps://mirrors.aliyun.com/centos-stream/9-stream/AppStream/x86_64/os/ gpgcheck0[ali-base] nameali-base baseurlhttps://mirrors.aliyun.com/centos-stream/9-stream/Base…