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

浅谈redis分布式锁

浅谈redis分布式锁

分布式锁介绍

分布式锁,顾名思义,分布式系统中的锁,当多个进程不在同一个系统中时,用分布式锁控制各个进程对共享资源的访问,通过互斥来保持一致性。

使用场景:电商中某商品的秒杀活动,接口中的幂等性校验等

分布式锁的特性

(1)互斥性。锁的目的是获取共享资源的使用权,则需保证在并发情况下,同一时刻只有一个线程能获得锁
(2)加锁解锁对称性。线程使用加锁获得对共享资源的使用后,使用完毕必须解锁,即,加锁解锁需为同一个线程
(3)防止死锁。假如由系统等原因出现宕机情况导致线程获取到锁后来不及解锁,而其他线程无法获取到锁,此情况为死锁,避免此情况,有必要设置锁的有效时间,确保系统出故障,在超出锁的有效时间后其他线程能获取到锁。
(4)锁粒度尽量小。锁的颗粒度要尽量小,避免导致大量线程同时为获取同一个锁而造成阻塞
(5)可重入性。同一个线程在锁使用期间可以重复拿到同一个资源的锁。

常用的三种分布式锁

(1) 基于数据库表主键唯一性原理、排他锁实现分布式锁
(2) 基于ZK临时有序节点实现的分布式锁
(3) 基于redis中setnx命令的原子性实现的分布式锁

Redis分布式锁的阶段性进展

基于redis为目前最常见的锁及之前介绍的redis原理,简单介绍下redis分布式锁

实现一个简易的Redis分布式锁

阶段性1、利用redis的setnx和expire命令设置一个简单的redis锁,代码如下:

        String thread = "thread";Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", thread,30, TimeUnit.SECONDS);if(lock){//(1)加锁成功,处理handle("此处执行业务逻辑");//(2)处理完毕后解锁Object lockValue = redisTemplate.opsForValue().get("lock");if(thread.equals(lockValue)){//根据值对比判断是此线程的锁后删除锁redisTemplate.delete("lock");// 删除锁}}else{// 加锁失败: 重试或者直接返回获取锁失败retryOrReturn();}

以上代码看着没什么问题,实现了针对某个线程获取锁,且设置超时时间,并且根据值对比判断,只能此线程解锁。然而,忽略一个问题,由于在获取锁并删除这个过程中并非原子性,假如线程A删除锁的时候,锁已超时,自动解锁,同时其他线程B获取到锁,此时A把B持有的锁给删除。
那么如何实现锁对比判断和删除是一个原子性呢?见阶段性2

引入LUA

阶段性2、引入LUA删除锁
引入LUA,在获取锁的value值,对比是否一致,假如相等则删除,此段过程保证其原子性。代码如下:

        String lockKey = "lock";String thread = "thread";Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, thread,30, TimeUnit.SECONDS);if(lock){//(1)加锁成功,处理handle("此处执行业务逻辑");//(2)处理完毕后解锁Object lockValue = redisTemplate.opsForValue().get("lock");//LUA脚本String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";// 原子删除Object lock1 = redisTemplate.execute(new DefaultRedisScript<Integer>(script, Integer.class), Arrays.asList(lockKey, thread));}else{// 加锁失败: 重试或者直接返回获取锁失败retryOrReturn();}

框架Redission

以上结合redis+Lua的实现,在框架redission中均一实。Redission,在一个提供redis基础功能实现的情况下,还提供了一系列的分布式服务。从而使使用者的开发能够集中的专注于业务逻辑上。
除redission具备了锁的锁的互斥性和可重入性等基本功能,还增加了其他功能,比如引入Watch Dog解决了一个关于锁的自动续期问题,以及引入Red Lock增加了一些更安全的锁实现
简易代码如下:

       RLock lock = redisson.getLock ("lock");//获取锁或阻塞等待lock.lock ();try {handle("此处执行业务逻辑");} finally {//释放锁,已封装获取到此线程的锁并封装lock.unlock ();}

看门狗(Watch Dog)

场景:假如线程A获取到锁后,由于执行的逻辑耗时比较长, 在运行期间超出了默认的超时时间(30s)范围。则出现在线程A未执行完毕正常释放锁的情况下,由超时解锁,线程B重新获取到锁,引发故障。
针对此场景,引入Redission的Watch Dog实现自动续期,保证在线程A使用期间,不会超时而引发其他多个线程同时持有锁的情况
原理:看门狗相当于是一个定时任务,线程一旦加锁成功,会对应启动一个看门狗(属于后台线程)。每10s观察线程是否还持有锁,如果有,则延迟锁的的持有时间,将时间重置到30s,直至线程主动解锁或者系统故障看门狗不执行
注意:如果指定超时时间,不会自动续签时间,此时需保证线程执行业务逻辑的时间务必大于指定超时时间。

关于红锁(RedLock)

场景:假设在集群中,有多个redis master节点,这些节点是完全独立的,其中一个master获取到锁后发生故障,此时还未来得及发生主从复制,即key未来得及同步到从节点上。而此时通过哨兵选举,其一slave节点升级为master节点。那么此时会出现,后续应用会申请到同一个锁,则此时同一个锁被获取了不只一次,导致出现问题。
针对以上情况,引入红锁,利用多个 Redission node 最终 组成 RedLock分布式锁,Redission node 是互相独立的,不存在任何复制或者其他隐含的分布式协调机制。解决主从结构下存在的安全问题。

RedLock特点
加锁过程中,在一个redis集群中,依次从N个reidis节点上获取锁(需要相同的key和value),并且至少半数以上(N/2+1)的redis节点获取到锁,才算是获取锁成功,否则获取失败。红锁以节点组的方式解决单个节点出现故障的情况。
** 场景**:假设redis集群中五个主节点,客户端申请获取锁的请求到了redis节点(节点三个A\B\C获取到锁)并成功执行setnx操作,此时假如其中一节点A宕机,则返回给客户端的响应失败,在客户端层面看,是获取锁超时而失败,但是在redis集群看来是获取锁成功。然后客户端在释放锁时,也会对那些获取锁失败的redis节点发起同样的请求。

RedLock弊端:在加锁/解锁多个节点,其过程均耗费时间,性能较低。针对红锁,假如全部redis重启,也可能会出现锁失效的问题。
因此是否使用红锁,需结合实际场景使用

相关文章:

浅谈redis分布式锁

浅谈redis分布式锁 分布式锁介绍 分布式锁&#xff0c;顾名思义&#xff0c;分布式系统中的锁&#xff0c;当多个进程不在同一个系统中时&#xff0c;用分布式锁控制各个进程对共享资源的访问&#xff0c;通过互斥来保持一致性。 使用场景&#xff1a;电商中某商品的秒杀活动…...

【Python保姆级教程】List容器

文章目录 前言一、列表是什么二、列表的定义2.1 有初始值2.2 空列表使用方括号创建空列表使用list()函数创建空列表 三、list列表常用操作3.1 添加元素3.2 删除元素3.3 修改元素3.4 列表长度 四、遍历操作4.1 使用for循环4.2 使用while循环和索引 总结 前言 Python是一种广泛使…...

微服务保护-授权规则

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…...

v-if失效原因

一般v-if失效都是和绑定变量有关&#xff0c;我所知道的一般有两种 1.绑定的变量为String类型或者其他类型 就是返回的变量类型与所需要的布尔类型不匹配。 <template><div><div id"container" ref"container" v-iftype></div>&l…...

Chrome 基于 Wappalyzer 查看网站所用的前端技术栈

1. 找到谷歌商店 https://chrome.google.com/webstore/search/wappalyzer?utm_sourceext_app_menu 2. 搜索 Wappalyzer 3. 添加至Chrome 4. 使用 插件 比如打开 https://www.bilibili.com/ 就可以看到其所以用的前端技术栈了...

python的装饰器

作用:在不改变原来函数的代码情况下,进行修改,或者增加函数的功能装饰器本质上就是一个闭包雏形:def wrapper(fn): wrapper: 装饰器 , fn: 目标函数def inner():# 在目标函数执行前的一些动作fn()# 在目标函数执行后的一些动作return inner #千万别加(),这里是返回一…...

P2P协议的传输艺术

TP 采用两个 TCP 连接来传输一个文件。 控制连接&#xff1a;服务器以被动的方式&#xff0c;打开众所周知用于 FTP 的端口 21&#xff0c;客户端则主动发起连接。该连接将命令从客户端传给服务器&#xff0c;并传回服务器的应答。常用的命令有&#xff1a;list——获取文件目…...

辅助驾驶功能开发-功能规范篇(21)-4-XP行泊一体方案功能规范

XPilot Parking 自动泊车系统 • 超级自动泊车辅助(Super AutoParking Assist)、语音控制泊车辅助(Autoparking with Speech) - 产品定义 超级自动泊车辅助是⼀个增强的自动泊车辅助系统。在超级自动泊车辅助系统中,识别车位将会变得实时可见, 并且不可泊入的⻋位也将…...

家政服务小程序上门服务小程序预约上门服务维修保洁上门服务在线派单技师入口

套餐一:源码=1500元 套餐二:全包服务 包服务器+域名+认证小程序+搭建+售后=2000元 主要功能: 1、服务商入驻 支持个人或企业入驻成为平台服务商; 2、发布商品 入驻服务商后,可以发布服务商品,用户可以在线下单,预约服务; 3、发布需求 用户可以发布一口价或竞价需求…...

LeetCode精选100题-【3数之和】-2

这里写自定义目录标题 解法1:解法2: 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。注意&#xff1a;答案中不…...

springboot集成mybatis-plus

一、在spring boot中配置mybatis-plus 1、创建一个spring boot项目&#xff0c;注意勾选mysql 2、在pom.xml文件中添加mybatis-plus的依赖包 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0&qu…...

再想一想GPT

一 前言 花了大概两天时间看完《这就是ChatGPT》&#xff0c;触动还是挺大的&#xff0c;让我静下来&#xff0c;认真地想一想&#xff0c;是否真正理解了ChatGPT&#xff0c;又能给我们以什么样的启发。 二 思考 在工作和生活中&#xff0c;使用ChatGPT或文心一言&#xff0c;…...

Blazor前后端框架Known-V1.2.15

V1.2.15 Known是基于C#和Blazor开发的前后端分离快速开发框架&#xff0c;开箱即用&#xff0c;跨平台&#xff0c;一处代码&#xff0c;多处运行。 Gitee&#xff1a; https://gitee.com/known/KnownGithub&#xff1a;https://github.com/known/Known 概述 基于C#和Blazo…...

Tomcat 的部署和优化

目录 1、什么是Tomcat 1.1、静态页面的选择 2、Tomcat是怎么运行的 3、安装jdk &#xff06; 部署jdk环境 & Tomcat 安装 1、安装jdk 2、配置jdk环境变量 3、tomcat安装 4、Tomcat启动 5.优化tomcat启动速度 6.Tomcat的主要命令 7.Tomcat 配置虚拟主机 8.Tomca…...

后端中间件安装与启动(Redis、Nginx、Nacos、Kafka)

后端中间件安装与启动 RedisNginxNacosKafka Redis 1.打开cmd终端&#xff0c;进入redis文件目录 2.输入redis-server.exe redis.windows.conf即可启动&#xff0c;不能关闭cmd窗口 &#xff08;端口配置方式&#xff1a;redis目录下的redis.windows.conf配置文件&#xff0c;…...

【电子元件】常用电子元器件的识别之电阻器

目录 前言1. 电阻器的识别1.1 普通电阻器的识别1. 普通电阻器的识别色环电阻器绕线电阻器水泥电阻器贴片电阻器网络电阻器(排阻)保险电阻器精密电阻器2. 电阻器的符号3. 普通电阻器的主要参数标称阻值和允许误差额定功率最高工作电压温度系数1.2 电位器的识别1. 电位器的识别…...

指针和数组笔试题讲解(2)

&#x1f435;本篇文章将会对上篇一维数组笔试题的剩余部分和二维数组的笔试题进行讲解 一、一维数组 1>试题部分(一)✏️ char* p "abcdef";printf("%zd\n", sizeof(p)); printf("%zd\n", sizeof(p 1)); printf("%zd\n", sizeo…...

MapReduce YARN 的部署

1、部署说明 Hadoop HDFS分布式文件系统&#xff0c;我们会启动&#xff1a; NameNode进程作为管理节点DataNode进程作为工作节点SecondaryNamenode作为辅助 同理&#xff0c;Hadoop YARN分布式资源调度&#xff0c;会启动&#xff1a;ResourceManager进程作为管理节点NodeM…...

vue 引入zTree

下载js包解压后找个地方放文件夹内 引入 import "/common/zTree/js/jquery-1.4.4.min" import "/common/zTree/js/jquery.ztree.core.min.js" import "/common/zTree/js/jquery.ztree.excheck.min.js" import "/common/zTree/css/metroSt…...

链队列的基本操作(带头结点,不带头结点)

结构体 typedef struct linknode{int data;struct linknode* next;后继指针 }linknode; typedef struct {linknode* front, * rear;//队头队尾指针 }linkquene; 初始化队列&#xff08;带头结点&#xff09; int initquene(linkquene* q)//初始化队列 {q->front q->r…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...