redis应用-分布式锁

目录

什么是分布式锁

分布式锁的基本实现

引入过期时间

引入校验id

引入lua

引入看门狗

引入redlock算法


什么是分布式锁

在一个分布式系统中,也会涉及到多个节点访问同一个公共资源的情况,此时就需要通过锁来做互斥控制,避免出现类似于"线程安全"的问题.

而Java中的synchronized这样的锁只能在当前进程中生效,在分布式这样的多个进程多个主机的场景下就无能为力了.

在分布式系统中,有很多进程(每个服务器,都是独立的进程),因此synchronized就难以对现在的分布式系统中的多个进程之间产生制约.

分布式系统中,多个进程之间的执行顺序也是不确定的,充满随机性.

此时就需要分布式锁来控制.

分布式锁本质上是使用一个公共的服务器,来记录加锁状态.这个公共的服务器可以是redis,也可以是其他组件,比如mysql等,还可以是自己写的一个服务.


分布式锁的基本实现

通过一个键值对来表示锁的状态.

考虑一个买票的场景,现在车站提供了若干车次,每个车次的票数都是固定的.现在存在多个服务器节点,都可能需要处理这个买票的逻辑:先查询指定车次的车票,如果余票>0,则设置余票值-1.

客户端1先执行查询余票,发现剩余一张,在即将执行1->0的过程之前,客户端2也执行查询余票,查询到的也是剩余一张,客户端2也会执行1->0的过程,就出现了超卖.

显然上述场景存在"线程安全"问题,会出现超卖的情况,需要用锁来控制.

如何进行加锁?

在上述架构中引入一个redis,作为分布式锁的管理器.

此时,如果买票服务器1尝试买票,就需要先访问redis,在redis上设置一个键值对,比如key为车次,value随便设个值,比如1.

如果这个操作设置成功,就视为当前没有节点对该车次加锁,就可以进行数据库的读写操作了,操作完之后,再把redis上刚才的键值对删除掉.

如果在买票服务器1操作数据库的过程中,买票服务器2也想买票,也会尝试给redis上写一个键值对,key同样是车次,但是此时设置的时候发现该车次的key已经存在了,则认为已经有其他服务器正在持有锁,此时服务器2就需要等待或者暂时放弃了.

redis中提供了setnx操作,正好适合上述场景,key不存在则设置,存在则设置失败.


引入过期时间

当服务器1加锁之后,开始处理买票的过程,如果在此过程中服务器1意外宕机,就会导致后续的解锁操作无法执行,就可能引起其他服务器始终无法获取到锁的情况.

为了解决这个问题,就可以在设置key的同时引入过期时间,即这个锁最多持有多久,就应该被释放.

使用 set ex nx的方式,在设置锁的同时把过期时间也设置进去.此处只能使用一条命令来完成,不能拆分成setnx和expire.


引入校验id

所谓的加锁就是给redis上设置一个key-value,所谓的解锁就是给redis上这个key-value删除掉.

那么也就有可能出现,服务器1执行了加锁,服务器2执行了解锁.

当然服务器2不会进行这样的恶意删除,不过不能保证因为一些bug导致服务器2把锁误删掉.

为了解决上述问题,我们可以引入一个校验id.

比如可以把设置的键值对的值,不在简单的设置为一个而是设置成服务器的编号,形如"001:"服务器1".

这样就可以在删除key的时候,先校验当前删除key的服务器是否是当初加锁的服务器,如果是才能真正的删除,不是则不能删除.

但是很明显,解锁逻辑中的get和del两部操作并非是原子的!!!


引入lua

为了使解锁操作是原子的,可以使用redis的lua脚本功能.

上述情况来说,看起来重复执行DEL好像问题不大?实则不然!! 
主要是引入一个新的服务器,执行加锁就可能出现问题了. .
在线程A执行完DEL之后,B执行DEL之前 
服务器2的线程C正好要执行加锁(set),此时由于A已经把锁释放了,C的加锁是能够成功的!! 
但是紧接着,线程B DEL就到来了.就把刚刚服务器2的加锁操作给解锁了.
服务器1和服务器2进行加锁, key是资源的编号(比如车次),服务器的id是value.

新加的锁被删除了.归根结底是因为get和del不是原子产生的问题.

使用redis的事务可以解决上述问题,但是实践中往往使用更好的方案,lua脚本.

lua是一个变成语言,作为redis内嵌的脚本,lua语言特别轻量.

使⽤Lua脚本完成上述解锁功能.

上述代码可以编写成⼀个 .lua 后缀的⽂件, 由 redis-cli 或者 redis-plus-plus 或者 jedis 等客⼾端加载, 并发送给 Redis 服务器, 由 Redis 服务器来执⾏这段逻辑.
⼀个 lua 脚本会被 Redis 服务器以原⼦的⽅式来执⾏.
redis官方文档也明确说,lua属于是事务的替代方案.

引入看门狗

如果要在加锁的时候,给key设定过期时间.

过期时间设置多少合适呢?

如果设置过短,那么可能业务逻辑没有执行完,锁就被释放了.

如果设置的太长,就会导致锁释放不及时的问题.

更好的方式是动态续约.往往需要服务器这边有一个专门的线程,负责续约,把这个负责的线程就叫做看门狗(watch dog).

初始情况下,设置一个过期的时间(比如设置1s),就提前在还剩比如300ms的时候,如果当前任务还没执行完,就把过期时间在续上1s,等到时间又快到了,任务还没执行完,就在续.

如果服务器,中途崩溃了,自然就没有线程负责续约了,此时,锁也能在较短的时间内被自动释放!!!


引入redlock算法

实践中的 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 节点, ⽽要写个多个!! 分布式系统中任何⼀个节点都是不可靠的. 最终的加锁成功结论是 "少数服从多数的".

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

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

相关文章

@Autowired注入多态

如IBizStudyService接口有多个实现类BizStudyServiceImpl和BizStudyServiceExImpl,在Autowired注入时要用Qualifier指定实现类名称。 Autowired Qualifier("BizStudyServiceImpl") private IBizStudyService bizStudyService; 在实现类定义时要加上名称…

【开源】基于Vue和SpringBoot的计算机机房作业管理系统

项目编号: S 017 ,文末获取源码。 \color{red}{项目编号:S017,文末获取源码。} 项目编号:S017,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 登录注册模块2.2 课程管理模块2.3 课…

【QT】Qt类库的模块

目录 1.Qt基本模块 2.Qt附加模块 3.增值模块 4.技术预览模块 5.Qt工具 1.Qt基本模块 Qt基本模块是Qt在所有平台上的基本功能,它们在所有的开发平台和目标平台上都可用,在Qt5所有版本上是源代码和二进制兼容的。 Qtcore模块是Qt类库的核心,所有…

【2021研电赛】基于EAIDK-310的云端互联无人驾驶系统

本作品介绍参与极术社区的有奖征集|分享研电赛作品扩大影响力,更有重磅电子产品免费领取! 参赛单位:上海理工大学 参赛队伍:你说的都是对的 指导老师:蒋全 参赛队员:童锐,邹祖奇,胡涛 获奖情况&…

分享一个Python网络爬虫数据采集利器

前言 你是否曾为获取重要数据而感到困扰?是否因为数据封锁而无法获取所需信息?是否因为数据格式混乱而头疼?现在,所有这些问题都可以迎刃而解。让我为大家介绍一款强大的数据收集平台——亮数据Bright Data。 作为世界领先的数据…

聚观早报 |JFrog发布新功能;中科百孚减持龙芯中科股票

【聚观365】12月7日消息 JFrog发布新功能 中科百孚减持龙芯中科股票 商汤集团再回应做空报告 xAI融资新进展 苹果市值再次突破 JFrog发布新功能 流式软件公司、企业软件供应链平台提供商JFrog发布新功能,推出业界首款致力于加速安全软件建构与发布的端到端平台…

跟着GPT学习shell脚本,学习脚本中的各种符号(一)。

Shell脚本符号深入学习计划 第1周:基本符号和它们的用法 学习目标:掌握基本的Shell符号,如#, ;, &&, ||。内容: #用于注释。;用于在一行中分隔多个命令。&&和||用于连接命令,实现逻辑控制。 第2周&…

VectorDB的使用方法

🔗链接: https://github.com/jina-ai/vectordb 安装: 以下3个都要安装才可以使用VectorDB 1. Microsoft Visual C 14.00 Microsoft Visual C 14.0: https://blog.csdn.net/ViatorSun/article/details/118699938 2. DocArray pip install docarray 3. VectorDB …

springboot整合webservice修改cxf自动生成wsdl的soap:address location

近期系统中的webservice接口要上线 通过http://localhost:8080/webServices/testService?wsdl走网关访问时&#xff0c;返回的<soap:address location>是真实业务服务的ip:port。因为我们只能暴露网关的ip和端口&#xff0c;需要将真实服务的ip和端口隐藏起来。 Beanpu…

什么是神经网络的超参数

1 引言 超参数在神经网络的设计和训练中起着至关重要的作用。它们是在开始训练之前设置的参数&#xff0c;与网络的结构、训练过程和优化算法有关。正确的超参数选择对于达到最优模型性能至关重要。 2 神经网络结构的超参数 层数&#xff08;Layers&#xff09;&#xff1a; 决…

Elastcsearch:通过 Serverless 提供更多服务

作者&#xff1a;Ken Exner 人们使用 Elasticsearch 解决最大数据挑战的方式一直令我们感到惊讶。 从超过 40 亿次下载、70,000 次提交、1,800 名贡献者以及我们全球社区的反馈中可以清楚地看出这一点。 Elastic 在广泛的用例中发挥的作用促使我们简化复杂性&#xff0c;让搜索…

支付通道是什么?支付通道的价值体现在哪里?

支付通道是什么&#xff1f;什么是通道&#xff1f; “道”&#xff0c;人走路用的&#xff0c;从一个地点通向另一个地点。而支付通道也是这样&#xff0c;只不过道路上的不是人&#xff0c;是资金流&#xff1b;也就是一个能把金钱从一个地方转移到另一个地方的方式。 支付…

不敢想象,会用大数据分析工具有多爽!

当业务人、小白会用大数据分析工具会有多爽&#xff1f;1、再不用去跟IT沟通需求&#xff0c;等IT取数开发报表&#xff1b;2、有新的分析需求&#xff0c;我当场就能分析数据&#xff0c;获取信息&#xff1b;3、有足够多的数据信息支撑业务分析决策&#xff0c;实现从经验决策…

Spring中@Contorller和@ResController的区别

Controller 和 RestController 是在 Spring 框架中用于定义控制器的注解&#xff0c;它们之间有一些区别。 一、Contorller Controller 注解用于标识一个类为控制器&#xff08;Controller&#xff09;。控制器负责处理客户端请求并返回相应的响应。在使用 Controller 注解时&…

【富文本编辑器】原生JS使用WangEditor和vue上传图片前后端demo

【富文本编辑器】原生JS使用WangEditor上传图片前后端demo 第一步 HTML 第二步 初始化WangEditor与图片上传回调函数 第三步 后端返回数据体封装 第四步 后端接口上传图片&#xff0c;并返回图片地址 最近&#xff0c;我遇到了这样一个问题&#xff1a;因为我们的项目是基于…

MySQL和MongoDB简介以及它们之间的区别

本文主要介绍MySQL和MongoDB的简介以及它们之间的区别。 目录 MySQL简介MySQL的优缺点MySQL的应用场景MongoDB简介MongoDB的优缺点MongoDB的应用场景MySQL和MongoDB的区别 MySQL简介 MySQL是一种开源的关系型数据库管理系统&#xff0c;是世界上最流行的数据库之一。它支持多用…

DAPP开发【10】express.js的使用

Express.js 是一种流行、轻量级的开源 Web 应用程序框架&#xff0c;用于开发基于 Node.js 的服务器端 Web 应用程序。它提供了强大的功能集&#xff0c;适用于 Web 和移动应用程序。Express.js 旨在支持单页、多页和混合式 Web 应用程序的开发。Express.js 提供了广泛的功能&a…

Linux软件包管理器yum

yum—Linux应用商店 前言Linux的软件安装1. 源代码安装2. rpm安装使用rpm安装升级或者更新.rpm软件包卸载指定的.rpm软件包查询已安装的.rpm软件包优缺点 3. yum安装&#xff08;推荐&#xff09;yum源使用yum命令&#xff08;检测是否有网&#xff1a;ping指令&#xff09;优缺…

Nginx的反向代理与负载均衡

概念介绍 1). 正向代理 正向代理服务器是一个位于客户端和原始服务器(origin server)之间的服务器&#xff0c;为了从原始服务器取得内容&#xff0c;客户端向代理发送一个请求并指定目标(原始服务器)&#xff0c;然后代理向原始服务器转交请求并将获得的内容返回给客户端。 …

51单片机的硬件组成的功能以及40个引脚的功能

AT89S51单片机的硬件组成 本文主要涉及AT89S51单片机的硬件结构&#xff0c;与89C51还是存在一定的区别文中有说明&#xff0c;介绍了单片机的各硬件的基本功能&#xff0c;并详细介绍了单片机40个引脚的功能 文章目录 AT89S51单片机的硬件组成一、 AT89S51单片机的硬件组成1.1…