Redis做分布式锁

(一)为什么要有分布式锁以及本质

  在一个分布式的系统中,会涉及到多个客户端访问同一个公共资源的问题,这时候我们就需要通过锁来做互斥控制,来避免类似于线程安全的问题

  因为我们学过的sychronized只能对线程加锁,在分布式系统中无法对进程进行加锁,此时我们就需要用分布式锁

 那分布式锁的本质我们可以理解为一个公共服务器,来记录加锁的状态,那我们这里使用redis来作为这个公共服务器

(二)分布式锁的基本实现

1.基础实现

  我们说分布式锁的本质是服务器,来记录加锁状态,那这个加锁的本质就是通过一个键值对的方式来标识锁的状态

  就用我们常见的购票场景,我们现在有多个服务器节点来提供购票需求,那购票的流程:先查询指定车的余票,如果余票>0,就-=1,很明显,这个操作不是原子的,就会导致有其他服务器节点插到中间执行,这就会导致超卖的情况(这种情况在单机上,我们可以通过对线程加锁的方式来处理,但是加锁对于多进程来说,是无能为力的)

  如果我们最终存储数据的服务器是mysql,我们可以使用事务来解决,但是如果不是,我们还是需要之后的步骤

  

 那我们这里想要加锁,我们就需要引入一个公共服务器,作为分布式锁的管理者

我们服务器节点会先访问redis,在redis设置一个键值对,比如key是车次

   如果这个操作设置成功,就视为有服务器节点对这个车次进行加锁了,其他的服务器节点想要购票时,就也需要写一个键值对,但是我们会发现这个key已经存在了此时就需要进行阻塞等待,等到我们加锁的这个服务器节点在进行完数据库的读写操作后,就要把redis刚才的键值对给删除掉,这个删除操作就相当于释放锁,然后我们其他的服务器节点才可以再次购票进行加锁解锁操作

 注:我们redis本来就是key-value结构,并且提供了setnx操作,当我们key不存在的时候就设置成功,存在就设置失败,所以使用redis很合适

2.引入过期时间

 当服务器1加锁后解锁前,如果服务器1挂了,就会导致我们这个解锁操作不能执行,那么其他的服务器程序就一直无法获取到锁

 那我们之前讲多线程的时候,使用了finally,来保证最后一定会解决,那这个能不能在分布式锁中使用呢?    是不可以的,因为我们加锁不是在自己进程中加的,而是在一个公共服务器中加的,程序异常退出,是不会给公共服务器上的锁解锁的

 那我们如果挂了,为了解决无法解锁的问题,不如我们未雨绸缪,我们在设置key的同时引入过期时间来保证这个key存在多久就自动销毁(这个锁加锁多久后自动解锁)

 那我们可以使用redis中的set ex nx的方式,在设置锁的同时设置过期时间

 注意:如果我们使用setnx 后使用expire,因为是两个指令,不是原子的,即使使用事务也不能保证都执行正确,就导致可能会出现无法正确释放锁的问题

3.引入校验id

   对于redis中的数据,我们其他服务器节点也是可以删除的,上述情况下,我们一个服务器对他加锁后,另一个服务器也可以进行解锁操作,虽然我们不会故意让另一个服务区程序去解锁,但是我们还是要保证不能因为一些bug导致服务器2把key误删了

  为了解决这个问题,我们可以把我们的服务器程序的编号给放到value中,因为我们上述说是写key然后校验key是否存在来判断是否加锁的,这个value的值就可以任我们发挥,那我们value放服务器编号,然后我们想要解锁时,先判断这个key对应的value是不是我们当前的服务器,如果是就进行删除,不是就不可以删除

那我们伪代码如下

 我们发现,这里的get和del不是原子的,那就可能会出现错误

  如果在多线程的情况下就会导致重复删除一个key,那有人会有疑问,重复删就删了呗,那如果此时正好有一个set key在最后一个del之前执行呢?这就会导致我们新设置的key被直接删除了

 那这里的问题我们可以使用redis事务来解决,也可以使用lua脚本

4.lua脚本

  lua是redis的一个内嵌语言,语法简单并且执行速度快,且轻量,并且redis官方文档说,我们可以使用lua来实现redis的事务

 因为redis执行lua脚本是相当于一个操作也就是原子的,但是lua脚本中可以有很多操作

如果使用lua脚本,那代码可以写为

5.引入watch dog

  上述方案还有一个问题,也就是我们过期时间的设置,我们设置了key过期时间后,可能会导致我们任务没执行完,key就过期了,或者当我们key过期时间很长,就会导致其他服务器无法及时加锁,那么针对这个问题,我们就引入了一个watch dog,本质上是加锁服务器上的一个单独线程,来针对这个加锁时间进行“续约”

 就比如,我们先设置过期时间1s,当还剩300ms我们任务没执行完,我们这个watch dog线程就会把过期时间重新设置,也就是续约过程,这样就不用担心过期时间设置的过长或者过短了,因为过期时间变成了动态的

 而且当我们服务器挂了,这个线程也就挂了,过期时间就不会改变,就可以正常的释放锁

6.引入redlock

我们上述都是在讨论服务器节点的问题,那假如我们redis服务器挂了呢?这时有人会说,主从结构和哨兵可以帮我们解决啊,我们一直会有主节点的,虽然是这样,但是会存在我们之前的主节点中有一些加锁操作没来得及同步数据给从节点,导致数据丢失,这样就相当于没有加锁,其他服务器就可以进行加锁

 那为了解决这种问题,redis作者提出了redlock算法

也就是引入了一组redis节点,每一组都是相同的主从结构,并且数据也相同,加锁的时候,我们按照一定顺序,写多个master节点,写操作时要设定操作的超时时间,当set key的操作超过超时时间没有成功,就视为加锁失败

   

  如果给某个节点加锁失败,就尝试下一个节点,当加锁成功的节点数超过总数一半,就视为加锁成功

 这个算法就是通过空间换取准确度

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

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

相关文章

IntelliJ+SpringBoot项目实战(四)--快速上手数据库开发

对于新手学习SpringBoot开发,可能最急迫的事情就是尽快掌握数据库的开发。目前数据库开发主要流行使用Mybatis和Mybatis Plus,不过这2个框架对于新手而言需要一定的时间掌握,如果快速上手数据库开发,可以先按照本文介绍的方式使用JdbcTemplat…

12、Linux系统的网络基本设置

查看网络接口信息ifconfig ip addr/ip a #简单查看网络接口信息 ifconfig #表示只显示当前活跃的设备接口信息 ifconfig -a #查看当前主机所有的(all)网络设备,包括未运行的设备。 如我们查看本机网卡ens33的…

JDK1.8升级JDK不生效

最近因为项目原因,需要将jdk1.8升级到JDK11.升级发生了一个纠结的问题,就是cmd不生效。在此记录! 项目中指定jdk 如果在android studio项目,可以单独指定该项目的jdk,而不用全局升级,可以做如下配置&#…

八 Bean的生命周期

八、Bean的生命周期 8.1 什么是Bean的生命周期 Spring其实就是一个管理Bean对象的工厂。它负责对象的创建,对象的销毁等。 所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。 什么时候创建Bean对象? 创建Bean对象的前后会调用什…

【Android】webview常用方法和使用

文章目录 前言一、常见用法二、基础属性webView的常用方法WebViewClient的常用方法WebChromeClient的常用方法WebSettings的相关方法 三、加载流程和事件回调四、webview和JS之间的互相调用总结 五、参考链接 前言 最近项目又用到了webview,在回顾复习一次webview相…

OpenGL ES 共享上下文实现多线程渲染

OpenGL ES 共享上下文时,可以共享哪些资源? 共享上下文实现多线程渲染 EGL 概念回顾 EGL 是 OpenGL ES 和本地窗口系统(Native Window System)之间的通信接口,它的主要作用: 与设备的原生窗口系统通信; 查询绘图表面的可用类型和配置; 创建绘图表面; 在OpenGL ES 和…

09C++结构体

/*结构体属于用户自定义的数据类型&#xff0c; 允许用户存储不同的数据类型, 语法:struct 结构体名{结构体成员列表} ;*/ //struct 结构体名 变量名 #include <iostream> #include <string> using namespace std; struct student { string name; int age;int s…

python第七次作业

01.设计一个函数&#xff0c;可以传入一个或多个单词的字符串&#xff0c;并返回该字符串&#xff0c;但所有五个或更多字母的单词都前后颠倒 a input("输入:") print(a) #将一句话以空格为分界拆分为单个单词 b a.split(" ") ls_1 [] ls_2 []for i i…

C++开发基础之使用librabbitmq库实现RabbitMQ消息队列通信

1. 前言 RabbitMQ是一个流行的开源消息队列系统&#xff0c;支持多种消息协议&#xff0c;广泛用于构建分布式系统和微服务架构。可以在不同应用程序之间实现异步消息传递。在本文中&#xff0c;我们将熟悉如何使用C与RabbitMQ进行消息通信。 2. 准备工作 在 Windows 平台上…

AI写作(四)预训练语言模型:开启 AI 写作新时代(4/10)

一、预训练语言模型概述 ​ 预训练语言模型在自然语言处理领域占据着至关重要的地位。它以其卓越的语言理解和生成能力&#xff0c;成为众多自然语言处理任务的关键工具。 预训练语言模型的发展历程丰富而曲折。从早期的神经网络语言模型开始&#xff0c;逐渐发展到如今的大规…

图像处理实验一(Matlab Exercises and Image Fundamentals)

一、基本概念介绍 MATLAB是一种广泛使用的高性能语言&#xff0c;特别适用于数学计算、算法开发、数据分析和可视化。在图像处理领域&#xff0c;MATLAB提供了强大的工具和函数&#xff0c;使得图像的读取、处理和分析变得相对简单。通过MATLAB&#xff0c;用户可以实现从基本的…

番外-JDBC:2024年最新java连接数据库教程

前言 JavaScript的内容晚点更新&#xff0c;今天继续更新一点番外&#xff0c;今天更新的是jdbc&#xff0c;如何用java连接数据库 1.导包 要使java能够连接数据库我们需要导入一个包&#xff0c;请按照以下操作安装并导包 1.进入官网 MySQL 以上为官网链接进去后点击下载…

Ubuntu22.04安装DataEase

看到DataEase的驾驶舱&#xff0c;感觉比PowerBI要好用一点&#xff0c;于是搭建起来玩玩。Dataease推荐的操作系统是Ubuntu22.04/Centos 7。 下载了Ubuntu22.04和DataEase 最新版本的离线安装包 一.安装ubuntu22.04 在安装的时候&#xff0c;没有顺手设置IP地址信息&#xff…

vueRouter路由切换时实现页面子元素动画效果, 左右两侧滑入滑出效果

说明 vue路由切换时&#xff0c;当前页面左侧和右侧容器分别从两侧滑出&#xff0c;新页面左右分别从两侧滑入 效果展示 路由切换-滑入滑出效果 难点和踩坑 现路由和新路由始终存在一个页面根容器&#xff0c;通过<transition>组件&#xff0c;效果只能对页面根容器有效…

acwing算法基础03-递归,枚举

cWing 93. 递归实现组合型枚举 1.排序 考虑顺序 2. 组合 不考虑顺序 参数 -核心 递归 模板 1.指数型 选/不选 2. 排列 -考虑顺序 &#xff08;判重数组 不知道哪个数有有没有用过&#xff09;3.组合 不考虑顺序 数据范围 从n个数里选m个数 组合数中间点 取范围 #includ…

ASP.NET 部署到IIS,访问其它服务器的共享文件 密码设定

asp.net 修改上面的 IIS需要在 配置文件 添加如下内容 》》》web.config <system.web><!--<identity impersonate"true"/>--><identity impersonate"true" userName"您的账号" password"您的密码" /><co…

多角度审视推荐系统

参考自《深度学习推荐系统》——王喆&#xff0c;用于学习和记录 介绍 推荐工程师需要从不同的维度审视推荐系统&#xff0c;不仅抓住问题的核心&#xff0c;更要从整体上思考推荐问题。 具体包括以下内容&#xff1a; &#xff08;1&#xff09;推荐系统如何选取和处理特征…

从0开始机器学习--Day23--支持向量机

经过前面的学习&#xff0c;我们已经知道在解决问题时&#xff0c;重要的不仅仅是要在算法A或算法B中选择更优的&#xff0c;而是考虑怎么选择用于学习算法的特征和正则化参数&#xff0c;相比神经网络和逻辑回归&#xff0c;支持向量机在这两个方面做得更好。 优化目标(Optimi…

Vulnhub靶场案例渗透[9]- HackableIII

文章目录 一、靶场搭建1. 靶场描述2. 下载靶机环境3. 靶场搭建 二、渗透靶场1. 确定靶机IP2. 探测靶场开放端口及对应服务3. 扫描网络目录结构4. 敏感数据获取5. 获取shell6. 提权6.1 敏感信息获取6.2 lxd提权 一、靶场搭建 1. 靶场描述 Focus on general concepts about CTF…

生成 Django 中文文档 PDF 版

文章目录 背景克隆 Django 文档和翻译仓库配置 conf.py设置和同步翻译生成 .pot 文件运行 sphinx-intl update复制翻译文件 构建 PDF生成 tex 文件安装 MikTeX生成 PDF Sphinx 生成文档 背景 浏览看到一个帖子&#xff0c;有个评论说可以用 sphinx 构建一个 pdf&#xff0c;正…