[Redis]典型应用——分布式锁

什么是分布式锁?

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

举个例子,在平时抢票时,多个用户可能会同时买票,但票数有限,现在存在多个服务器节点,都可能需要处理这个买票的逻辑:先查询指定车次的余票,如果余票>0,则设置余票值-=1 。显然,这样的情况是存在线程安全问题的,如果不加锁控制,就会导致超卖或数据错误。但是,这可能涉及到不同的机器,而不是传统的同一个线程可以加锁,不同的机器间怎么保证线程安全呢?

为了解决上述问题,我们就可以把redis作为架构中分布式锁的管理器。

分布式锁本质上就是一个架构内一台公共的服务器,用来记录加锁状态,而redis就可以完成这样的工作

工作原理 

 为了防止出现线程安全问题,我们可以在服务器操作数据库之前要先访问redis,在redis上设置一个键值对(mutex:1),如果设置成功,视为获取锁成功,就可以对数据库操作,操作完后,就把redis对应的数据删掉,视为释放锁。在这期间,如果其他服务器想操作数据库,也必须先设置同样的key,设置失败就不能访问数据库。

引入过期时间

但是上述方案还是有问题,如果设置key后,服务器宕机了怎么办?锁就永远无法释放了,所以我们就要设置key的过期时间

服务器在设置key的时候,同时设置key的过期事件,也就是说这个锁最多持有多久,过期自动释放。

注意!此处的过期时间只能使用一个命令的方式设置

如果分开多个操作,比如setnx之后,再来一个单独的expire,由于Redis的多个指令之间不存在关 联,并且即使使用了事务也不能保证这两个操作都一定成功,因此就可能出现setnx成功,但是expire 失败的情况

此时仍然会出现无法正确释放锁的问题

 引入校验id

有没有可能自己设置的锁被别人释放了呢?请看下图

可能会因为一些潜在bug或误操作,释放了别人设置的锁,就会发生很大的问题

为了解决这个问题,我们可以引入校验id

 也就是设置key时设置的value改成有意义的能表示身份的值,比如可以把客户端编号,几号客户端设置的key就把value设置成几

这样,在释放锁,也就是删除key的时候,先校验删除的key的value是不是对应当初加锁的值,如果是,再删数据

引入lua

但是上面这个操作中,先get key再del key 这两步并不是原子的,也会有线程安全问题。

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

Lua也是一个编程语言.读作"撸啊"。是葡萄牙语中的"月亮"的意思

为什么redis会选择lua作为内嵌的脚本语言呢?因为Lua语法简单精炼,执行速度快,解释器也比较轻量,内嵌到redis中不会太过于臃肿

lua脚本可以编写成一个.lua后缀的文件,可以由 redis-cli 发送给redis,由redis服务器来执行脚本

一个lua脚本会被redis服务器以原子的方式执行

引入看门狗(watch dog)

上述方案仍然有一定问题,当我们设置过期时间(比如10s)后,如果任务还没有执行完,锁就已经过期失效了,怎么办?

那就可以引入看门狗,本质上是服务器上的一个单独的线程,通过这个线程来对锁过期时间进行"续约"

比如说,我们设置10s过期,设置看门狗每隔3s检测一次,每过3s,看门狗就去判定当前任务是否完成,如果任务完成了,就释放锁,如果任务未完成,就把过期时间重新设置成10s(续约)

值得一提的是,看门狗线程应该是业务服务器的线程,而不是redis服务器的线程

这样,不用担心锁提前过期,就算服务器挂了,看门狗线程也就挂了,就没人去续约,过期就会释放锁了

引入redlock算法

到这里,方案还是有一定问题,如果redis服务器(也就是分布式锁管理器)挂了,怎么办?那我们可以对redis服务器设计主从架构,保证redis服务器的可用性

那么就有一个问题,如果当我获取锁之后,redis主服务器挂了,从服务器变成了主服务器,但是加锁的数据还没有同步,这时候获取的锁失效了,别的服务器仍然可以获取锁

为了解决这个问题,Redis的作者提出了Redlock算法

我们引入一组Redis节点,其中每一组Redis节点都包含一个主节点和若干从节点.并且组和组之间存储的数据都是一致的,相互之间是"备份"关系

首先,获取锁

客户端依次向Redis 节点(通常是 5 个)请求加锁。每个节点使用相同的 key 和一个唯一的随机值(UUID)(校验用)。

客户端在每个节点上设置锁的过期时间(TTL),以防止锁的持有者崩溃后锁无法释放。

如果客户端无法在某个节点上设置锁(例如,实例不可用或已经被其他客户端持有锁),则立即尝试下一个节点。

其次,检查锁的有效性

客户端计算从开始尝试加锁到完成加锁操作的总时间。

如果总时间小于锁的 TTL ,且客户端至少在 N/2 + 1 个节点上成功加锁,则认为锁获取成功。如果锁获取失败(未能在足够多的节点上成功加锁),客户端应立即在所有节点上释放已获取的锁。

比如说锁过期时间为50ms,有5个redis节点,从给第一个节点加锁开始算,到最后一个节点加锁截止,如果加起来总时间小于锁的过期时间(50ms),而且至少有3个节点加锁成功,那么就获取一个锁成功(50ms)

因为如果加锁流程时间太长,比如锁过期时间是50ms,结果光去各个节点加锁就用了100ms,那肯定有部分锁都已经过期了,这时候也就不能认为加锁成功了 

最后,释放锁

客户端在所有实例上依次释放锁。释放锁时,客户端需要检查锁的值是否与自己持有的随机值一致,以确保只有持有锁的客户端才能释放锁。

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

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

相关文章

大语言模型-文本向量模型评估基准 MTEB

MTEB(Massive Text Embedding Benchmark) 涵盖112种语言的58个数据集,包含如下8种任务。 1、双语文本挖掘(Bitext Mining) 任务目标: 在双语语料库中识别语义等价的句子对。 任务描述: 输入…

Nature子刊 | ATAC-seq、RNA-seq和蛋白组联合分析揭示脂质激活转录因子PPARα在肾脏代偿性肥大的作用机制

2023年6月,美国国立心肺血液研究所的研究团队在Nature Communications上发表题为“Signaling mechanisms in renal compensatory hypertrophy revealed by multi-omics”的文章,该研究通过在单侧肾切除的小鼠模型中使用多组学方法(蛋白质组学…

深入浅出WebRTC—NACK

WebRTC 中的 NACK(Negative Acknowledgment)机制是实时通信中处理网络丢包的关键组件。网络丢包是常见的现象,尤其是在无线网络或不稳定连接中。NACK 机制旨在通过请求重传丢失的数据包来减少这种影响,从而保持通信的连续性和质量…

Open3D 非线性最小二乘法拟合空间球

目录 一、概述 1.1原理 1.2实现步骤 二、代码实现 2.1关键代码 2.1.1定义残差函数 2.1.2拟合球面 2.2完整代码 三、实现效果 3.1原始点云 3.2拟合后点云 3.3结果数据 前期试读,后续会将博客加入下列链接的专栏,欢迎订阅 Open3D点云算法与点…

spark 动态资源分配dynamicAllocation

动态资源分配,主要是spark在运行中可以相对合理的分配资源。 初始申请的资源远超实际需要,减少executor初始申请的资源比实际需要少很多,增多executorSpark运行多个job,这些job所需资源有的多有的少,动态调整executor…

Automation Anywhere推出新一代AI+自动化企业系统,助力企业实现10倍商业增长

RPA厂商纷纷进军AI Agent ( AI 代理)领域,陆续推出创新产品。最近,Automation Anywhere宣布推出其新的AI 自动化企业系统,该系统结合AI和自动化技术,以实现指数级的业务成果。 在Imagine 2024大会上首次亮相的这款新产品&#xf…

前端实现视频播放添加水印

一、效果如下 二、代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title> </head> <body><style>.container {position: relative;}.base {width: 300px;hei…

鸿蒙开发StableDiffusion绘画应用

Stable Diffusion AI绘画 基于鸿蒙开发的Stable Diffusion应用。 Stable Diffusion Server后端代码 Stable Diffusion 鸿蒙应用代码 AI绘画 ​ 使用Axios发送post网络请求访问AI绘画服务器 api &#xff0c;支持生成图片保存到手机相册。后端服务是基于flaskStable Diffusion …

ACM中国图灵大会专题 | 图灵奖得主Manuel Blum教授与仓颉团队交流 | 华为论坛:面向全场景应用编程语言精彩回顾

ACM 中国图灵大会&#xff08;ACM Turing Award Celebration Conference TURC 2024&#xff09;于2024年7月5日至7日在长沙举行。本届大会由ACM主办&#xff0c;in cooperation with CCF&#xff0c;互联网之父Vinton Cerf、中国计算机学会前理事长梅宏院士和廖湘科院士担任学术…

移动端如何离线使用GPT

在移动端离线使用GPT&#xff0c;只需要一个app&#xff1a;H2O AI Personal GPT 是H2OAI上架的一款app&#xff0c;可离线使用&#xff0c;注重数据隐私&#xff0c;所有数据都只存储在本地。对H2OAI感兴趣的伙伴&#xff0c;可移步&#xff1a;https://h2o.ai 该app支持的模…

Intel和AMD用户再等等!微软确认Win11 24H2年底前登陆

微软近日确认&#xff0c;Windows 11 24H2版本将于2024年底前正式登陆使用英特尔和AMD处理器的PC。 根据微软介绍&#xff0c;Windows 11 24H2将作为传统功能更新&#xff0c;将在今年晚些时候提供给所有设备。 此前&#xff0c;微软已向搭载骁龙X Plus和X Elite系列处理器的Co…

作为爬虫工程师,在封装API时如何做得更好

在数据驱动的时代&#xff0c;爬虫工程师的角色日益重要。他们不仅是数据的收集者&#xff0c;更是数据的桥梁构建者&#xff0c;通过编写高效、稳定的爬虫程序&#xff0c;将互联网上的海量信息转化为有价值的数据集。而在这一过程中&#xff0c;API&#xff08;应用程序接口&…

深度剖析机构号矩阵系统:如何根据业务需求做出明智选择

在数字化营销的浪潮中&#xff0c;短视频平台如抖音、快手等已成为品牌传播和用户互动的重要渠道。为了更高效地管理这些平台的账号&#xff0c;机构号矩阵系统应运而生。本文将深度剖析机构号矩阵系统&#xff0c;并探讨如何根据业务需求做出明智的选择。 机构号矩阵系统概述…

网络爬虫入门(学习笔记)

爬取网页源代码 抓取百度首页的HTML源代码&#xff0c;并将其保存到一个名为baidu.html的文件中。打开这个文件&#xff0c;可以看到一个和百度首页一模一样的页面。 from urllib.request import urlopen# 发送请求并获取响应 response urlopen("http://www.baidu.com&q…

jenkins+gitlab+harbor+maven自动化容器部署

一、gitlab安装配置 1.1、安装 由于比较懒啊&#xff01;这里就直接使用docker安装了啊&#xff01; 没事先更新一个yum源&#xff1a;yum update -y 整一个gitlab镜像&#xff1a;docker pull gitlab/gitlab-ce 运行一个gitlab容器&#xff1a;docker run -d -p 8443:443 -p…

函数定义、合约与面向对象(以太坊solidity合约)

函数定义、合约与面向对象&#xff08;以太坊solidity合约&#xff09; 1-函数定义、构造与多态2-事件日志3-面向对象特征 1-函数定义、构造与多态 创建合约就是创建类&#xff0c;部署合约就是实例化 合约的方法还支持多态 还能使用第三方的库进行开发 整个合约部署后&…

【第4章】Spring Cloud之Nacos单机模式支持mysql

文章目录 前言一、初始化1. 初始化数据库2. 修改配置文件 二、效果1. 重新启动2. 新增用户 总结 前言 在0.7版本之前&#xff0c;在单机模式时nacos使用嵌入式数据库实现数据的存储&#xff0c;不方便观察数据存储的基本情况。0.7版本增加了支持mysql数据源能力&#xff0c;具…

【devops】gitlab 实现cicd 实践

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

HarmonyOS页面跳转和页面间传值

IndexPage 定义一个参数类 export class RouterParams {src:stringconstructor(str:string) {this.src str} }点击按钮后&#xff0c;将创建的RouterParams 对象传递到第二页 Button($r(app.string.next)).fontSize(16).width(300).height(50).backgroundColor($r(app.color.…

Android 视频音量图标

attrs.xml <?xml version"1.0" encoding"utf-8"?> <resources><!--图标颜色--><attr name"ijkSolid" format"color|reference" /><!--喇叭底座宽度--><attr name"ijkCornerWidth" form…