Redis ①⑦-分布式锁

在这里插入图片描述

分布式锁

分布式锁是锁的一种,都是为了解决多线程/多进程环境下,对共享资源的访问冲突问题。

不过,像 Java 的 synchronized 或者 C++ 的 mutex 这种锁,都是进程内的锁,而分布式锁则是跨越进程/机器的锁。也就是可以针对多个进程、多台服务器的的共享资源进行加锁

考虑买票的场景,现在车站提供了若干个车次,每个车次的票数都是固定的。

现在存在多个服务器节点,都可能需要处理这个买票的逻辑:先查询指定车次的余票,如果余票 > 0,则设置余票值 -= 1在这里插入图片描述

上述场景如果任何处理,就会存在 “线程安全问题”。

当多个客户端同时购买一个车次的票时,此时余票数量还未作出相应的更新。
假设此时只剩一张余票,当多个客户端都判断 余票 > 0 成功后,导致余票 “被卖出去了多张”,但实际只剩一张了,这就是是出现 “超卖” 的情况。

为了解决这个问题,引入分布式锁。

实现分布式锁

引入 SETNX

既然普通的锁无法跨越多个进程/机器,那就只能单独找一台服务器作为锁的管理者,该服务器可以使用 Redis 来实现分布式锁。

某个客户端执行买票请求前,先访问 Redis,在 Redis 上设置一个键值对。比如 key 就是车次,value 随便设置个值 (比如 1)。

当另一个客户端也想要访问买票请求时,也先访问 Redis,在 Redis 上设置一个 key 为该车次的键值对,如果发现 key 已经设置过了,说明有其他客户端正在处理该车次的票,则该客户端要么直接放弃,要么等待。

而当该客户端处理完买票请求后,直接删除该 key 即可。就相当于是解锁操作。

如何实现?可以使用 Redis 的 setnx 命令,该命令的作用是设置一个键值对,当且仅当键不存在时才设置成功。

引入过期时间

但是上述方案存在问题,如果某个客户端设置完锁 key 后,突然挂掉了,此时锁一直存在,其他客户端就无法获取到锁,导致其他客户端无法正常处理买票请求。

所以,我们可以给锁引入一个过期时间,比如 1 秒,即这个锁的最长持有时间,如果锁的过期时间到了,则自动释放锁。

如何实现?可以使用 Redis 的 set ex nx 命令,在设置锁的同时把过期时间加上。

能否先设置锁,然后通过 expire 的方式设置过期时间?答案不行的,因为这是两条命令了,就不是原子的了,就有概率发生 “线程安全问题”。

引入校验ID

上述依然存在问题,是否可能会出现 服务器1 设置锁,服务器2 误删锁。答案是可能的,保不齐代码哪里会出现 bug,导致锁被误删。

正常的解锁操作是必须由加锁的这一方执行的。

所以,我们可以给每个服务器设置一个唯一的 ID,在设置锁,将这个锁的 value 设置为这个 ID。

在解锁时,先获取到该锁,校验其 value 是否与当前服务器的 ID 相同,如果相同,则执行解锁操作。如果不相同,则忽略该操作。

引入 Lua 脚本

上述解锁的判断依然可能存在问题,根本原因还是可能造成 “线程安全问题”。

校验和删除这两个操作,不是原子的,则可能会出现下图的情况:在这里插入图片描述

如果发生上述情况,命令按照上图的顺序执行,会导致 服务器1 删除锁之后,服务器3 来加锁了,但是马上又被 服务器2 给删了。

我们可以使用事务将这两个操作打包成一个原子的操作,但是,Redis 的事务比较鸡肋,形同虚设。

Redis 官方文档明确说,Lua 脚本可以作为事务的替代方案。Redis 在执行 Lua 脚本时,就相当于是执行一条命令,只有全部命令都执行完了,才会服务其他客户端。

使用 Lua 脚本完成上述功能:

if redis.call("setnx", KEYS[1]) == ARGV[1] thenreturn redis.call("expire", KEYS[1])
elsereturn 0
end

上述代码可以编写成一个 .lua 后缀的文件,由 redis-cli 或者 redis-plus-plus 或者 jedis 等客户端加载,并发送给 Redis 服务器,由 Redis 服务器来执行这段逻辑。

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

引入看门狗

上述的方案依然存在问题,就是锁的过期时间较为固定。

如果锁的过期时间设置的过短,可能业务逻辑还没处理完就释放锁了。
如果锁的过期时间设置的过长,导致锁的持有时间太长,导致其他客户端无法正常处理请求。

所以我们采用动态续约的机制,引入一个 “看门狗” 线程,每隔一段时间,如果当前业务还没执行完,就续上锁的过期时间。

引入 Redlock 算法

实践中的 Redis 一般是以集群的方式部署的(至少是主从的形式,而不是单机)。那么就可能出现以下比较极端的情况:

  • 服务器1master 节点进行加锁操作。这个写入 key 的过程刚刚完成,master 就挂了;slave 节点升级成了新的 master 节点。
  • 但是由于刚才写入的这个 key 尚未来得及同步给 slave,此时就相当于 服务器1 的加锁操作形同虚设了,服务器2 仍然可以进行加锁(即给新的 master 写入 key。因为新的 master 不包含刚才的 key)。

为了解决这个问题,Redis 官方提出了 Redlock 算法。

我们引入一组 Redis 节点。其中每一组 Redis 节点都包含一个主节点和若干从节点。并且组和组之间存储的数据都是一致的,相互之间是 “备份” 关系(而并非是数据集合的一部分。这点有别于 Redis cluster)。

加锁的时候,按照一定的顺序,写多个 master 节点。在写锁的时候需要设定操作的 “超时时间”。比如 50ms。即如果 setnx 操作超过了 50ms 还没有成功,就视为加锁失败。

如果给某个节点加锁失败,就立即再尝试下一个节点。

当加锁成功的节点数超过总节点数的一半,才视为加锁成功。

这样的话,即使有某些节点挂了,也不影响锁的正确性。

同理,释放锁的时候,也需要把所有节点都进行解锁操作。(即使是之前超时的节点,也要尝试解锁,尽量保证逻辑严密)。

简而言之,Redlock 算法的核心就是,加锁操作不能只写给一个 Redis 节点,而要写给多个!!!

分布式系统中任何一个节点都是不可靠的。最终的加锁成功结论是 “少数服从多数的”。

证逻辑严密)。

简而言之,Redlock 算法的核心就是,加锁操作不能只写给一个 Redis 节点,而要写给多个!!!

分布式系统中任何一个节点都是不可靠的。最终的加锁成功结论是 “少数服从多数的”。

由于一个分布式系统不至于大部分节点都同时出现故障,因此这样的可靠性要比单个节点来说靠谱不少。

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

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

相关文章

OpenCV-图像预处理➀【图像颜色空间转换、灰度化实验、二值化处理、镜像翻转 和 仿射变换】

文章目录先言一、图像颜色空间转换1.RGB颜色空间2.颜色加法3.颜色加权加法4.HSV颜色空间5.图像转换(cvtColor())二、灰度实验1.灰度图2.图像灰度化(最大值法)3.图像灰度化(平均值法)4.图像灰度化&#xff0…

APP逆向 day9 安卓开发基础

一.前言 app逆向当然要学安卓基础啦!今天我们来教安卓基础当然,安卓基础不会教的很多,比java还要少,还是那句话,了解就好。 二.安卓环境搭建 2.1 安卓介绍 如果做安卓开发 需要会java代码安卓SDK(安卓提供的内置…

Jmeter的元件使用介绍:(三)配置元件详解02

六、计数器 可以用来做一些变量自增操作。 1、Starting value:定义初始值 2、递增:定义每次执行递增多少 3、Maximum value:定义承受的最大值 4、数据格式:可以不填,也可以定义成000;001;002等等任意格式都行。(1)如…

JavaWeb学习打卡15(JSP标签、JSTL标签、EL表达式)

EL表达式&#xff1a;${ }获取数据执行运算获取web开发的常用对象在pom.xml 文件中导入JSP、JSTL相关依赖&#xff1a;<!--JSP依赖--><!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --><dependency><groupId>java…

7.22数据结构——顺序表

文章目录一、思维导图二、实现顺序表的功能代码head.htest.cmain.c一、思维导图 二、实现顺序表的功能代码 head.h #ifndef __HEAD_H__ #define __HEAD_H__#include <stdio.h> #include <string.h> #include <stdlib.h> //数组的最大长度 #define MAXSIZE …

【如何无限制免费试用 IDEA || Pycharm(JB 全家桶)】

如何无限制免费试用 IDEA || Pycharm(JB 全家桶) 一、目标:解决 JB 全家桶试用时长痛点 如果你是程序员,大概率用过 JetBrains 家的 IDE——IDEA 写 Java、Pycharm 写 Python、WebStorm 做前端,体验确实顶流,但官方 30 天试用到期后,动辄几千的年费实在让人肉痛。 咱…

Qt(资源库和按钮组)

这一节是对上一节的补充&#xff0c;上一节提到QLabel类和QAabstractButton类&#xff0c;这节内容&#xff1a;1.如设置资源库&#xff0c;使用资源设置图片2. 使用按钮组管理多个按钮。一、资源库1. 资源库作用Qt的资源库&#xff08;Resource System&#xff0c;.qrc文件&am…

一道检验编码能力的字符串的题目

#include<iostream> #include<vector> #include<string> using namespace std; int bNum0,gNum0; int findEnd(string& s,int si){int lens.size();//当前字母在哪个字符串中,存入comp中string comp;if(s[si]b||s[si]o||s[si]y){comp"boy";bNu…

UniApp X 网络请求避坑指南:从 JS 到 UTS 的 JSON 数据处理全解析

在 UniApp 开发中&#xff0c;我们经常需要通过 uni.request 获取服务器返回的 JSON 数据&#xff0c;并将其绑定到页面或进行逻辑处理。但在 UniApp X&#xff08;基于 UTS&#xff09; 中&#xff0c;由于引入了 强类型语言特性&#xff0c;处理 JSON 数据的方式与 JS 有明显…

iOS 网络请求常用依赖库与系统自带 API 介绍与示例

iOS 网络请求常用依赖库与系统自带 API 介绍与示例 在 iOS 开发中&#xff0c;进行网络请求是几乎所有应用都不可或缺的功能。开发者有多种选择来处理网络通信&#xff0c;从系统自带的 URLSession 到各种流行的第三方库。下面我将为您介绍 URLSession、AFNetworking、Alamofir…

JavaScript 中 let 在循环中的作用域机制解析

一、let在循环中的特殊性 let作为ES6引入的块级作用域声明&#xff0c;在循环结构中存在特殊行为&#xff0c;其核心区别于var的函数作用域特性。理解这一特性对于编写正确的闭包逻辑至关重要。 在 ECMAScript 规范里&#xff0c;let声明的变量具有块级作用域特性&#xff0c;这…

@Subscribe@AllowConcurrentEvents解析这两个注解

@Subscribe@AllowConcurrentEvents解析这两个注解 @Subscribe 和 @AllowConcurrentEvents 是 Guava EventBus(Google 开源的事件总线框架)中用于处理事件订阅的注解,主要用于实现组件间的解耦通信。下面分别解析: 1. @Subscribe 注解 作用:标记一个方法为事件订阅者方法,…

好看的小程序推广单页HTML源码 可用作导航页

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 响应式的小程序推广单页HTML源码。这个设计采用了现代化的UI元素&#xff0c;包含吸引人的标题、特性展示、二维码区域和行动号召按钮。 二、效果展示 1.部分代码 代码如下&#xff0…

华为仓颉编程语言实践体验

华为仓颉编程语言实践体验 目前华为仓颉编程语言因为其推出时间较短&#xff0c;生态系统不完善。官网资料权威&#xff0c;但比较庞大难懂。快速实验入门&#xff0c;是学习一门编程语言的法宝。网上靠谱的资料稀少&#xff0c;特此撰文介绍&#xff0c;帮助初学者减少挫折感&…

YOLOv11实战,使用YOLOv11训练自己的数据集和推理(附YOLOv11网络结构图)

2024年计算机视觉领域的颠覆性突破,YOLOv11以22%的参数量减少和0.3%的mAP提升重新定义实时目标检测的边界 本文将手把手带你完成YOLOv11的全流程实战,包含环境配置、数据准备、模型训练、推理部署及创新优化方案,并深度解析其网络架构设计思想。 一、YOLOv11核心创新解析 …

macOS xcode打包ios测试ipa应用包

可以参考&#xff1a; https://blog.csdn.net/sinat_34104446/article/details/133684756 过程中遇到很多稀奇古怪的报错&#xff0c;基本重启电脑即可解决。。。在我按照上面的步骤申请并导入新证书后&#xff0c;还遇到了一个问题&#xff1a;解决办法&#xff1a; https://b…

STM32基础知识学习笔记:ICODE、DCODE、DMA等常见名词的解释

基于AI生成内容。 ICODEICODE&#xff1a;指令总线&#xff08;Instruction Bus&#xff09; 主要用于处理 CPU 对程序指令的读取操作。它是 STM32 存储架构中重要的组成部分&#xff0c;与数据总线&#xff08;DCODE&#xff09;、系统总线&#xff08;System Bus&#xff09;…

谁将统治AI游戏时代?腾讯、网易、米哈游技术暗战

游戏行业的“产能天花板”正被AI技术轰然击穿。腾讯、网易、米哈游……所有的游戏厂商都在押注AI&#xff0c;腾讯混元发布混元游戏视觉生成平台&#xff0c;分钟级生成高精度游戏角色&#xff1b;网易《蛋仔派对》借AI实现UGC创作平民化&#xff1b;米哈游新作更以实时多模态对…

基于springboot的工商局商家管理系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…

ABP VNext + Razor 邮件模板:动态、多租户隔离、可版本化的邮件与通知系统

&#x1f680; ABP VNext Razor 邮件模板&#xff1a;动态、多租户隔离、可版本化的邮件与通知系统 &#x1f4da; 目录&#x1f680; ABP VNext Razor 邮件模板&#xff1a;动态、多租户隔离、可版本化的邮件与通知系统&#x1f31f; 一、TL;DR&#x1f4c8; 二、系统流程图…