Redis原理篇——分布式锁

Redis原理篇——分布式锁

    • 分布式锁是什么?
    • 分布式锁有哪些特性?
    • 分布式锁常用实现方式
    • Redis 实现分布式锁
      • 一、简单的 Redis 锁
      • 二、带过期时间的 Redis 锁
      • 三、加上 Owner 的 Redis 锁
      • 四、Lua 脚本确保原子性

分布式锁是什么?

分布式锁是在分布式系统中用来确保当多个进程或服务在不同的计算机上同时尝试访问和操作同一份资源时,能够协调一致地进行,避免数据冲突和不一致性的问题。

分布式锁就像是一个网络版的门卫,确保在多台计算机上运行的程序不会同时操作同一个数据。想象一下,每台计算机都要先拿到这个门卫的钥匙,才能操作数据。这样,就能防止数据混乱,确保每次只有一个程序在使用数据。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

分布式锁有哪些特性?

  • 互斥性:很好理解,确保在任何时刻,只有一个客户端可以持有锁。这意味着当一个进程或线程成功获取到锁时,其他任何尝试获取该锁的进程或线程都会被阻止,直到锁被释放。

老王进去了老李就不能再进了!!

  • 锁失效机制:为了 防止死锁,分布式锁应该具有 超时机制 。如果持有锁的进程因崩溃或其他原因未能释放锁,锁将在设定的超时时间后自动释放。

老王在里面干太久了,这不行,挂了都不知道,甭管你挂没挂,不出来拉倒,别人还要进去呐!

  • 对称性:加锁的必须和解锁的是 同一个竞争者 ,不能把其他的竞争者持有的锁给释放掉了

跟大爷打招呼,拿着钥匙进去的,得和出来的时候还钥匙的是一个人,不能老王进去老李出来吧,那不见鬼了!!

  • 高可用:需要能有一定程度的 异常处理能力 容灾能力 ,确保业务不会出现中断

保安大爷不行了,干不动了,换那个新来的大学生顶上啊!!

分布式锁常用实现方式

  • 基于缓存(如 Redis):使用缓存系统的原子操作来实现锁。例如,Redis的SETNX命令可以用来设置一个不存在的键,如果键已存在,则操作失败,这可以用来实现锁的互斥性。
  • 基于数据库:利用数据库的唯一性约束来实现锁机制。通过向数据库表中插入具有唯一索引的记录来获取锁,操作完成后删除记录来释放锁。
  • 基于Zookeeper:Zookeeper提供了一种基于临时节点和顺序节点的锁实现机制。客户端可以创建一个临时顺序节点,并检查是否为最小节点来获取锁,释放锁时删除该节点。

而本篇文章,将基于 Redis 缓存详细探讨分布式锁的使用

Redis 实现分布式锁

一、简单的 Redis 锁

想象一下,我们的系统是一个超级忙碌的酒吧,而分布式锁就是酒吧里唯一的洗手间的钥匙。客户(也就是进程)想要使用洗手间(也就是资源),他们需要先拿到钥匙。

SET restroom_key "occupied" NX

这条命令就像是在问酒保:“嘿,洗手间钥匙在吗?”如果NX(Not eXists)标志起作用,那就意味着洗手间空着,你就可以拿到钥匙(也就是锁)。如果钥匙“不存在”,那就意味着洗手间已经有人在用了,你得等等。最后,在使用完成之后会归还钥匙(delete)

不足之处

但是,如果老王进了洗手间,然后突然不见了(也就是进程崩溃了)或者没卫生纸了需要其他人递过来但又没手机(发生死锁),怎么办?我们的钥匙就永远被锁在里面了。这就引出了我们的第二部分。

二、带过期时间的 Redis 锁

为了防止洗手间被永久占用,我们给钥匙加上了一个计时器。

SET restroom_key "occupied" NX EX 5

现在,不管老王发生了什么,5分钟后钥匙也会自动回到酒保手里,其他客户就可以使用洗手间了。

进一步的不足

但是,如果老王今天身体确实不舒服,窜了太长的时间了,或者因为其他原因接个电话什么( 比如说网络延迟或者 GC卡顿等原因)导致他没消失但一直占着茅坑不拉屎,然后钥匙回到了酒保手上,另一个人老张就拿着钥匙进去了

然后关键来了,这时候老王结束了,然后出来的时候按照流程就把钥匙(也就是锁),但是实际上他还的是老张的钥匙,而这时候老张不就完犊子了,你老王的问题别把我也扯进去!!

三、加上 Owner 的 Redis 锁

分布式锁应该满足, 谁申请谁释放 的原则,不能释放别人的锁

因此我们决定在钥匙(锁)上刻上名字,这样只有名字匹配的人(一般是进程的 uuid )才能归还钥匙。

SET restroom_key “老张” NX EX 5

如果老张有了钥匙,那么只有老张能归还它。如果老王试图归还一个写着“老张”的钥匙,酒保会说:“不行,这不是你的钥匙。”

再进一步的问题

可以看到,解锁是有两个操作,先查看是否是自己的钥匙,是的话再归还钥匙(delete)

但整个解锁操作并不是原子性的,可能检查的时候是自己的,而归还删除的时候已经是别人的了( 比如说你刚获取到是自己的锁,然后处于了一个很长的 GC…)

四、Lua 脚本确保原子性

这时就需要 Lua 脚本来保证解锁的原子性,因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,保证了锁释放操作的原子性。

// 释放锁时,先比较 unique_value 是否相等,避免锁的误释放
if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end

这样就通过使用 SET 命令 加上 NXEX 参数 以及 Owner 标志 和 Lua 脚本在 Redis 单节点上完成了分布式锁的加锁和解锁。

通过以上方式,分布式锁的前三个特性 互斥性 、 锁失效机制以及对称性就基本解决了

那么对于高可用,其实,就是基于集群模式,主从复制加上哨兵模式即可

详见之前文章:

Redis实战篇——搭建主从复制
Redis原理篇——哨兵机制

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

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

相关文章

软件体系结构笔记(自用)

来自《软件体系结构原理、方法与实践(第三版)》清华大学出版社 张友生编著 1-8章12章 复习笔记 如有错误,欢迎指正!!!

HCIP认证笔记(填空)

1、为防止攻击者伪造BGP报文对设备进行攻击,可以通过配置GTSM功能检测IP报文中的TTL值的范围来对设备进行保护。如果某台设备配置了“peer x.x.x.x valid-ttl-hops 100",则被检测的报文的TTL值的有效范围为【(156),255】; 解析: peer {group-name | ipv4-address…

学习cel-go了解一下通用表达语言评估是什么

文章目录 1. 前言2. cel-go2.1 cel-go关键概念Applications(应用)Compilation(编译)Expressions(表达式)Environment环境解析表达式的三个阶段 3. cel-go的使用4. cel-go使用5. 说明6. 小结7. 参考 1. 前言 最近因为在项目里面实现的一个使用和||来组合获取字段值的功能有点儿…

MySQL员工练习

MySQL员工练习 1.数据显示 员工信息表emp: 字段:员工id,员工名字,工作岗位,部门经理,受雇日期,薪水,奖金,部门编号 英文名:EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,BONUS,DEPTNO 部门信息表dept: 字段:部门编号,部门名称,部…

自然抽样和平顶抽样

自然抽样和平顶抽样是两种信号处理和采样技术,它们在音频信号处理、信号重建以及数字信号处理中有着不同的应用。 1. 自然抽样(也称为理想抽样或无失真抽样):样值脉冲的幅度随原始信号m(t)的幅度而变; 自然抽样过程的…

Java算法常用技巧

一、排序 资料:https://blog.csdn.net/weixin_72499901/article/details/136592073 正排序 import java.util.Arrays;public class SortArray {public static void main(String[] args) {int[] citations {5, 3, 8, 2, 1, 4};// 打印原数组System.out.println(&…

windows10或者windows11怎么查看自己电脑显卡型号

win10系统: 右键单击任务栏后弹出菜单选择任务管理器 打开任务管理器后,点击性能查看左侧GPU0或者GPU1 如果有nvidia字样表示自己电脑有nvidia显卡,如果是AMD或者intel字样表示没有nvidia显卡。注意如果你有GPU0或者GPU1说明你电脑是双显卡&…

后端中缓存的作用以及基于Spring框架演示实现缓存

缓存的作用及演示 现在我们使用的程序都是通过去数据库里拿数据然后展示的 长期对数据库进行数据访问 这样数据库的压力会越来越大 数据库扛不住了 创建了一个新的区域 程序访问去缓存 缓存区数据库 缓存里放数据 有效降低数据访问的压力 我们首先进行一个演示 为了演示…

spring boot配置ssl证书,支持https访问

1. 阿里云官网下载证书,云控制台搜索ssl,点击进入。 2.点击免费证书,立即购买。 3. 点击创建证书,填写完证书申请后,等待证书签发。 4. 证书签发以后,点击下载证书,spring boot选tomcat服务器类型的。 5. …

Android开发更改JDK版本

今天在跑GitHub上面一个Android项目时,在Android编译时出现如下错误: Unsupported Java. Your build is currently configured to use Java 17.0.2 and Gradle 7.0.2.错误原因: JDK和Gradle版本对应出错。 本地的JDK为1.8正好可以更改为本…

跨境电商测评、采购大额下单自养号需要解决哪些技术原理?

市场上有许多伪装工具,但大多数只是为了方便开发人员测试系统程序,它们并不能针对特定的电商平台进行伪装。每个电商平台都有其独特的风控机制,因此,我们需要从硬件环境的底层配合软件控制,以满足各平台的检测规则。 …

永磁同步直线电机(PMLSM)控制与仿真4-永磁同步直线电机数学三环闭环控制仿真

文章目录 1、参数设置及脚本2、相电流波形3、位置波形4、速度波形5、控制电流波形6、永磁同步直线电机在实际控制中如何控制参考 写在前面:原本为一篇文章写完了永磁同步直线电机数学模型介绍,永磁同步直线电机数学模型搭建,以及永磁同步直线…

Jacob环境探索(兼容性、管理员、DLL位置、VS环境,COM权限)

概述: 最近在生产开发实践出现了很多问题,经过了一系列排查,特做如下总结 探索成果: 1. jacob.dll的建议位置 首先jacob的官网,以及官方GitHub,你可以从这里找到DLL文件,以及相关资料然后DLL文…

【APP移动端自动化测试】第一节.环境配置和adb调试工具

文章目录 前言一、Java环境搭建二、AndroidSDK环境搭建三、Android模拟器安装四、adb调试工具基本介绍 4.1 adb构成和基本原理 4.2 adb获取包名,界面名 4.3 adb文件传输 4.4 adb获取app启动时间 4.5 adb获取手机日志 4.6 adb其他有关…

Windows 11 中安装 Docker Desktop 并安装镜像

本该主要介绍在 Windows 11 中安装 Docker Desktop 时的一些准备工作,以及该如何下载和安装,然后分别使用管理界面和 Docker 命令安装两个镜像。 一、准备工作 在 Windows 11 中安装 Docker Desktop 前,需要做一些准备。打开 【Windows 功能…

MongoDB~事务了解;可调一致性模型功能与因果一致性模型功能分析

背景 MongoDB 从 3.0版本引入 WiredTiger 存储引擎之后开始支持事务,MongoDB 3.6之前的版本只能支持单文档的事务,从 MongoDB 4.0版本开始支持复制集部署模式下的事务,从 MongoDB 4.2版本开始支持分片集群中的事务。 根据官方文档介绍&…

C++11 move左值转化为右值

单纯的左值只能用左值引用和右值只能用右值引用有些局限,在一些情况下,我们也需要对左值去调用右值引用,从而实现将左值里的内容转移到右值中 标准定义: 功能就是将一个左值强制转化为右值,然后实现移动语义 注意&…

「TCP 重要机制」滑动窗口 粘包问题 异常情况处理

🎇个人主页:Ice_Sugar_7 🎇所属专栏:计网 🎇欢迎点赞收藏加关注哦! 滑动窗口&粘包问题&异常情况处理 🍉滑动窗口🍌流量控制🍌拥塞控制🍌延时应答&…

Perl语言入门指南:掌握文本处理与系统管理的利器!

Perl是一种高级的、解释型的编程语言,具有强大的文本处理能力,被广泛用于文本处理、系统管理、网络编程等多种任务。本文将全面介绍Perl的基本概念、语法规则、主要用途以及如何开始学习Perl。 一、Perl语言简介 1. Perl的历史 Perl由Larry Wall在1987…

JUC并发编程-第二天:线程池相关

线程池相关 线程池内置线程池的使用线程池的关闭excute方法和submit方法的区别 线程池 线程池就是一个可以复用线程的技术 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,Thread…