当前位置: 首页 > news >正文

【Redis】-- 分布式锁

文章目录

  • 1. Redis应用--分布式锁
    • 1.1 什么是分布式锁
    • 1.2 分布式锁的实现
    • 1.3 引入过期时间
    • 1.4 引入校验id
    • 1.5 引入lua
    • 1.6 引入watch dog(看门狗)
    • 1.7 引入Redlock算法

1. Redis应用–分布式锁

1.1 什么是分布式锁

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

而Java的synchronized或者C++的std::mutex,这样的锁都是只能在当前进程中生效,在分布式锁的这种多个进程多个主机之间就很难产生制约,分布式系统中多个进程之间的执行顺序也是不确定的。此时就需要分布式锁。

1.2 分布式锁的实现

分布式锁也是一个/一组单独是服务器程序,给其他的服务器提供加锁这样的服务。

Redis就是一种典型的可以用来实现分布式锁的方案。

在这里插入图片描述
以买票服务器为例:

  1. 在进行买票操作的时候,先加锁(在Redis上设置一个特殊的key-value,完成了买票操作,再把这个key-value删除掉。)
  2. 其他服务器也想买票的时候,也去Redis上尝试设置key-value,如果发现key-value已经存在,就认为加锁失败。
  3. 这样就保证了再第一个服务器执行“查询-更新"过程中,第二个服务器不会执行查询,也就解决了超卖问题。

1.3 引入过期时间

使用set nx可以达到加锁的效果;使用del来完成解锁的效果。

但是如果设置的key-value还没来得及解锁,进程异常终止了,这样就会导致Redis上设置的key无人删除,也就导致其他服务器无法获取到锁了。

这种情况就可以给set的key设置一个过期时间,一旦时间到了,key就会被自动删除掉。

不能使用setnx expire这两个命令分开设置,务必使用set ex nx这样的方式来进行设置。因为Redis上的多个命令之间是无法保证原子性的,此时就可能出现一个命令成功,一个失败的情况。相比之下,使用一条命令设置更加稳妥。

1.4 引入校验id

那么是否会出现服务器1执行了加锁,服务器2执行了解锁操作呢?

正常来说一般肯定不是故意的,但是代码总会有bug,不小心执行到了解锁操作,因此就可能进一步的给系统带来更严重的问题。

为了解决上述问题,就需要引入一点校验机制。

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

1.5 引入lua

在通过上述的校验的方式来进行解锁:
1. 查询判定。
2. del
此处的操作是两步操作,不是原子的,就可能会出现问题。

在这里插入图片描述
前提:服务器1执行了加锁操作。

  1. 服务器1的线程A和线程B先后执行了GET操作进行校验,由于是服务器1进行的加锁操作,所以线程A和线程B都能校验通过。
  2. 服务器1的线程A先执行了DEL操作,实现了解锁。
  3. 在服务器1的线程A执行DEL和线程B执行DEL之间,服务器2的线程C执行来了set nx ex加锁操作,此时肯定是能加锁成功的。
  4. 然后服务器1的线程B执行了DEL操作。

此时就出现了问题。

虽然Redis中的事务能够解决上面的问题,但是在实践中往往是使用lua脚本。

lua是一个编程语言,作为Redis内嵌的脚本。MySQL8支持js作为内嵌语言。lua语言特别轻量(实现一个lua解释器,消耗的体积是非常小的)。

可以使用lua编写一些逻辑,把这个lua脚本上传到Redis服务器上,然后可以让客户端来控制Redis执行上述脚本。

Redis执行lua脚本的过程也是原子的,相当于执行一条命令。

1.6 引入watch dog(看门狗)

我们要在加锁的时候给key设置一个过期时间。

  1. 如果过期时间设置的短,就可能在业务逻辑还没有执行完就释放锁了。
  2. 如果过期时间设置的过长,就会导致锁释放不及时的问题。

那么最好的方式就是动态续约,往往需要服务器这边一个专门的线程,负责续约的事情,我们把这个负责的线程,叫做“看门狗”。

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

1.7 引入Redlock算法

使用Redis作为分布式锁,redis是有可能挂的。那么我们就要保证高可用。

在集群中,主节点和从节点之间的数据同步,是存在延迟的。可能主节点收到了set请求,但是还没来得及同步给从节点的时候主节点就已经挂了,即使从节点升级成了主节点,但是刚才的set的key-value也已经不存在了。

Redis作者针对这个问题给出了一个方案。那就是redback算法(冗余)

我们引⼊⼀组 Redis 节点. 其中每⼀组 Redis 节点都包含⼀个主节点和若⼲从节点. 并且组和组之间存储的数据都是⼀致的, 相互之间是 “备份” 关系(⽽并⾮是数据集合的⼀部分, 这点有别于 Redis cluster). 加锁的时候, 按照⼀定的顺序, 写多个 master 节点. 在写锁的时候需要设定操作的 “超时时间”. ⽐如 50ms. 即如果 setnx 操作超过了 50ms 还没有成功, 就视为加锁失败.

如果给某个节点加锁失败, 就⽴即再尝试下⼀个节点. 当加锁成功的节点数超过总节点数的⼀半, 才视为加锁成功. 这样的话, 即使有某些节点挂了, 也不影响锁的正确性.

在这里插入图片描述

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


文章转载自:

http://xYLGXScQ.Lbpqk.cn
http://qVfk9VsD.Lbpqk.cn
http://3KjqA7v0.Lbpqk.cn
http://QGuobvPb.Lbpqk.cn
http://6ZVHnqps.Lbpqk.cn
http://WuxXKX3I.Lbpqk.cn
http://6eL2tWDk.Lbpqk.cn
http://WZJGkaxj.Lbpqk.cn
http://oBTYX3EA.Lbpqk.cn
http://j3fUF39g.Lbpqk.cn
http://DvIIqJtc.Lbpqk.cn
http://PR7wRnOv.Lbpqk.cn
http://TSEh70OZ.Lbpqk.cn
http://U6Q1jHWa.Lbpqk.cn
http://QOCLlucY.Lbpqk.cn
http://vqakSAlM.Lbpqk.cn
http://INqQk0ak.Lbpqk.cn
http://GsHuhUeQ.Lbpqk.cn
http://ibFak9x4.Lbpqk.cn
http://1udANNny.Lbpqk.cn
http://MGdCDVpH.Lbpqk.cn
http://IdG9YodV.Lbpqk.cn
http://9eOGFptf.Lbpqk.cn
http://WjlHW1Nh.Lbpqk.cn
http://2pstz78d.Lbpqk.cn
http://qDyxbNbH.Lbpqk.cn
http://lNIEN1yZ.Lbpqk.cn
http://hXFkp7ao.Lbpqk.cn
http://uTaVUgoz.Lbpqk.cn
http://sTaC2Q5n.Lbpqk.cn
http://www.dtcms.com/a/388387.html

相关文章:

  • 分布式拜占庭容错算法——实现工作量证明(PoW)算法详解
  • 基础介绍(Solidity、Polkadot)
  • 【Axure高保真原型】智慧水利可视化分析案例
  • oracle的sql语句中 a=b(+),代表什么意思
  • 联邦学习论文分享:
  • Linux渗透中group的利用
  • Linux:基础开发工具
  • 数据结构----链表
  • 堆排序算法
  • 安卓多任务闹钟实现
  • 【源码集锦】基于Java+SpringBoot+Uniapp+Mysql的租房小程序技术搭建
  • Oceanbase下使用TPC-H模式生成数据
  • 20250917让荣品RD-RK3588-MID开发板的Android13系统在刷机的时候就直接以百分比显示电池电量
  • MySQL 核心操作全解析(用户 + SHOW+DML+DCL)
  • 【前端】【React】【Zustand】[特殊字符] Zustand 系统学习大纲(实战版)
  • 在测试接口时,遇到关于时间参数的传参时,遇到类型编译器无法转换的解决方案
  • 晶圆厂为什么都采用高架地板?
  • unsloth 笔记:微调mistral-7b(纯文本数据集)
  • 【vim,Svelte】怎样使用 vim 编辑 Svelte 那些奇奇怪怪名字的文件?
  • 【AOI基板外观缺陷检测软件】基于Halcon+C#开发的AOI基板外观缺陷检测软件,全套源码,开箱即用
  • htb academy笔记-module-Password Attacks(一)
  • Java程序设计:顺序结构与分支结构
  • 铺满式水印添加教程!水印如何铺满整个详情页页面?
  • 基于SpringBoot+Vue.js开发的医疗器械管理系统
  • 职业定位:用 “能力 - 兴趣 - 需求” 模型找到赛道
  • Caffeine Expiry
  • 【C++项目】C++11重构muduo库
  • 如何选择靠谱的防伪溯源系统公司?
  • 线程池 相关知识
  • 搭建CI/CD 流水线简单说明