Redis分布式锁存在的问题以及解决方式

☆* o(≧▽≦)o *☆嗨~我是小奥🍹
📄📄📄个人博客:小奥的博客
📄📄📄CSDN:个人CSDN
📙📙📙Github:传送门
📅📅📅面经分享(牛客主页):传送门
🍹文章作者技术和水平有限,如果文中出现错误,希望大家多多指正!
📜 如果觉得内容还不错,欢迎点赞收藏关注哟! ❤️

文章目录

  • Redis分布式锁实现
  • 一、分布式锁
  • 二、 基于Redis的分布式锁
    • 2.1 初级版本
    • 2.2 解决分布式锁误删问题
    • 2.3 分布式锁的原子性问题
    • 2.4 Redis分布式锁存在的问题

Redis分布式锁实现

一、分布式锁

分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。

分布式锁的核心是实现多进程之间互斥,而满足这一点的方式有很多,常见的有三种:

MySQLRedisZookeeper
互斥利用MySQL本身的互斥锁机制利用setnx互斥命令利用节点的唯一性和有序性实现互斥
高可用
高性能一般一般
安全性断开连接,自动释放锁利用锁超时时间,到期释放临时节点,断开连接自动释放

二、 基于Redis的分布式锁

2.1 初级版本

实现基于Redis的分布式锁需要实现两个基本的方法:

获取锁

互斥:确保只有一个线程获取锁

// 添加锁,利用setnx的互斥特性
setnx lock thread1
// 添加锁过期时间,避免服务器宕机引起的死锁
expire lock 10
// 添加锁,NX是互斥,EX是设置超时时间
set lock thread1 NX EX 10

释放锁

  • 手动释放:删除key即可
  • 超时释放:获取锁时添加一个超时时间
// 释放锁,删除即可
del key

基本逻辑

  • 业务开始时尝试获取锁
    • 获取锁失败,直接返回
    • 获取锁成功,开始执行业务
      • 如果业务超时或服务宕机,自动释放锁
      • 否则执行完业务手动释放锁

存在的问题 :分布式锁误删问题

比如如下的场景:

  • 线程1首先获取锁,正常获取到锁,开始执行自己的业务。
  • 由于某种原因,线程1的业务被阻塞,并且阻塞时间超过了锁的过期时间,导致锁被自动释放
  • 锁被释放后,线程2再来获取锁,因为线程1的锁被释放了,所以线程2也能成功获取到锁,然后开始执行自己的业务。
  • 在线程2执行业务时,线程1的业务完成,线程1手动释放锁,此时,线程1释放的是线程2的锁。
  • 这时候,线程3也来获取锁,因为线程2的锁被线程1释放了,所以线程3也能成功获取到锁,然后开始执行自己的业务。
  • 此时,线程2和线程3是并行执行业务的,会出现错误的结果。

产生原因:

  • 没有唯一的锁标识,所以会产生误删的情况。

在这里插入图片描述

2.2 解决分布式锁误删问题

要想解决分布式锁误删的问题,主要的关键思路在于:如何判断是不是自己的锁。

这时就可以使用**线程标识 **(即线程ID)来当作分布式锁标识:

  • 如果线程标识与当前线程一致,则释放锁;
  • 如果线程标识与当前线程不一致,则不做处理;

处理逻辑

业务开始时尝试获取锁,锁的标识可以是线程ID:

  • 获取锁之前先比较当前线程ID与锁标识是否一致:
    • 不一致,获取锁失败,直接返回
    • 一致,获取锁成功,开始执行业务
      • 如果业务超时或服务宕机,自动释放锁
      • 业务执行完成,比较当前线程ID与锁标识是否一致
        • 一致,手动释放锁
        • 不一致,不做任何处理

存在的问题:分布式锁原子性问题

比如如下的场景:

  • 线程1首先获取锁,正常获取到锁,开始执行自己的业务。
  • 线程1业务执行完毕,需要手动释放锁,获取锁标识并判断是否与自己一致,结果一致,执行手动释放锁的动作,假设此时产生了阻塞,并且阻塞时间超过了锁的过期时间,导致锁被自动释放
  • 锁被释放后,线程2再来获取锁,因为线程1的锁被释放了,所以线程2也能成功获取到锁,然后开始执行自己的业务。
  • 在线程2执行业务过程中,线程1的阻塞结束了,此时继续执行手动释放锁动作,线程1手动释放锁,此时,线程1释放的是线程2的锁。
  • 这时候,线程3也来获取锁,因为线程2的锁被线程1释放了,所以线程3也能成功获取到锁,然后开始执行自己的业务。
  • 此时,线程2和线程3是并行执行业务的,会出现错误的结果。

产生原因:

  • 判断锁标识释放锁是两个操作,没有保证原子性。

在这里插入图片描述

2.3 分布式锁的原子性问题

要想解决操作原子性问题,我们可以使用Lua脚本解决多条命令原子性问题。

Redis提供的调用函数,语法如下:

# 执行redis的命令
redis.call('命令名称','key','其他参数',...)

Lua脚本

-- 锁的key
local key = KEYS[1]
-- 当前线程标识
local threadId = ARGV[1]
-- 比较线程标识与锁中的标识是否一致
if (redis.call('get', KEYS[1]) == ARGV[1]) then-- 释放锁return redis.call('del', KEYS[1])
end
return 0

Lua脚本处理逻辑

  • 获取锁中的线程标识
  • 判断是否与当前线程标识一致
    • 一致,手动删除锁
    • 不一致,不做处理

2.4 Redis分布式锁存在的问题

上面的实现逻辑呢,其实就已经能满足简单的分布式锁的功能了,但是由于它是我们自己实现的,所以还是会有一些问题:

(1)不可重入:同一个线程只能获取一次锁,无法多次获取同一把锁,如果我们有嵌套业务都需要用到分布式锁,那么这种Redis实现的锁就不可以使用了。

(2)不可重试:获取锁时如果获取失败就直接返回了,没有重试机制,这种对性能来说其实并不友好。

(3)超时释放:锁超时释放虽然可以避免死锁,但是如何业务执行耗时较长也会导致锁超时释放,存在不可预估的问题。

(4)主从一致性无法保证:如果Redis提供了主从集群,因为主从同步存在延迟,并且一般都是主写从读。如果线程在主节点获取了锁,并且尚未同步给从节点的过程中,突然主节点宕机,虽然Redis会重新选取一个从节点作为新的主节点,但是新主节点中没有锁的标识,所以也会出现多线程并行执行业务的情况(情况出现概率极低)。

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

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

相关文章

孚盟云 多处SQL注入漏洞复现

0x01 产品简介 上海孚盟软件有限公司是一家外贸SaaS服务提供商,也是专业的外贸行业解决方案专业提供商。 全新的孚盟云产品,让用户可以用云模式实现信息化管理,让用户的异地办公更加流畅,大大降低中小企业在信息化上成本,用最小的投入享受大型企业级别的信息化服务,使中…

让Mac与Windows合二为一:Microsoft Remote Desktop for Mac的魅力

在数字时代,远程连接已成为工作、学习和生活的必备工具。而Microsoft Remote Desktop for Mac正是这样一款能够让你随时随地,轻松连接到Windows系统的强大工具。 Microsoft Remote Desktop for Mac不仅提供了高效、稳定的远程访问体验,更凭借…

聚道云软件连接器1月新增应用/产品更新合集

1月更新概要 新增应用: 应用1:法大大 应用2:契约锁 应用3:E签宝 应用4:红圈CRM 应用5:中国民生银行 新增应用 应用1:法大大 法大大是国内领先的电子签名与电子合同云平台,致…

【react】创建react项目+项目结构

使用create-react-app快速搭建开发环境 create-react-app是一个快速创建React开发环境的工具,底层由Webpack构建,封装了配置细节 npx create-react-app react_hm执行命令后开始创建 创建好执行cd react_hm npm start 当看到webpack compiled successfu…

Nginx重写功能location与rewrite

1. location 从功能看 rewrite 和 location 似乎有点像,都能实现跳转,主要区别在于 rewrite 是在同一域名内更改获取资源的路径,而 location 是对一类路径做控制访问或反向代理,还可以proxy_pass 到其他机器。 rewrite 对访问的…

车载音频EMI的产生及典型音频功放AW836XX的解决方案

之前针对 eCall的文章中有提到D类音频功放需要关注EMI问题(点击文章回看《车载eCall系统音频应用解决方案》),在此展开此问题并寻求解决方案。 1. EMI定义与分类 电磁干扰(Electromagnetic Interference,EMI&#xff…

yum配置文件及NFS共享

一 yum配置文件及命令 1 /etc/yum.conf //主配置文件 2 /etc/yum.repos.d/*.repo //yum仓库文件位置 写错一个字母就不行,可以ping www.google.com 测试网络 3 /var/log/yum.log //日志文件 二 yum命令 1 [rootlocalhost ~…

当前从 Python 调用 C/C++ 代码的有多少种方法、最佳方案是什么?

当前从 Python 调用 C/C 代码的有多少种方法、最佳方案是什么? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家…

大寒---每年的最后一个节气

# 大寒节气 # 大寒,是二十四节气中的最后一个节气。斗指丑;太阳黄经达300;于每年公历1月20日左右交节。大寒同小寒一样,都是表示天气寒冷程度的节气,大寒是天气寒冷到极致的意思。大寒节气处在三九、四九时段&#xf…

IGBT工作原理

IGBT(绝缘栅双极型晶体管) 在实际应用中最流行和最常见的电子元器件是双极结型晶体管 BJT 和 MOS管。 IGBT实物图电路符号图 你可以把 IGBT 看作 BJT 和 MOS 管的融合体,IGBT具有 BJT 的输入特性和 MOS 管的输出特性。 与 BJT 或 MOS管相比,…

常用排序算法总结(直接插入排序、选择排序、冒泡排序、堆排序、快速排序、希尔排序、归并排序)

目录 一. 直接插入排序 二:选择排序 三:冒泡排序 四.堆排序 五:希尔排序 六:快速排序(递归与非递归) 七.归并排序(递归与非递归) 一. 直接插入排序 🌟排序思路 直接插入排序的基本原理是将一条记录插入到已排好的有序表中,从而得到一个新的、记录…

mp4文件可以转成mp3音频吗

现在是个非常流行刷短视频一个年代,刷短视似乎成了人们休闲娱乐的一种方式,在日常刷短视频过程中,肯定会有很多同学被短视频 bgm 神曲洗脑,比如很多被网红翻唱带火的歌曲,例如其中"不负人间”,就是其中…