浅谈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分布式锁 分布式锁介绍 分布式锁,顾名思义,分布式系统中的锁,当多个进程不在同一个系统中时,用分布式锁控制各个进程对共享资源的访问,通过互斥来保持一致性。 使用场景:电商中某商品的秒杀活动…...

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

微服务保护-授权规则
个人名片: 博主:酒徒ᝰ. 个人简介:沉醉在酒中,借着一股酒劲,去拼搏一个未来。 本篇励志:三人行,必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》,SpringCloud…...
v-if失效原因
一般v-if失效都是和绑定变量有关,我所知道的一般有两种 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 连接来传输一个文件。 控制连接:服务器以被动的方式,打开众所周知用于 FTP 的端口 21,客户端则主动发起连接。该连接将命令从客户端传给服务器,并传回服务器的应答。常用的命令有:list——获取文件目…...

辅助驾驶功能开发-功能规范篇(21)-4-XP行泊一体方案功能规范
XPilot Parking 自动泊车系统 • 超级自动泊车辅助(Super AutoParking Assist)、语音控制泊车辅助(Autoparking with Speech) - 产品定义 超级自动泊车辅助是⼀个增强的自动泊车辅助系统。在超级自动泊车辅助系统中,识别车位将会变得实时可见, 并且不可泊入的⻋位也将…...
家政服务小程序上门服务小程序预约上门服务维修保洁上门服务在线派单技师入口
套餐一:源码=1500元 套餐二:全包服务 包服务器+域名+认证小程序+搭建+售后=2000元 主要功能: 1、服务商入驻 支持个人或企业入驻成为平台服务商; 2、发布商品 入驻服务商后,可以发布服务商品,用户可以在线下单,预约服务; 3、发布需求 用户可以发布一口价或竞价需求…...
LeetCode精选100题-【3数之和】-2
这里写自定义目录标题 解法1:解法2: 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。注意:答案中不…...

springboot集成mybatis-plus
一、在spring boot中配置mybatis-plus 1、创建一个spring boot项目,注意勾选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》,触动还是挺大的,让我静下来,认真地想一想,是否真正理解了ChatGPT,又能给我们以什么样的启发。 二 思考 在工作和生活中,使用ChatGPT或文心一言,…...

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

Tomcat 的部署和优化
目录 1、什么是Tomcat 1.1、静态页面的选择 2、Tomcat是怎么运行的 3、安装jdk & 部署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终端,进入redis文件目录 2.输入redis-server.exe redis.windows.conf即可启动,不能关闭cmd窗口 (端口配置方式:redis目录下的redis.windows.conf配置文件,…...

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

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

MapReduce YARN 的部署
1、部署说明 Hadoop HDFS分布式文件系统,我们会启动: NameNode进程作为管理节点DataNode进程作为工作节点SecondaryNamenode作为辅助 同理,Hadoop YARN分布式资源调度,会启动: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; 初始化队列(带头结点) int initquene(linkquene* q)//初始化队列 {q->front q->r…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...