Redis 分布式锁:线程安全在分布式环境中的解决方案

news2024/9/22 4:20:07

Redis 分布式锁:线程安全在分布式环境中的解决方案

  • 一 . 分布式锁
  • 二 . 分布式锁的实现策略
    • 2.1 引入 setnx
    • 2.2 引入过期时间
    • 2.3 引入校验 ID
    • 2.4 引入 lua 脚本
    • 2.5 引入看门狗
    • 2.6 引入 redlock 算法

Hello , 大家好 , 这个专栏给大家带来的是 Redis 系列 ! 本篇文章给大家讲解的是 Redis 的分布式锁. 我们会深入探讨分布式锁的概念和实现策略,这是分布式系统中确保多个进程间操作顺序和线程安全的重要机制。由于传统的锁机制仅在单个进程内部有效,分布式锁应运而生,以解决跨进程和跨主机的同步问题。

在这里插入图片描述
本专栏旨在为初学者提供一个全面的 Redis 学习路径,从基础概念到实际应用,帮助读者快速掌握 Redis 的使用和管理技巧。通过本专栏的学习,能够构建坚实的 Redis 知识基础,并能够在实际学习以及工作中灵活运用 Redis 解决问题 .
专栏地址 : Redis 入门实践

一 . 分布式锁

我们之前在多线程阶段学习到了一个问题 : 线程安全问题 , 通过线程安全问题引入了 “锁” 的概念 .

但是我们之前学习过的锁 , 本质上是只能在一个进程内部生效 , 而我们分布式系统中 , 是存在很多进程的 , 并且很多进程都是跨主机的 . 所以我们之前的锁就很难在分布式系统中发挥作用 , 并且在分布式系统中多个进程之间的执行顺序也是不确定的 , 更何必线程了 .

所以我们就需要引入一个新的 “分布式锁” 来解决上述问题

比如我们现在有这样的一个场景 : 买票

二 . 分布式锁的实现策略

2.1 引入 setnx

我们刚才介绍分布式锁的时候 , 触发查询操作的时候 , 就需要先在 Redis 中设置一个键值对 , 表示我现在正在查询 , 如果其他客户端查询这个键值对不为空 , 他就知道了我需要阻塞等待 .

那这个键值对实际上就是不存在才去设置 , 如果存在就不设置 , 那这不就是我们的 setnx 操作吗 .

虽然使用 setnx 可以得到分布式加锁效果 , 但是加锁之后我们还需要解锁 , 就可以使用 del 命令来去解锁 , 来去删除掉 Redis 中的键值对 .

但是我们考虑一个极端的情况 : 某个服务器加锁成功了 (setnx 执行成功) , 但是在执行后续逻辑过程中 , 程序崩溃了 (也就是没有执行到解锁操作 , 也就是 del 命令) , 这就比较尴尬了 .

2.2 引入过期时间

我们可以给设置的 key 设置过期时间 , 一旦时间到了 , key 就会自动被删除掉了 .

我们可以使用 set ex nx 这样的命令来去设置 .

但是使用 setnx + expire 这两条命令是不行的 , 因为 Redis 的多个命令是无法保证原子性的 , 就有可能出现一个成功一个失败的情况 . 相比之下 , 使用一条命令设置更加稳妥 .

这样的话 , 如果出现极端情况导致某个服务器挂了 , 没有正确的释放锁 , 那这个锁到达过期时间也就会自动释放了 .

2.3 引入校验 ID

我们介绍的 , 所谓分布式锁

  • 加锁就是给 Redis 上设置一个 key-value
  • 解锁就是将 Redis 上的 key-value 删除掉

那就有可能出现服务器 1 执行了加锁 , 服务器 2 执行了解锁 , 这样就出现一些不可预料的错误 , 导致分布式锁形同虚设 , 从而进一步引起超卖问题 .

那为了解决这个问题 . 就需要引入一些校验机制

  1. 给服务器编号 , 每一个服务器都有自己的标识
  2. 进行加锁的时候 , 设置 key-value , key 对应着要针对哪个资源进行加锁 , value 就可以存储刚才服务器的编号 , 标识出当前这个锁是哪个服务器加上的
  3. 后续解锁的时候 , 就可以针对 value 进行校验了 . 在解锁的时候先查询一下这个锁对应的服务器编号 (get key 操作) , 然后判定一下这个编号是否就是当前执行解锁操作的服务器编号 . 如果是才能执行 del , 如果不是就执行失败 .

那这些逻辑 , 就需要服务器端来去完成的逻辑 , 通过上述校验规则 , 就可以有效避免 “锁误删” 的概念 .

2.4 引入 lua 脚本

我们在解锁操作的时候 , 需要先查询判定 , 再进行 del 操作 . 那这两个操作不是原子的 , 就也有可能出现问题 .

比如 : 一个服务器内部 , 也有可能是多线程的 . 此时就有可能一个服务器中两个线程都在执行上述解锁操作

我们可以使用 Lua 语言来去编写一些逻辑 , 然后把这个脚本上传到 Redis 服务器上 , 然后就可以让客户端来控制 Redis 执行上述脚本了 . 并且 Redis 执行 Lua 脚本的过程 , 也是原子的 , 实际上就相当于执行一条命令 .

我们可以给一个示例代码来看一下 :

-- ARGV 是调用其他的脚本,需要给定参数,此处就需要传入一个服务器的 ID
if redis.call('get',KEYS[1]) == ARGV[1] then
	return redis.call('del',KEYS[1]) -- ID 匹配就执行删除操作
else
	return 0
end;

2.5 引入看门狗

那新的问题也就出现了 , 我们在加锁的时候需要设置过期时间 . 那这个过期时间设置成多少合适 ?

  • 如果设置的太短 , 就有可能在业务逻辑执行完毕之前 , 锁就被释放了
  • 如果设置的太长 , 就也会导致锁释放的不及时的问题

相比之下 , 我们更倾向于 “动态续约” 这种方式 .

在初始情况下 , 设置一个过期时间 (比如 : 设置 1s) , 就提前在还剩 300ms 的时候 (数值可以灵活调整 , 只是举个例子) , 判断当前任务是否执行完 . 如果当前任务还没执行完 , 就把过期时间再续上 1s . 等到时间又快到了 , 任务还没执行完 , 那就继续续约 .

如果服务器中途崩溃了 , 自然就没人负责续约了 , 此时锁就能够在较短时间内被自动释放 .

2.6 引入 redlock 算法

我们使用 Redis 来作为分布式锁 , 那 Redis 本身有没有可能挂了呢 ?

当然有可能 , 要想保证高可用 , 我们就需要通过一系列的 “预案演戏” .

我们之前也学习过各种场景

  • 主从复制
  • 哨兵 : 保证高可用的最佳方案
  • 集群 : 更多的是解决存储空间不足的问题

那如何使用哨兵保证高可用的呢 ?

我们进行加锁操作 (set nx ex) , 就是把 key 写入到主节点中 , 然后同步给从节点 . 哨兵节点负责监控每个节点的工作状态 , 如果主节点挂了 , 就有哨兵自动的把从节点升级成主节点 , 进一步保证刚才的加锁操作依然有效 .

但是主节点和从节点之间同步数据是存在延时的 . 可能主节点收到了 set 请求 , 还没来得及同步给从节点 , 主节点就先挂了 . 即使从节点升级成了主节点 , 但是刚才加锁操作也是丢失的了 .

作为分布式系统 , 就需要随时考虑某个节点挂了的情况 , 需要保证某个节点挂了不会影响到大局

Redis 作者给出的方案是 redlock 算法 , 实际上就是一个冗余的思路

那此时 , 如果进行加锁操作 , 就会按照一定的顺序针对这些组的 Redis 都进行加锁操作 .

如果某个节点挂了 , 那就继续给下一个节点加锁即可 .

如果当前加锁成功的个数大于当前总节点总数的一半 , 我们就认为加锁成功 . 此时就不会因为某个 Redis 节点挂了导致影响整体操作 .

同时 , 解锁的时候也会把所有节点都设置一遍解锁操作 .


到此为止 , 我们分布式锁的内容也介绍完毕了 , 整个 Redis 模块我们也就介绍完毕了 , 希望大家能够通过我的文章了解并学习到 Redis 相关的知识 .
如果对你有帮助的话 , 还请一键三连~ 咱们下个专题见
在这里插入图片描述

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

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

相关文章

Flutter 中的低功耗蓝牙概述

随着智能设备数量的增加,控制这些设备的需求也在增加。对于多种使用情况,期望设备在需要进行控制的同时连接到互联网会受到很大限制,因此是不可行的。在这些情况下,使用低功耗蓝牙(也称为 Bluetooth LE 或 BLE&#xf…

[yolov5] --- yolov5入门实战「土堆视频」

1 项目介绍及环境配置 下载yolov5 tags 5.0源码,https://github.com/ultralytics/yolov5/tree/v5.0,解压 Pycharm 中创建conda虚拟环境 激活conda虚拟环境 根据作者提供的requirements.txt文件,pip install -r requirements.txt 如果作者没有…

【Spring Boot】 SpringBoot自动装配-Condition

目录 一、前言二、 定义2.1 Conditional2.2 Condition2.2.1 ConditionContext 三、 使用说明3.1 创建项目3.1.1 导入依赖3.1.2 添加配置信息3.1.3 创建User类3.1.4 创建条件实现类3.1.5 修改启动类 3.2 测试3.2.1 当user.enablefalse3.2.2 当user.enabletrue 3.3 小结 四、改进…

如何实现加密功能

文章目录 1. 概念介绍2. 方法与功能2.1 基本用法2.2 加密算法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"FlutterCacheManager组件"相关的内容,本章回中将介绍一个加密工具包.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 加密主要…

基于YOLO8的图片实例分割系统

文章目录 在线体验快速开始一、项目介绍篇1.1 YOLO81.2 ultralytics1.3 模块介绍1.3.1 scan_task1.3.2 scan_taskflow.py1.3.3 segment_app.py 二、核心代码介绍篇2.1 segment_app.py2.2 scan_taskflow.py 三、结语 代码资源:计算机视觉领域YOLO8技术的图片实例分割…

0x05 tomcat AJP文件包含漏洞(CVE-2020-1938)复现(脚本最终没有验证成功)

参考: 13-3 tomcat AJP文件包含漏洞(CVE-2020-1938)_omcat ajp文件包含漏洞 payload-CSDN博客 一、fofa 搜索使用该服务器的网站 网络空间测绘,网络空间安全搜索引擎,网络空间搜索引擎,安全态势感知 - F…

linux编译器——gcc/g++

1.gcc linux上先要安装, sudo yum install gcc gcc --version 可以查看当前的版本 ,我们默认安装的是4.8.5的版本,比较低, gcc test.c -stdc99 可以使他支持更高版本的c标准 -o 可以殖指明生成文件的名字,可以自己…

什么是Web服务器集群?

Web服务器集群是指将多台服务器组成一个集群,通过负载均衡将客户端请求分发到这些服务器上进行处理,从而提高网站的性能和可用性。每台服务器都运行着相同的应用程序和数据,并且能够相互通信和协调工作。 1.为什么需要Web服务器集群 随着互联…

0基础学习爬虫系列:网页内容爬取

1.背景 今天我们来实现,监控网站最新数据爬虫。 在信息爆炸的年代,能够有一个爬虫帮你,将你感兴趣的最新消息推送给你,能够帮你节约非常多时间,同时确保不会miss重要信息。 爬虫应用场景: 应用场景主要功…

Transformer从零详细解读

Transformer从零详细解读 一、从全局角度概况Transformer ​ 我们把TRM想象为一个黑盒,我们的任务是一个翻译任务,那么我们的输入是中文的“我爱你”,输入经过TRM得到的结果为英文的“I LOVE YOU” ​ 接下来我们对TRM进行细化,…

【Linux】萌新看过来!一篇文章带你走进Linux世界

🚀个人主页:奋斗的小羊 🚀所属专栏:Linux 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 前言💥1、初识Linux💥1.1 什么是操作系统?💥1.2 各种操作…

分享一个基于微信小程序的医院挂号就诊一体化平台uniapp医院辅助挂号应用小程序设计(源码、调试、LW、开题、PPT)

💕💕作者:计算机源码社 💕💕个人简介:本人 八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流&…

SpringBoot学习(9)(springboot自动配置原理)(源码分析、面试题)

目录 一、引言 二、为啥学习自动配置原理? 三、自动配置 (1)基本概述 (2)学习回顾 四、自动配置——源码分析 (1)回顾学习 (2)回到源码学习 (1)注…

文件系统 文件描述符fd 重定向原理 缓冲区

文章目录 基础的文件操作文件的系统调用接口位图向文件中写入标记位选项总结&#xff1a;open的返回值文件描述符fdfd012与硬件的关系read && stat 重定向dup2 缓冲区的理解经典的例子 基础的文件操作 引子&#xff1a; #include <stdio.h>int main() {FILE* f…

[Linux]:环境变量与进程地址空间

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 1. 环境变量 1.1 概念 **环境变量(environment variables)**一般是指在操作…

在Unity环境中使用UTF-8编码

为什么要讨论这个问题 为了避免乱码和更好的跨平台 我刚开始开发时是使用VS开发,Unity自身默认使用UTF-8 without BOM格式,但是在Unity中创建一个脚本,使用VS打开,VS自身默认使用GB2312(它应该是对应了你电脑的window版本默认选取了国标编码,或者是因为一些其他的原因)读取脚本…

自己部门日均1000+告警?如何减少90%无效告警?

目录标题 一、告警的类别1.技术告警1.1基础设施告警1.2基本服务告警 2.业务告警3.监控大盘告警 二、为何需要告警治理&#xff1f;三、治理迫在眉睫1.1告警治理策略1.2核心监控告警点1.3避免告警反模式1.4告警规约制定1.5自动化处理 一、告警的类别 一般的告警分为以下几点&am…

ISP面试准备2

系列文章目录 文章目录 系列文章目录前言一.如何评价图像质量&#xff1f;二.引起图像噪声的原因三. ISP3.1 ISP Pipeline主要模块3.1.1坏点校正&#xff08;Defect Pixel Correction, DPC&#xff09;3.1.2黑电平校正&#xff08;Black Level Correction, BLC&#xff09;3.1.…

面试官:synchronized的锁升级过程是怎样的?

大家好&#xff0c;我是大明哥&#xff0c;一个专注「死磕 Java」系列创作的硬核程序员。 回答 在 JDK 1.6之前&#xff0c;synchronized 是一个重量级、效率比较低下的锁&#xff0c;但是在JDK 1.6后&#xff0c;JVM 为了提高锁的获取与释放效&#xff0c;,对 synchronized 进…

基于JSP的实验室管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 Spring Boot框架 工具&#xff1a;IDEA/Eclipse、Navicat、Tomcat 系统展示 首页 用户个…