上篇文章:

Redis原理之缓存https://blog.csdn.net/sniper_fandc/article/details/149141968?fromshare=blogdetail&sharetype=blogdetail&sharerId=149141968&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link​​​​​​​

目录

1 基本实现

2 引入过期时间

3 引入校验id

4 引入lua脚本

5 引入看门狗机制(watch dog)

6 引入Redlock算法


        普通的锁比如Java中的synchronized通常解决的是线程安全问题,但是到了多进程多服务器环境下,普通的锁就无法保证多个进程或节点同时访问同一个资源的问题,这就需要分布式锁。

        分布式锁从本质来讲是通过一个公共服务器来记录加锁状态。所有的进程或节点访问某个资源时先访问该服务器尝试加锁,待某个已经加锁的进程或节点访问结束后再解锁让其他进程或节点访问。

        注意:个人理解的分布式锁核心问题是进程间通信问题。分布式环境下,进程间通过网络通信,网络IO的时间是各种数据IO方式中最慢的(寄存器>缓存>内存>磁盘>网络),因此进程对一个数据进行访问就有了时延。而在这个时延期间,如果有其他进程也对该数据进行访问(失去了原子性),就可能造成数据不一致或重复读写等问题,因此需要通过锁来控制进程通信的顺序问题(互斥性)。

1 基本实现

        注意:实现分布式锁可以有很多方式,比如Redis、MySQL和ZooKeeper等等。

        这里使用Redis来实现分布式锁。核心操作是当多个客户端进程查询同一个资源时,请求负载均衡到某个服务器后首先访问Redis,第一个进程会在Redis设置关于该资源的key-value(加锁)。此时其他进程(服务器)如果也想查询该资源就会去Redis尝试加锁,如果发现key已经存在就加锁失败,可以选择阻塞或返回(具体哪种看实现场景)。待第一个进程访问资源结束后,就会把Redis上的这个key-value删除(解锁)。

        使用setnx命令即可实现这个分布式锁:key不存在则设置(加锁),否则失败(加锁失败)。使用del命令即可实现解锁。

2 引入过期时间

        当在Redis加锁的服务器如果出现意外情况,比如宕机、断电等等,锁还未释放,此时其它服务器就无法对该资源加锁,从而无法访问资源。

        解决办法:对key-value引入过期时间,即使用set ex nx命令来设置过期时间。

        注意:不能使用setnx、expire两条命令来实现上述效果,因为Redis的命令是串行化执行的,无法保证多条命令执行的原子性。

3 引入校验id

        上述方案还有问题,由于多个服务器都可以访问Redis来执行各种命令,就可能出现一个服务器设置键值对(加锁),另一个服务器删除键值对(解锁),从而导致问题(当然这个问题不是故意的)。

        解决办法:为每个服务器引入校验id,加锁时针对某个资源的key的value设置为服务器的校验id值。当解锁时,首先查询准备执行del命令的服务器的校验id是否和value值相同,如果相同则允许执行del;如果不同则不允许执行。上述过程由服务器来完成:

String key = [要加锁的资源id];String serverId = [服务器的id];// 加锁, 设置过期时间为 10sredis.set(key, serverId, "NX", "EX", "10s");// 执行各种业务逻辑, 比如修改数据库数据.doSomeThing();// 解锁, 删除 key. 但是删除前要检验下serverId是否匹配.if (redis.get(key) == serverId) {redis.del(key);}

4 引入lua脚本

        新的问题又出现了,执行解锁的过程中,由于get命令和del命令的执行不是原子性的,因此就会出现命令插队的情况。比如同一个服务器多个线程都需要操作同一个资源,当执行解锁时按照如下所示顺序执行:

        在线程2执行完get判断锁的校验id和服务器id一样后,线程1继续执行del已经解锁了。而此时服务器2判断该资源是无锁状态就加锁,此时线程2又执行del把刚加的锁给解除了,从而引起问题。

        解决办法:保证解锁时两个命令执行的原子性。可以用redis事务来解决,但是更好的方案是lua脚本。Lua是Redis的内嵌脚本语言,Lua脚本的执行是原子性的:

if redis.call('get',KEYS[1]) == ARGV[1] thenreturn redis.call('del',KEYS[1])elsereturn 0end;

        KEYS和ARGV是调用脚本时输入的参数。上述代码存于.lua后缀的文件,并发送给Redis服务器来执行。

5 引入看门狗机制(watch dog)

        从引入过期时间开始就一直存留一个问题:过期时间设多长合适?过短的时间可能服务器还没有访问完资源锁就被释放了;过长的时间可能服务器早已经结束资源访问但是锁迟迟无法释放(影响系统并发量和吞吐量)。

        解决办法:动态调整过期时间,初始设置一个时间,待时间快结束时(定期)查询服务器是否访问资源结束,如果未结束则延长时间(续约,重新设置过期时间);如果已经结束则通过lua脚本解锁。这个动态调整过期时间的过程由服务器的一个线程专门负责,该线程也被成为看门狗,因此这个机制就被称为看门狗机制

        上述过程,如果服务器宕机,看门狗线程也就挂了,此时key的过期时间无人续约,也就快速解锁便于让其它服务器进程能及时访问资源。

6 引入Redlock算法

        通常Redis节点的部署不是单机形式,至少是主从复制。主从复制存在从节点和主节点短时间的数据不一致,假设向master进行加锁操作,master还未及时同步给slave就故障,此时其它服务器也就可以进行加锁操作。

        解决办法:引入Redlock算法,具体而言,加锁时不是向一个master节点写入,而是向所有的master节点都加锁。如果超过超时时间仍未加锁成功,则认为对该master加锁失败(该节点可能宕机)。当向所有master都尝试加锁后,统计加锁成功的节点数超过半数master节点数,则认为加锁成功。通过这样,即使有master节点挂了,其它master节点仍然保存着锁的信息。

        解锁时,也要向所有的master节点尝试解锁。即Redlock算法的核心思想就是冗余备份,同时结合分布式的少数服从多数的思想。

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

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

相关文章

网络基础19:OSPF单区域原理实验

一、实验拓扑二、设备配置AR1 配置<AR1> system-view [AR1] interface GigabitEthernet0/0/0 [AR1-GigabitEthernet0/0/0] ip address 192.168.1.1 24 [AR1-GigabitEthernet0/0/0] quit[AR1] ospf 1 router-id 0.0.0.1 [AR1-ospf-1] area 0 [AR1-ospf-1-area-0.0.0.0] ne…

【实战推荐】小白也能上手的多端陪玩系统平台项目源码

在当今的游戏市场中&#xff0c;游戏陪玩服务已经成为了一个热门领域。无论是寻找高手带自己升级、学习游戏技巧&#xff0c;还是仅仅想找人一起玩耍&#xff0c;越来越多的玩家倾向于通过专业的陪玩平台找到合适的伙伴。对于想要进入这个市场的创业者和开发者来说&#xff0c;…

[hot 100 ]最长连续序列-Python3

需要时间复杂度为O(n)&#xff0c;如果采用暴力求解则为O(n^2)1.在遍历hash表的时候检查是否当前值为连续序列的最小值,如果是&#xff0c;则跳过此次循环,这样使得原本需要对每个值进行一次遍历变成了对每个值只访问一次:2.使用set()和普通for num in nums的区别&#xff1a;

[element-plus] el-table show-overflow-tooltip 没有显示省略号

<el-table-columnprop"col2"label"列2"width"70"show-overflow-tooltip/> </el-table-column>不知道为什么没有省略号 再给加个样式 <el-table-column prop"col2" label"列2" width"70" show-ove…

网络基础19--OSPF路由协议单区域

一. RIP的不足跳数评估非最优路径&#xff1a;RIP以跳数作为度量值&#xff0c;不考虑带宽&#xff0c;可能导致次优路径选择。网络规模限制&#xff1a;最大跳数为16&#xff0c;限制了网络规模。收敛速度慢&#xff1a;更新周期长&#xff08;默认30秒&#xff09;&#xff0…

SpringBoot 整合 Langchain4j 实现会话记忆存储深度解析

目录 一、前言 二、AI大模型会话记忆介绍 2.1 AI 大模型的会话记忆是什么 2.2 AI 大模型为什么需要会话记忆 2.3 AI 大模型会话记忆常用实现方案 2.4 LangChain4j 会话记忆介绍 2.4.1 LangChain4j 会话记忆介绍 2.4.2 LangChain4j 会话记忆类型 三、Langchain4j 会话记…

《R 矩阵》

《R 矩阵》 引言 在数学与统计学领域&#xff0c;矩阵是一种强大的工具&#xff0c;它广泛应用于各种科学研究和实际应用中。本文将深入探讨 R 矩阵的概念、特性及其在数据分析中的应用。 R 矩阵的定义与特性 1. 定义 R 矩阵&#xff0c;全称为“实对称矩阵”&#xff0c;是指一…

从java到vue3:第二天

文章目录前言一、setup1.定义2.作用3.响应式数据1.ref2.reactive3.ref与reactive的区别4.toRefs5.computed二、Watch1.监视ref&#xff1a;基本数据2.监视ref&#xff1a;对象数据3.监视reactive&#xff1a;对象数据。4.监视ref或reactive中某个属性5.监视多个属性总结前言 s…

基于 JmsClient 的高效消息通信架构设计与实现

1. 引言 1.1 消息通信在分布式系统中的作用 随着企业级应用的复杂性不断提升,传统的同步调用方式已难以满足高并发、低延迟、高可用等需求。消息通信机制通过异步解耦的方式,提升了系统的可扩展性和容错能力。Java Message Service(JMS)作为一种标准的消息中间件接口,广…

2025.7.24

这题写了好一会, 因为遇到一些问题分糖分的是原来的糖果还是拿到了别人给的糖果加起来一起的?如果是分原来的糖果之后那就要再另外那一个数组存, 数组初始为0, 那么分完之后自己的那一份应该存进另一个数组, 是加法如果是分拿到了别人给的糖果加起来一起的, 那么分完之后不是直…

学习设计模式《十九》——享元模式

一、基础概念 享元模式的本质是【分离与共享】。 思考享元模式序号说明1 【分离】的是对象状态中变与不变的部分&#xff0c;【共享】的是对象中不变的部分&#xff1b; 享元模式的关键就在于【分离变与不变】把不变的部分作为享元对象的内部状态&#xff0c;而变化部分则作为外…

AI助力 三步实现电子发票发票号码的提取

小伙伴们&#xff0c;大家好今天我们来利用ollama本地大模型&#xff0c;三步实现电子发票发票号码的提取。 步骤1&#xff1a;安装Ollama访问官网https://ollama.com/ 下载相应的版本进行安装&#xff0c;下载属于自己平台的ollama&#xff0c;根据安装向导完成安装。…

告别下载中断:深入解析Tomcat JSP中的“远程主机强迫关闭连接”与“软件中止连接”

在Web开发中,提供文件下载功能是一项常见需求。然而,当用户在Tomcat JSP项目中尝试下载文件时,有时会遭遇令人头疼的错误提示:“远程主机强迫关闭了一个现有链接”(Remote host closed connection unexpectedly)或“您的主机中的软件中止了一个已建立的连接”(Software …

实战演练—基于Transformers的NLP解决方案总结

实战演练—基于Transformers的NLP解决方案总结 截至目前讲解的基础组件 以文本分类为例 Transformers显存优化 截至目前讲解的基础组件 Pipeline 流水线,用于模型推理,封装了完整的推理逻辑,包括数据预处理、模型预测及后处理 Tokenizer 分词器,用于数据预处理,将原始文本…

Java 解析前端上传 ZIP 压缩包内 Excel 文件的完整实现方案

使用zip压缩包上传excel文件的优点1、体积更小&#xff0c;节约带宽2、比excel直接读取更方便携带参数及修改3、可以一次性批量导入Java代码 ControllerPostMapping("/importData")ApiOperationSupport(order 3)ApiOperation(value "上传")public R impo…

【shell脚本编程】day1 备份指定文件类型

文章目录1、脚本要求2、脚本编写3、脚本解释4、脚本改进1、脚本要求 编写一个脚本&#xff0c;遍历/data/目录下的.txt文件将这些txt文件做一个备份备份的文件名增加一个年月日的后缀&#xff0c;比如将aming.txt备份为aming.txt_20231001 2、脚本编写 [rootlocalhost shell…

Gata 携手 Walrus 构建 AI 的开放执行基础设施

致力于开发去中心化大模型推理、训练和数据技术的 Gata&#xff0c;现已整合 Walrus&#xff0c;作为其 AI 开放执行基础设施的核心组件。Walrus 将为 Gata 的首款产品 DataAgent 提供关键的数据层&#xff0c;助力其全套应用&#xff0c;将去中心化 AI 的优势直接带给用户&…

DNS及DNS域名解析流程

文章目录什么是DNS域名解析DNS服务器DNS域名解析流程什么是DNS域名解析 我们首先要了解域名和IP地址的区别。IP地址是互联网上计算机唯一的逻辑地址&#xff0c;通过IP地址实现不同计算机之间的相互通信&#xff0c;每台联网计算机都需要通过IP地址来互相联系和分别。 但由于I…

用 STM32 的 SYSTICK 定时器与端口复用重映射玩转嵌入式开发

目录 1. SYSTICK 定时器的基本功:时间管理大师 1.1 SYSTICK 的核心寄存器与工作原理 1.2 配置 SYSTICK 的正确姿势 1.3 实战:用 SYSTICK 实现精准延时 1.4 小技巧:SYSTICK 的低功耗优化 2. SYSTICK 中断:让你的程序“活”起来 2.1 配置 SYSTICK 中断 2.2 实战:用 S…

Sa-Token:轻量级Java权限认证框架使用指南

一、Sa-Token简介 Sa-Token 是一个专注于权限认证的轻量级 Java 框架&#xff0c;旨在简化登录认证、权限控制等功能的实现。其核心功能包括&#xff1a; 登录认证&#xff1a;通过 Token 机制管理用户会话&#xff0c;支持单点登录&#xff08;SSO&#xff09;。权限认证&am…