一篇文章了解Redis分布式锁

news2024/11/24 10:50:19

Redis分布式锁

什么是分布式锁?

​ redis分布式锁是一种基于redis实现的锁机制,它用于在多并发分布式环境下控制并发访问共享资源。在多个应用程序或是进程访问共享资源时,分布式锁可以确保只有一个进程可以访问该资源,不会发生数据的不一致和竞争条件的发生。

为什么需要分布式锁?

​ 在多线程环境下,如果多个线程同时访问共享资源,如外卖订单,商品库存,这时就会发生数据竞争导致脏数据或者商品超卖的问题。

举个例子,假设现在有 100 个用户参与某个限时秒杀活动,每位用户限购 1 件商品,且商品的数量只有 3 个。如果不对共享资源进行互斥访问,就可能出现以下情况:

  • 线程 1、2、3 等多个线程同时进入抢购方法,每一个线程对应一个用户。
  • 线程 1 查询用户已经抢购的数量,发现当前用户尚未抢购且商品库存还有 1 个,因此认为可以继续执行抢购流程。
  • 线程 2 也执行查询用户已经抢购的数量,发现当前用户尚未抢购且商品库存还有 1 个,因此认为可以继续执行抢购流程。
  • 线程 1 继续执行,将库存数量减少 1 个,然后返回成功。
  • 线程 2 继续执行,将库存数量减少 1 个,然后返回成功。
  • 此时就发生了超卖问题,导致商品被多卖了一份。

在这里插入图片描述

为了保证共享资源被安全地访问,我们需要使用互斥操作对共享资源进行保护,即同一时刻只允许一个线程访问共享资源,其他线程需要等待当前线程释放后才能访问。这样可以避免数据竞争和脏数据问题,保证程序的正确性和稳定性。

如何才能实现共享资源的互斥访问呢? 锁是一个比较通用的解决方案,更准确点来说是悲观锁。

悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程

对于单机多线程来说,在 Java 中,我们通常使用 ReetrantLock 类、synchronized 关键字这类 JDK 自带的 本地锁 来控制一个 JVM 进程内的多个线程对本地共享资源的访问。

在这里插入图片描述

从图中可以看出,这些线程访问共享资源是互斥的,同一时刻只有一个线程可以获取到本地锁访问共享资源。

分布式系统下,不同的服务/客户端通常运行在独立的 JVM 进程上。如果多个 JVM 进程共享同一份资源的话,使用本地锁就没办法实现资源的互斥访问了。于是,分布式锁 就诞生了。

下图是在分布式系统中添加本地锁的情况。
在这里插入图片描述

​ 这时因为sychornized锁是基于JVM实现的,但是每台服务器都有自己的JVM所以此时sychornized无法对多个线程进行控制。

下图是采用了分布式锁。

在这里插入图片描述

​ 我在看这部分时,看到有人在弹幕中提到分布式锁就是让多个jvm虚拟机去争抢同一把锁。我觉得这样想的话分布式锁就很好理解了。

分布式锁应该具备哪些条件?

一个最基本的分布式锁需要满足:

  • 互斥:任意一个时刻,锁只能被一个线程持有。
  • 高可用:锁服务是高可用的,当一个锁服务出现问题,能够自动切换到另外一个锁服务。并且,即使客户端的释放锁的代码逻辑出现问题,锁最终一定还是会被释放,不会影响其他线程对共享资源的访问。这一般是通过超时机制实现的。
  • 可重入:一个节点获取了锁之后,还可以再次获取锁。

除了上面这三个基本条件之外,一个好的分布式锁还需要满足下面这些条件:

  • 高性能:获取和释放锁的操作应该快速完成,并且不应该对整个系统的性能造成过大影响。
  • 非阻塞:如果获取不到锁,不能无限期等待,避免对系统正常运行造成影响。

分布式锁的实现

redis实现分布式锁主要是利用了Redis的setnx命令。setnx是SET IF NOT EXISTS(如果不存在就创建)。

  • 获取锁

    #添加锁  NX是互斥  EX是设置超时时间
    SET lock value NX EX 10
    
  • 释放锁

    DEL lock
    

在这里插入图片描述

Redis实现分布式锁如何控制有效时长

1,根据业务执行时间进行预估(一般不采用,不准确)。

2,给锁设置过期时间,并在业务超出过期时间后进行续期。

如何进行续期?

Redisson是一个开源的java语言Redis客户端,提供了许多开箱即用的功能。

Redisson中提供了一个watch dog (看门狗)机制,如果操作共享数据的线程在过期时间内并未完成业务,Watch Dog就会不断的延长锁的获取时间。进而保证锁不会因为超时而被释放。
在这里插入图片描述

​ 在一般的锁操作中我们一般设置当一个锁被一个线程获取后,若有另一个线程想要获取锁就会中断这个线程让他无法获取这个锁。但是在redisson中提供了一个等待机制也就是上图中的while循环,在锁被获取后,另一个线程不断循环尝试获取锁,这样就使得如果线程1在很短的时间内就完成了业务,线程2在此时循环获取到锁就能立刻执行业务,减少了等待时间,提高了执行业务的效率。

Redisson实现分布式锁是可重入的吗?

​ Redisson实现分布式锁是可重入的,所谓可重入锁指的是在一个线程中可以多次获取同一把锁,比如一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法即可重入 ,而无需重新获得锁。像 Java 中的 synchronized``ReentrantLock

​ redisson分布式锁可重入的原理就是,其内部维护了一个hash结构。

public void add1(){
RLock lock = redissonClient.getLock(“heimalock"); 
boolean isLock = lock.tryLock();
//执行业务
add2(); 
//释放锁
lock.unlock();
}
public void add2(){
RLock lock = redissonClient.getLock(“heimalock");
boolean isLock = lock.tryLock();
//执行业务
//释放锁
lock.unlock();
}

在这里插入图片描述

总结

  • Redis分布式锁时如何实现的?

    在Redis中,可以使用SET命令结合NX(SET IF NOT EXISTS)选项来实现分布式锁。以下是基本的实现步骤:

    1. 获取锁:当一个进程需要获取锁时,它会向Redis发送一个SET命令,设置一个特定的键作为锁的标识,并设置过期时间。关键参数如下:

      • 锁的键名:通常是一个唯一的标识符,用于标识该锁。
      • 锁的值:可以是一个随机生成的唯一值,用于区分不同的进程。
      • 过期时间:确保即使锁没有显式释放,也会在一定时间后自动过期,避免死锁的发生。

      例如,使用以下命令获取锁:

      #添加锁  NX是互斥  EX是设置超时时间
      SET lock value NX EX 10
      

      如果该键不存在,即锁尚未被其他进程占用,则成功获取锁并返回OK;如果该键已存在,表示锁已被其他进程占用,获取锁失败,返回nil。

    2. 释放锁:当进程完成对共享资源的操作后,需要释放锁以允许其他进程获取锁。释放锁的过程包括以下两个步骤:

      • 删除锁:进程通过执行DEL命令来删除锁的键,释放锁资源
      DEL lock
      
  • 如何用Redis实现锁的有效时长?

    使用了Redis中的Redisson框架,redisson需要手动加锁,可以设置锁的失效时间和等待时间,当一个业务超出了锁的过期时间时,在redisson中引入了一个Watch Dog看门狗机制,它会每隔一段时间就会检查该业务是否还持有锁,若是仍然持有锁那就增加持有锁的时间,当业务完成后释放锁。

    在一般的锁操作中我们一般设置当一个锁被一个线程获取后,若有另一个线程想要获取锁就会中断这个线程让他无法获取这个锁。但是在redisson中提供了一个等待机,在锁被获取后,另一个线程不断循环尝试获取锁,这样就使得如果线程1在很短的时间内就完成了业务,线程2在此时循环获取到锁就能立刻执行业务,减少了等待时间,提高了执行业务的效率。

  • Redisson实现的可重入锁是否为可重入锁?

    是可重入的,redisson分布式锁可重入的原理就是,其内部维护了一个hash结构。判断是否为当前线程持有的锁,如果是就对当前线程持有的锁进行计数,如果释放锁就对hash结构中的value减一。

本文章中图片多是黑马ppt中的图片,在此借用。Redis篇-10-redis分布式锁-实现原理(setnx、redisson)_哔哩哔哩_bilibili

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

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

相关文章

采用555时基电路的简易/可调定时长延时电路设计

采用 555 时基电路的简易长延时电路 本电路和一般的定时电路相比是通过在 555 时基电路的 5 脚处加了一个二极管 VD1,使得定时时间延长的特点。 一、电路工作原理 电路原理如图 11 所示。 当按下按钮SB时,12V的电源通过电阻器Rt向电容器Ct充电&#…

弹性IP和公网IP有什么区别?哪个好

​  弹性IP和公网IP有什么区别?哪个好。IP是服务器重要的组成资源,一台云服务器实例一般分为公网IP和内网IP,公网IP指的是对外访问的IP地址,是针对公众用户的IP,这是网站绑定的服务器IP地址。而内网IP顾名思义就是内部的网络IP…

Android Monkey稳定性测试

l 命令样例: adb shell monkey -p packagename --ignore-timeouts --ignore-crashes -v -v --throttle 200 1000000 各个参数的意义如下: -p 用此参数指定一个或多个包(Package)。指定包之后,Monkey将只允许系统启…

cmake多文件、多文件夹编译(2)

一、同级文件夹下代码调用问题 目录如下: ./testCMake(根目录): /build: /MyClass: CMakeLists.txt MyClass.cpp MyClass.h /MyFunction: CMakeLists.txt MyFunction.cpp MyFunction.h CMakeLists.txt main.cpp 上述…

day35-Postman/ajax

0目录 1.postman 2.ajax 1.Postman 1.1 定义:postman用于测试http协议接口,无论是开发还是测试人员 1.2 Servlet中的doGet()/daPost…

基于JavasSwing+MySQL的医药销售管理系统

点击以下链接获取源码: https://download.csdn.net/download/qq_64505944/87987881?spm1001.2014.3001.5503 功能:管理员与普通用户两个角色登录,可以增删改查用户,增删改查药品等功能 JDK1.8 MySQL5.7

微信小程序——开发入门

注册小程序 微信公众平台 设置相关信息 设置好之后需要去获取appID和秘钥,后序开发需要用到。 下载开发工具并安装 微信开发者工具(稳定版 Stable Build)下载地址与更新日志 | 微信开放文档 创建项目 打开开发者工具创建一个新项目并如下…

使用 ONLYOFFICE 宏检索网站详细信息

在上一篇文章中,我们基于一位用户发送的 VBA 参考构建了一个功能完善的 ONLYOFFICE 宏。今天,我们想再进一步,为其添加一些 Whois API 功能。 什么是 ONLYOFFICE 宏 如果您是一名资深 Microsoft Excel 用户,那么相信您已对于 VBA…

Nacos(服务注册与发现)+SpringBoot+openFeign项目集成

📝 学技术、更要掌握学习的方法,一起学习,让进步发生 👩🏻 作者:一只IT攻城狮 ,关注我,不迷路 。 💐学习建议:1、养成习惯,学习java的任何一个技术…

分割1——图像分割的前世今生

首先讲讲:什么是计算机视觉? 计算机视觉是一门让计算机学会“看”的学科,研究如何自动理解图像和视频中的内容。 其次讲讲:计算机视觉有哪些任务?我们所要讲的图像分割位于什么地位? 计算机视觉的三大经典…

计算机体系结构基础知识介绍之使用动态调度、多重问题和推测来利用流水线

我们已经了解了动态调度、多发射和推测等单独的机制是如何工作的。(具体请参见本人前几篇博客) 现在我们把这三种机制结合起来,得到一种和现代微处理器非常相似的微架构。为了简单起见,我们只考虑每个时钟周期发射两条指令的情况…

《算法竞赛·快冲300题》每日一题:“窗户”

《算法竞赛快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。 所有题目放在自建的OJ New Online Judge。 用C/C、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。 文章目录 题目描述题解C代码Java代码Python代码 “ 窗…

es6 数组操作个人总结

es6 数组操作个人总结 动机数组数组生成可枚举对象转数组箭头函数筛选判断所有元素枚举循环 小结 动机 es6 ,说白了,就是增强版本的 js 。。。。。嗯,说到底,还是原生 js 罢了,不过比原有的 js 多了一些属性、类型、指…

【c++修行之路】智能指针

文章目录 前言为什么用智能指针智能指针简单实现unique_ptrshared_ptr 循环引用和weak_ptr的引入循环引用weak_ptr 定制删除器 前言 大家好久不见,今天来学习有关智能指针的内容~ 为什么用智能指针 假如我们有如下场景: double Div() {int x, y;cin …

Clion 配置Mingw64的 c++开发环境

1、Mingw64的安装与环境变量的配置 Mingw64文件下载 Mingw64下载地址:https://sourceforge.net/projects/mingw-w64/files/ posix相比win32拥有C 11多线程特性,sjlj和seh对应异常处理特性,sjlj较为古老,所以选择seh 配置环境变…

MongoDB踩过的坑

目录 启动MongoDB服务 可视化工具:MongoDB Compass 由于目标计算机积极拒绝,无法连接 BSONObj size: xxxx is invalid. Size must be between 0 and 16793600 (16MB) 启动MongoDB服务 1. 打开CMD 2. 进入安装MongoDB文件夹中的bin目录 3. mongod -…

mapBox 绘制多边形无法设置 边框宽度 解决方法

目录 一、问题 二、解决方法 三、总结 tips:如嫌繁琐,直接看有颜色的文字即可! 一、问题 1.使用mapBox在地图上绘制点、线、面。绘制多边形的时候发现 直接用 zh(一家提供地图引擎的公司),提供的绘制多边形的方法无法设置边框颜色和边框宽度。很是离…

龙蜥社区 6 月技术委员会会议召开!欢迎 5 位开放原子 TOC 导师加入

2023 年 6 月 16 日上午 10 点召开了龙蜥社区 6 月技术委员会线上会议,共计 38 人参会。本次会议由联通肖微主持,会议也荣幸的邀请到了开放原子 TOC 导师线上参会,技术委员们来自阿里云、统信、飞腾、中科方德、红旗、万里红、Intel、Arm、龙…

入门篇:从零上手GitOps

文章目录 GitOps 介绍如何将业务代码构建为容器镜像?如何将容器镜像部署到K8s?K8s如何实现自动扩容和自愈?1.传统的扩容和自愈2.k8s自愈机制3.k8s弹性扩容 如何借助GitOps实现应用秒级自动发布和回滚?1.传统 K8s 应用发布流程2.从…

高级细腻的家居照明,欧瑞博智能无主灯是怎么实现的?

作者 | 辰纹 来源 | 洞见新研社 如今的现代生活,人类对光的需求已超越简单照明,而是希望在不同场景下能有专属的细腻用光体验,智能照明应运而生,并成为上升趋势。现阶段,精细化家居需求要求智能照明不仅要巧妙融合美学…