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会重新选取一个从节点作为新的主节点,但是新主节点中没有锁的标识,所以也会出现多线程并行执行业务的情况(情况出现概率极低)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【前沿技术杂谈:智能对话的未来】深入比较ChatGPT与文心一言

【前沿技术杂谈:智能对话的未来】深入比较ChatGPT与文心一言 引言主体智能回复语言准确性知识库丰富度 深入分析:ChatGPT与文心一言的技术对比技术架构和算法数据处理和隐私用户界面和体验 应用场景分析未来展望技术进步的趋势潜在的挑战对社会的影响 结…

2018年认证杯SPSSPRO杯数学建模C题(第二阶段)机械零件加工过程中的位置识别全过程文档及程序

2018年认证杯SPSSPRO杯数学建模 基于轮廓提取与图像配准的零件定位问题研究 C题 机械零件加工过程中的位置识别 原题再现: 在工业制造自动生产线中,在装夹、包装等工序中需要根据图像处理利用计算机自动智能识别零件位置,并由机械手将零件…

JDBC编程详细教程与示例源码

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl JDBC概述 为了在Java语言中提供对数据库访问的支持,Sun公司于1996年提供了一套访问数据库的标准Java类库JDBC。JDBC的全称是Java数据库连接(Java Database Conn…

怎么样的布局是符合可制造性的PCB布局?

满足可制造性、可装配性、可维修性要求,方便调试的时候于检测和返修,能够方便的拆卸器件: 1)极性器件的方向不要超过2种,最好都进行统一方向等要求,如图1-1所示; 图1-1 极性器件方向统一摆放 2…

CVE重要通用漏洞复现java php

在进行漏洞复现之前我们需要在linux虚拟机上进行docker的安装 我不喜欢win上安因为不知道为什么总是和我的vmware冲突 然后我的kali内核版本太低 我需要重新安装一个新的linux 并且配置网络 我相信这会话费我不少时间 查看版本 uname -a 需要5.5或以上的版本 看错了浪…

免费开源线上信息技术电子云书屋

1 概述 知命耳顺之际,时逢甲辰龙年到来,汇集半生研发积累和教育培训沉淀,以分布微服软件框架为基础,特别推出“线上电子云书屋”,陆续呈现编著的十余部信息技术教材和一些典型的软件架构平台,供给免费开源…

JVM-透彻理解字节码以及指令

一、字节码与指令概述 package ch13_bytecode;public class HelloWorld {public static void main(String[] args) {System.out.println("hello world");} }生成字节码: cafe babe 0000 0031 0022 0a00 0600 1409 0015 0016 0800 170a 0018 0019 0700 1a…

Docker(二)安装指南

作者主页: 正函数的个人主页 文章收录专栏: Docker 欢迎大家点赞 👍 收藏 ⭐ 加关注哦! 安装 Docker Docker 分为 stable test 和 nightly 三个更新频道。 官方网站上有各种环境下的 安装指南,这里主要介绍 Docker 在…

css-动画效果学习示例

阴影 x-轴 y-轴 模糊度 颜色 (正负值可以表示角度问题) 可以加多个阴影 内置阴影 transition 可以添加动画延迟效果 向z轴缩进,开启透视respective 触发旋转效果 学习来源 :动画属性_哔哩哔哩_bilibili

应用Dockerfile编写及部署使用

dockerfile内容规范: FROM mycentos-jdk:latest # 基础镜像 MAINTAINER # 镜像作者信息 姓名邮箱 RUN # 镜像构建的时候运行的命令 ADD # copy内容到容器(压缩包,自动解压) COPY # 类似…

C++:类与结构体的对比

2024年1月18日 内容来自The Cherno:C系列 -------------------------------------------------------------------------------------------------------------------------------- C中关于class与struct,几乎没有区别,只有一个关于“可见度”的区别…

element-ui的el-upload组件实现上传拖拽排序图片顺序(sortablejs)

<template><!-- 省略其他配置 --><el-upload ref"upload" :file-list.sync"fileList"></el-upload></template><script>import Sortable from sortablejs;export default {data() {return {fileList: []};},mounted()…

【React】组件生命周期、组件通信、setState

文章目录 React的组件化类组件render函数的返回值函数组件 认识生命周期生命周期解析生命周期函数不常用生命周期函数 认识组件间的通信父组件传递子组件 - 类组件和函数组件参数propTypes子组件传递父组件 React中的插槽&#xff08;slot&#xff09;children实现插槽props实现…

three.js 缓动算法.easing(渐入相机动画)

效果&#xff1a;淡入&#xff0c;靠近物体 代码&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div c…

地平线旭日 X3 开发板上手体验

最近嫖到一块旭日X3开发板&#xff0c;借此熟悉地平线 AI 芯片旭日 X3 模型部署流程&#xff0c;以及算法工具链。这里基本是跟着官方的用户手册进行操作&#xff0c;其中也遇到一些奇怪的问题。 1 烧写系统 1.1 系统选择 旭日X3派开发板支持Ubuntu 20.04 Desktop、Server两…

【数据结构与算法】排序算法:冒泡排序,冒泡排序优化,选择排序、选择排序优化

目录 一、冒泡排序 1、冒泡排序思想 2、冒泡排序算法的性能分析 代码实现&#xff1a; 二、选择排序 1、选择排序思想 2、选择排序算法的性能分析 代码实现&#xff1a; 一、冒泡排序 1、冒泡排序思想 冒泡排序的基本思想是通过相邻元素之间的比较和交换来逐步将最大…

轮胎侧偏刚度线性插值方法

一、trucksim取数据 步骤一 步骤二 二、数据导入到matlab中 利用simulink的look up table模块 1是侧偏角&#xff1b;2是垂直载荷&#xff1b;输出是侧向力。 侧向力除以侧偏角就是实时的侧偏刚度。

unocss+iconify技术在vue项目中使用20000+的图标

安装依赖 npm i unocss iconify/json配置依赖 vue.config.js文件 uno.config.js文件 main.js文件 使用 <i class"i-fa:user"></i> <i class"i-fa:key"></i>class名是 i- 开头&#xff0c;跟库名:图标名&#xff0c;那都有什么库…

数据结构之dict类

dict类 dict 是字典类。什么是字典&#xff08;Dictionary&#xff09;呢&#xff1f;就是一个可以通过索引找到对象的数据类型。在Python 的dict类里&#xff0c;索引就是“键”&#xff0c;对象也叫“值”&#xff0c;二者合起来就叫“键值对”。每个“键值对”之间用逗号&a…

“深入理解 Docker 和 Nacos 的单个部署与集成部署“

目录 引言&#xff1a;Docker Nacos 单个部署1.1 什么是 Docker&#xff1f;Docker 的概念和工作原理Docker 为什么受到广泛应用和认可 1.2 什么是 Nacos&#xff1f;Nacos 的核心功能和特点Nacos 在微服务架构中的作用 1.3 Docker 单个部署 Nacos Docker Nacos 集成部署总结&a…