首页 > 其他分享 >关于分布式锁的一些思考

关于分布式锁的一些思考

时间:2024-04-11 10:00:50浏览次数:22  
标签:释放 Redis 自动 关于 思考 超时 续费 分布式

首先分布式锁要解决的是什么问题? 解决的,对唯一资源的操作控制,简单说就是,有一些资源只能同时被一个地方使用。 常见的分布式锁的实现方式有哪些? 这是一个常见的面试题,一般给出的答案有以下几个:

  • 基于数据库的实现方式。可以通过在数据库表中使用排他锁(for update)来实现分布式锁,当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁,这种方法可以有效地解决分布式系统中并发访问的问题,但存在一些问题,如可能导致表锁,影响系统性能。
  • 基于Redis的实现方式。可以使用Redis的SET命令来加锁,例如SET KEY VALUE NX PX milliseconds,其中NX表示只在键不存在时设置键,PX表示设置键的过期时间为毫秒,这种方法可以保证加锁的原子性,并且当锁超时后能自动释放,但存在一些限制,如需要确保锁的唯一性和如何安全地释放锁。
  • 基于ZooKeeper的实现方式。可以利用ZooKeeper的有序节点或节点名称的唯一性来实现分布式锁,例如,所有请求都创建同一个节点(lock/lockKey),最终只有一个创建成功,即获得锁,这种方式利用了ZooKeeper的强一致性和可靠性,能有效解决分布式锁的问题。
Mysql怎么设置排他锁? -- 启动一个事务 START TRANSACTION; -- 选择特定记录并对其加排他锁 SELECT * FROM your_table WHERE condition_to_match_record FOR UPDATE; -- 进行更新或其他需要的操作 -- UPDATE your_table SET ... WHERE condition_to_match_record; -- 提交或回滚事务 COMMIT; Redis怎么实现分布式锁? Redis 锁主要利用 Redis 的 setnx 命令。
  • 加锁命令:SETNX key value,当键不存在时,对键进行设置操作并返回成功,否则返回失败。KEY 是锁的唯一标识,一般按业务来决定命名。
  • 解锁命令:DEL key,通过删除键值对释放锁,以便其他线程可以通过 SETNX 命令来获取锁。
  • 锁超时:EXPIRE key timeout, 设置 key 的超时时间,以保证即使锁没有被显式释放,锁也可以在一定时间后自动释放,避免资源被永远锁住。
// 假设你已经配置了Redis连接并获取了IDatabase实例 ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); IDatabase db = redis.GetDatabase(); // 分布式锁的键和超时时间 string lockKey = "my-distributed-lock"; TimeSpan lockTimeout = TimeSpan.FromSeconds(30); // 锁的超时时间设置为30秒 // 创建分布式锁实例 RedisDistributedLock redisLock = new RedisDistributedLock(db, lockKey, lockTimeout); // 尝试获取锁 bool lockAcquired = await redisLock.AcquireLockAsync(); if (lockAcquired) { try { // 在这里执行需要加锁的代码... Console.WriteLine("Lock acquired. Executing critical section..."); // 模拟一些工作... await Task.Delay(10000); // 等待10秒 Console.WriteLine("Critical section executed."); } finally { // 确保在finally块中释放锁,无论是否发生异常 redisLock.ReleaseLock(); } } else { Console.WriteLine("Failed to acquire lock."); } // 如果你想要定期检查并释放可能已经超时的锁(防止死锁),可以这样做: // await redisLock.CheckAndReleaseLockAsync(); // 最后,不要忘记关闭Redis连接(通常在应用程序关闭时) redis.Close(); redis.Dispose(); Redis实现分布式锁为了防止代码未执行完,加入了自动续费的策略。这块引发我的另一个疑问,比如,自动续费如果不加控制,会造成实时上的死锁,也就是说,如果程序发生了未被catch的异常或者说异常情况的时候,自动续费策略在一直给锁加上锁时间,这样这个锁可能就无法被释放了。 所以自动续费也需要有一些策略,如下:
  1. 设置最大续费次数
你可以为锁的自动续费设置一个最大次数限制。一旦达到这个限制,即使锁尚未被显式释放,也不再自动续期,从而允许其他进程或线程有机会获取锁。
  1. 结合锁的过期时间
除了自动续费外,你还应该为锁设置一个固定的过期时间。这个过期时间应该是一个相对较长的值,但远小于无限期。即使自动续费逻辑在运行,一旦达到这个过期时间,锁也会自动失效。
  1. 监控和报警
为了增加安全性,你可以实现监控逻辑来跟踪锁的持有时间和续费次数。如果某个锁被持有超过预期时间或续费次数异常,可以触发报警通知,以便管理员或开发人员及时介入处理。
  1. 优雅地处理应用程序退出
确保你的应用程序在退出时能够优雅地释放所有持有的锁。这可以通过在应用程序的关闭逻辑中添加显式的锁释放操作来实现。 此外还有一个细节,就是自动续费策略是否需要关心代码执行的情况,也就是说,在启动自动续费的那块执行代码的执行情况,是否需要被作为是否续费的判断条件,答案是否定的。因为自动续费的目的是确保锁在预期的时间内保持有效,而不是监控持有锁的方法的执行状态。锁的持有者(即你的应用程序)应该在完成所需操作后显式释放锁,而不是依赖于方法是否仍在执行。这块我的理解是,自动续费的逻辑应该简单而可靠,让自动续费程序更加纯粹的执行自己的逻辑,自动续费的条件就是能够查询到锁的存在就给它续费即可。 当然,即使加了自动续费的保障,分布式锁的使用中仍然有可能会出现并发的情况,比如,自动续费失败造成了过期释放锁,自动续费超过了规定次数造成的超时释放锁等。那么我们有什么需要去做的来避免这些问题发生吗?
  • 锁的粒度 尽量减小锁的粒度,让锁中执行的代码更简单
  • 代码的规范 锁中执行的代码规范,比如异常处理要完整,规范,异常发生后要及时释放锁等
  • 锁的超时时间的设置 需要根据实际情况,设置锁的过期时间,确保正常情况下或者说一般情况下,可以在过期时间之内完成代码执行,并释放锁。
  • 使用RedLock算法 RedLock算法是一种改进的分布式锁算法,通过在多个Redis节点上获取锁来提高可靠性和容错性。即使部分节点故障,只要大多数节点可用,就能保证锁的正确性。
 

标签:释放,Redis,自动,关于,思考,超时,续费,分布式
From: https://www.cnblogs.com/pangzili/p/18128161

相关文章

  • (Java)数据结构——排序(第一节)堆排序+PTA L2-012 关于堆的判断
    前言本博客是博主用于复习数据结构以及算法的博客,如果疏忽出现错误,还望各位指正。堆排序(HeapSort)概念堆排序是一种基于堆数据结构的排序算法,其核心思想是将待排序的序列构建成一个最大堆(或最小堆),然后将堆顶元素与最后一个元素交换,再将剩余元素重新调整为最大堆(或最小堆),重复......
  • 聊聊分布式事务
    分布式事务,算是分布式系统极为重要的一个模块。分布式事务的概念,网上随手可见,我不多讲。今天主要想聊聊,分布式事务的解决思路及其适用场景。在说具体思路之前,我先假设一个业务调度功能,分别会调用A、B、C三个服务。要保证这三个服务的事务,该怎么办呢?可靠消息队列A业务完成并......
  • 关于JSP的MVC设计(新手小白白week7速看)
    通过之前的学习JSP,我们发现我们可以用过Servlet来实现下图功能但是我们发现这样写也太麻烦了吧,而且工程量巨大,所以MVC设计应运而生在开始前,我们需要创建三个软件包,并且创建好我们需要的controller,dao,model相应文件通过需要在WEB-INF中创建目录views,同时把footer,header,i......
  • 分布式任务调度平台XXL-JOB:调度日志打印时区问题
    系列文章目录文章目录系列文章目录前言前言前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。Quartz作为开源作业调度中的佼佼者,是作业调度的首选。但是集群环境中Q......
  • Python中关于finally的使用场景
    finally关键字在Python中用于定义一个代码块,该代码块在try-except结构中无论是否发生异常,或者在try块中执行了return、break、continue等控制流语句,都会被执行。finally子句提供了确保某些清理操作(如释放资源、关闭文件、断开连接等)始终执行的一种机制,即使程序在处理过程中遭遇异......
  • 关于淘宝镜像过期问题解决方案
    问题:将项目拷贝到另一台电脑启动时报错Error:Theprojectseemstorequireyarnbutit'snotinstalled解决方法:1.删除项目中的yarn.lock文件2.终端执行npminstall-gyarn再次启动项目npmrunserve就可以了......
  • 关于一个软件开发的过程
    在踏入软件开发的领域之前,我对于这一行业充满了未知与好奇。当我第一次深入接触软件开发的完整流程时,那种新奇、挑战与收获并存的体验,让我有了许多深刻的感悟。起初,我对软件开发流程的理解仅限于编写代码这一环节。然而,随着学习的深入,我逐渐意识到,软件开发其实是一个系统且复杂的......
  • 关于atoi和strtol函数
    提示:文章文章目录前言一、背景二、2.12.2总结前言前期疑问:本文目标:一、背景最近在牛课题HJ33整数与IP地址间的转换题目时,涉及到大量的字符串和整型数值的转换,重新看一下字符和整型转换的函数二、2.1​避免使用atoi、atol、atoll、atof函数字符串中可能......
  • 关于抽象类和接口(详解)
    关于抽象类和接口一、抽象类1.语法规则2.注意事项3.抽象类的作用二、接口1.语法规则2.实现多个接口一、抽象类有些方法是抽象的,没有实际工作的方法,我们可以把它设计成一个抽象方法,比如draw(画画),不能实例化对象。包含抽象方法的类我们称为抽象类(abstractclass......
  • 关于需要root权限启动图形应用记录
    关于需要root权限启动图形应用记录环境Kernel:6.8.4-arch1-1OS:ArchLinuxx86_64DE:hyprland问题来源在vmware中安装win11,想更改Edit>Preferences>Memory到"FitallvirtualmachinememoryintoreservedhostRAM"来提高访问内存效率,但必须用root运行vmware才能改变......