技术分享 | Redis 之分布式锁

news2024/11/15 21:51:07

作者:贲绍华

爱可生研发中心工程师,负责项目的需求与维护工作。其他身份:柯基铲屎官。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。


引言:之前的一篇《缓存穿透 - Redis Module之布隆过滤器》中,介绍了布隆过滤器的使用,本篇主要通过实际业务场景来讲述Redis中关于分布式锁与Red lock的相关内容。

一、什么是分布式锁

分布式锁指的就是分布式系统下使用的锁(说了好像等于没说),在分布式系统中,常常需要协调组件间的动作。

如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。

二、场景案例

举个例子,假设ATM机A、ATM机B同时对同一账户入账,它们是两个独立且相同的业务系统。由于余额是要在现有金额上进行增加的,中间的前后操作会出现时差。

则A或B增加余额时都需要先获取互斥锁,锁住需要操作的资源,增加余额后释放锁。

三、使用Redis实现分布式锁

3.1 带TTL的key

在Redis中创建一个key,这个key有一个失效时间(TTL),以保证锁最终会被自动释放掉(这个对应上边脑图的活性A)

即:

get->不存在,获取成功->set->ttl->del

当客户端释放资源(解锁)时,会删除掉这个key。

3.2 setNX

使用3.1的方式存在一个问题,那就是每次都得先get一下看看这个key是否存在,插入之后还需要再设置TTL。

非常的繁琐且get->set->ttl操作并不是原子性的,需要额外处理类似get不存在但set又存在、锁被其他客户端释放掉的场景。

Redis提供了setNX命令(如果不存在就插入,并设置key的超时时间。如果存在则什么也不做)

使用命令:

set key value px milliseconds nx

3.3 setNX + Lua

在3.2中还存在一个问题,例如:

  1. ATM-A 获取锁成功
  2. ATM-A操作中,持续阻塞
  3. 设置key过期了,锁被自动释放
  4. ATM-B获取到锁
  5. ATM-A操作此时恢复处理,操作完成开始释放锁
  6. ATM-B持有的锁被ATM-A释放掉了

为了解决这个问题,释放锁之前需要对比value值(需要保证值的唯一性),释放锁的时候只有key存在并且存储的值和当前客户端指定的值一样才能删除成功。

同样的,get->delete操作并不是原子性的,需要使用lua脚本来同时完成:

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

3.4 锁的续期

锁的过期时间是插入key时直接设置的一个大概时间区间,实际业务执行过程中不能精确预估具体的执行的时间。会出现客户端正在处理时key TTL过期导致的被提前释放问题。

解决方式:可以让获得锁的客户端开启一个守护进程,用于给快要过期的key增加超时时间。当业务执行完成时,再主动关闭该守护进程。

3.5 高可用问题

单节点Redis实例会导致获取锁失败,业务直接停摆。但想通过增加slave节点解决这个问题其实是行不通的,因为Redis的主从同步通常是异步的。

会出现以下的问题:

  1. ATM-A从Redis master节点获取到锁
  2. 在master将锁同步到slave之前,master宕机
  3. slave节点被晋级为master节点
  4. ATM-B获取到了锁,ATM-A业务还在进行中,导致安全失效

四、Redis Module - RedLock

RedLock正是为了防止单点故障而设计的基于Redis的分布式锁实现。

它是由N(大于等于3的基数个)个Redis master节点组成的,节点与节点之间不使用复制或任何隐式协调系统。

当客户端需要获取锁时,会尝试顺序从N个实例中获取,在所有实例中使用相同的key与value。

  • 官方文档:https://redis.io/docs/manual/patterns/distributed-locks
  • 使用方式:https://github.com/wujunwei/redlock/blob/master/README.md

4.1 获取锁:

当N / 2 + 1个节点获取到锁时则成功得到锁(因为如果小于一半判断为成功的话,有可能出现多个客户端都成功获取锁的情况, 从而使锁失效)

4.2 释放锁:

客户端应该向所有Redis节点发起释放锁的操作。即使当时向某个节点获取锁没有成功,在释放锁的时候也不应该漏掉这个节点

4.3 延迟重启:

一个节点崩溃后,先不立即重启它,而是等待一段时间再重启,这段时间应该大于锁的有效时间(lock validity time)。

这样的话,这个节点在重启前所参与的锁都会过期,它在重启后就不会对现有的锁造成影响。

4.4 优点:

  • 有效防止单点故障

4.5 缺点:

  • 需要维护多台Redis Master,使用起来相当笨重
  • RedLock算法对时钟依赖性强,若集群中的某个节点发生时钟异常问题,可能会因此而引发锁安全性问题
  • 如果有节点发生崩溃重启,还是会对锁的安全性有影响的。具体的影响程度跟Redis对数据的持久化程度有关

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

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

相关文章

Redis事务

Redis事务官网: http://redis.cn/topics/transactions.html 一、Redis事务的特性 Redis事务可以一次执行多个命令,并且满足以下两个重要的特性 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中&a…

CSS3 calc()函数

CSS3 calc()函数 概述 在CSS3中,我们可以使用calc()函数通过“计算”的方式来定义某一个属性的取值。 使用 语法 属性: calc(表达式);说明 可以使用calc()函数计算元素的width、margin、padding、font-size等。 对于calc()函数,有以下5条运算规则…

我的第一个基于vue-cli的程序

文章目录一 准备环境1.1 node.js安装1.2 安装Vue工具(Vue CLI)第一种安装方式【可能会遇到失败,如果失败请尝试第二种方式】下载的文件的存放位置第二种安装方式安装cnpm二 操作步骤2.0 进行目标文件夹下的命令行窗口2.1 创建项目2.2 成功2.3 运行项目2.4 效果一 准…

力扣1700.无法吃午餐的学生数量

题目描述: 学校的自助午餐提供圆形和方形的三明治,分别用数字 0 和 1 表示。所有学生站在一个队列里,每个学生要么喜欢圆形的要么喜欢方形的。 餐厅里三明治的数量与学生的数量相同。所有三明治都放在一个 栈 里,每一轮&#xff…

戴尔成就300015电脑出现错误代码怎么重新安装系统?

戴尔成就300015电脑出现错误代码怎么重新安装系统?有用户使用这款戴尔成就300015电脑的时候,总是在使用过程中无故的冒出错误代码,导致系统崩溃了。那么这个情况怎么去进行问题的修复呢?一起来看看详细的解决方法分享吧。 准备工作…

【深度学习】如何封装可维护的restiful api

这篇文章是用一个案例的形式尝试解决字段入参多了,在python这种风格的语言下如何维护的问题! 文章目录前言1. json 是个好东西2. json 是个坏东西3. json维护数据的适用范围总结4.解决4.1 基础版4.2 进阶版4.2.1 行动4.2.2 精进4.3 另一种选择总结前言 …

立根铸魂 崛起数智时代 GBASE受邀出席操作系统产业峰会2022

2022年12月28日,由openEuler开源社区发起举办的操作系统产业峰会2022/openEuler Summit 2022正式召开。GBASE荣幸受邀参加统信软件“深耕数字化”主题论坛,分享GBase 8c基于鲲鹏生态的创新实践历程和经验。 操作系统产业峰会2022 -南大通用GBase 8c基于鲲…

使用Nordic的nrf52832控制指定从机(一主多从)

一主多从1. 想要实现的功能2. 从机3. 主机3.1 主从机连接个数设置3.2 扫描过滤3.3 连接和断开连接3.4 按键处理3.5 从机读写3.5.1 写3.5.1 读4运行效果1. 想要实现的功能 1.主机能连接多个从机(主机作为控制器,从机作为节点)。 2.主机能使用…

Java跨域问题

目录 1、跨域问题说明 ​2、跨域解决方案 2.1、局部跨域解决方案 2.1.1、CrossOrigin注解跨域 2.1.2、手动设置响应头 2.2、全局跨域解决方案 2.2.1、实现WebMvcConfigurer接口设置跨域 2.2.2、定义CorsFilter Bean实现跨域 2.2.3、重写ResponseBodyAdvice接口中的bef…

ros的launch文件知识

_node标签: 在指定机器上启动节点respawn"true|false"(可选) 如果节点退出,是否自动重启respawndelay"N"(可选) 如果 respawn 为 true,那么延迟N秒后启动节点required"true|false"(可选) 该节点是否必须,如果…

ZooKeeper 避坑实践:SnapCount 设置不合理导致磁盘爆满,服务不可用

作者:子葵 背景 在 ZooKeeper 的日常使用过程中,一个令人头疼的问题就是节点的磁盘容量问题,如果由于过大的 TPS 或者不适当的清理策略会导致集群中数据文件,日志文件的堆积,最终导致磁盘爆满,Server 宕机…

在线客服系统部署配置邮箱消息通知功能 - 唯一客服(v1kf.com) -开源私有化独立部署在线客服系统源码...

为在线客服系统设置邮件通知具有以下几个好处: 改善客户体验:邮件通知可以让客户实时收到新消息或更新通知,这有助于提高他们对您的服务的整体体验。 提高效率:邮件通知可以帮助提高客服团队的效率,因为它们会在新消息…

非专业人士如何完成数据采集?纯干货,一文看懂

写在前面: 本教程能够解决大部分人的数据采集及分析需求,实用、简单,尤其适合Excel大户、办公族、业务人员,或者不会编程、不懂数据分析理论的技术小白…… 来不及看的可以先点赞收藏! 01 点对点的采集:…

吴恩达《机器学习》——欠拟合与过拟合

欠拟合与过拟合1. 方差与偏差模型的容量、过拟合和欠拟合2. Python代码实践2.1 拟合直线2.2 拟合多项式数据集、源文件可以在Github项目中获得 链接: https://github.com/Raymond-Yang-2001/AndrewNg-Machine-Learing-Homework 1. 方差与偏差 在数学上,估计的偏差…

Java基础漏洞(二)

继续填补自己的知识漏洞 1.&、&&、|、||之间的区别 &是逻辑与,而&&则是短路与。&和&&之间的区别是,在短路与&&的情况下,两个条件当第一个条件为假时,则不再执行第二个条件&#xf…

java学习之类方法

目录 一、基本介绍 二、类方法的调用 三、类方法的应用实例 代码 内存分析 运行结果 四、类方法的经典使用场景 五、类方法使用细节 第一条 第二条 第三条 第四条 第五条 第六条 六、练习 第一题 考察点 分析 结果 第二题 代码 考察点 结果 第三题 类方法 …

LeetCode498. 对角线遍历

LeetCode刷题记录 文章目录📜题目描述💡解题思路⌨C代码📜题目描述 给你一个大小为 m x n 的矩阵 mat ,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。 示例1 输入:mat [[1,2,3],[4,5,6],[…

VUE2使用浏览器缓存的方法

分两种:localStorage和sessionStorage,它两统称webStorage 注意点1:localStorage对象和sessionStorage对象都是window对象下的,且方法都是一样的,默认”window.”可以省略,添加可用setItem(K,V),查询可用ge…

数据库|scMethBank:单细胞全基因组 DNA 甲基化图谱数据库

甲基化是DNA的一种重要化学修饰,可调节基因的表达和关闭,与癌症、衰老、老年痴呆等许多疾病密切相关,是表观遗传学的重要研究内容之一。测序技术的发展,极大促进了单细胞DNA甲基化研究。然而大量数据的不断积累,对单细…

《HTTP权威指南》----HTTP报文

目录 报文流 报文的组成部分 报文语法 1.起始行 2.首部 通用首部,既可以出现在请求报文中也可以出现在响应报文中。 请求首部,提供更多有关请求的信息。 响应首部,提供更多有关响应的信息。 实体首部,描述主题的长度和内…