基于Redis的分布式锁和Redlock算法

基于Redis的分布式锁和Redlock算法

作者: conan5566 2021-06-03 00:02:43

存储

存储软件

分布式

算法

Redis 在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量。

[[403381]]

 本文转载自微信公众号「UP技术控」,作者conan5566。转载本文请联系UP技术控公众号。

在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量。

而同步的本质是通过锁来实现的。为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记。这个标记可以理解为锁。

不同地方实现锁的方式也不一样,只要能满足所有线程都能看得到标记即可。如 Java 中 synchronize 是在对象头设置标记,Lock 接口的实现类基本上都只是某一个 volitile 修饰的 int 型变量其保证每个线程都能拥有对该 int 的可见性和原子修改,linux 内核中也是利用互斥量或信号量等内存数据做标记。

除了利用内存数据做锁其实任何互斥的都能做锁(只考虑互斥情况),如流水表中流水号与时间结合做幂等校验可以看作是一个不会释放的锁,或者使用某个文件是否存在作为锁等。只需要满足在对标记进行修改能保证原子性和内存可见性即可。

1 什么是分布式?

分布式的 CAP 理论告诉我们:

任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。

目前很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。基于 CAP理论,很多系统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证最终一致性。

分布式场景

此处主要指集群模式下,多个相同服务同时开启.

在许多的场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。很多时候我们需要保证一个方法在同一时间内只能被同一个线程执行。在单机环境中,通过 Java 提供的并发 API 我们可以解决,但是在分布式环境下,就没有那么简单啦。

  • 分布式与单机情况下最大的不同在于其不是多线程而是多进程。
  • 多线程由于可以共享堆内存,因此可以简单的采取内存作为标记存储位置。而进程之间甚至可能都不在同一台物理机上,因此需要将标记存储在一个所有进程都能看到的地方。

什么是分布式锁?

  • 当在分布式模型下,数据只有一份(或有限制),此时需要利用锁的技术控制某一时刻修改数据的进程数。
  • 与单机模式下的锁不仅需要保证进程可见,还需要考虑进程与锁之间的网络问题。(我觉得分布式情况下之所以问题变得复杂,主要就是需要考虑到网络的延时和不可靠。。。一个大坑)
  • 分布式锁还是可以将标记存在内存,只是该内存不是某个进程分配的内存而是公共内存如 Redis、Memcache。至于利用数据库、文件等做锁与单机的实现是一样的,只要保证标记能互斥就行。

2 我们需要怎样的分布式锁?

可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。

  • 这把锁要是一把可重入锁(避免死锁)
  • 这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)
  • 这把锁最好是一把公平锁(根据业务需求考虑要不要这条)

有高可用的获取锁和释放锁功能

获取锁和释放锁的性能要好

代码实现

  1. public interface IDistributedLock 
  2.     { 
  3.         ILockResult Lock(string resourceKey); 
  4.         ILockResult Lock(string resourceKey, TimeSpan expiryTime); 
  5.         ILockResult Lock(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime); 
  6.         ILockResult Lock(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken); 
  7.         Task<ILockResult> LockAsync(string resourceKey); 
  8.         Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime); 
  9.         Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime); 
  10.         Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken); 
  11.     } 
  12.  
  13.     public interface ILockResult : IDisposable 
  14.     { 
  15.         string LockId { get; } 
  16.         bool IsAcquired { get; } 
  17.         int ExtendCount { get; } 
  18.     } 
  1. class EndPoint:RedLock.RedisLockEndPoint 
  2.     { 
  3.         private readonly string _connectionString; 
  4.         public EndPoint(string connectionString) 
  5.         { 
  6.             _connectionString = connectionString; 
  7.             //139.196.40.252,password=xstudio,defaultDatabase=9 
  8.             var connection = connectionString.Split(','); 
  9.             var dict = new Dictionary<string, string>(); 
  10.             foreach (var item in connection
  11.             { 
  12.                 var keypar = item.Split('='); 
  13.                 if (keypar.Length>1) 
  14.                 { 
  15.                     dict[keypar[0]] = keypar[1]; 
  16.                 } 
  17.             } 
  18.             this.EndPoint = new System.Net.DnsEndPoint(connection[0], 6379); 
  19.             if (dict.TryGetValue("password"out string password)) 
  20.             { 
  21.                 this.Password = password
  22.             } 
  23.             if (dict.TryGetValue("defaultDatabase"out string defaultDatabase) && int.TryParse(defaultDatabase,out int database)) 
  24.             { 
  25.                 RedisDatabase = database
  26.             } 
  27.         } 
  28.     } 
  1. [Export(typeof(IDistributedLock))] 
  2.     class InnerLock : IDistributedLock 
  3.     { 
  4.         private static Lazy<RedLock.RedisLockFactory> _factory; 
  5.  
  6.         static InnerLock() 
  7.         { 
  8.             _factory = new Lazy<RedisLockFactory>(() => new RedisLockFactory(new EndPoint(ConfigurationManager.AppSettings["Redis"])), System.Threading.LazyThreadSafetyMode.ExecutionAndPublication); 
  9.         } 
  10.         public ILockResult Lock(string resourceKey) 
  11.         { 
  12.             return new LockResult(_factory.Value.Create(resourceKey, TimeSpan.FromDays(1))); 
  13.         } 
  14.  
  15.         public ILockResult Lock(string resourceKey, TimeSpan expiryTime) 
  16.         { 
  17.             return new LockResult(_factory.Value.Create(resourceKey, expiryTime)); 
  18.         } 
  19.  
  20.         public ILockResult Lock(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime) 
  21.         { 
  22.             return new LockResult(_factory.Value.Create(resourceKey, expiryTime, waitTime, retryTime)); 
  23.         } 
  24.  
  25.         public ILockResult Lock(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken) 
  26.         { 
  27.             return new LockResult(_factory.Value.Create(resourceKey, expiryTime, waitTime, retryTime, cancellationToken)); 
  28.         } 
  29.  
  30.         public async Task<ILockResult> LockAsync(string resourceKey) 
  31.         { 
  32.             var result = await _factory.Value.CreateAsync(resourceKey, TimeSpan.FromDays(1)); 
  33.             return new LockResult(result); 
  34.         } 
  35.  
  36.         public async Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime) 
  37.         { 
  38.             var result = await _factory.Value.CreateAsync(resourceKey, expiryTime); 
  39.             return new LockResult(result); 
  40.         } 
  41.  
  42.         public async Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime) 
  43.         { 
  44.             var result = await _factory.Value.CreateAsync(resourceKey, expiryTime, waitTime, retryTime); 
  45.             return new LockResult(result); 
  46.         } 
  47.  
  48.         public async Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken) 
  49.         { 
  50.             var result = await _factory.Value.CreateAsync(resourceKey, expiryTime, waitTime, retryTime, cancellationToken); 
  51.             return new LockResult(result); 
  52.         } 
  53.     } 
  54.  
  55.     class LockResult : ILockResult 
  56.     { 
  57.         private IRedisLock _lock; 
  58.         public LockResult(IRedisLock redisLock) 
  59.         { 
  60.             _lock = redisLock; 
  61.         } 
  62.  
  63.         public string LockId => _lock.LockId; 
  64.  
  65.         public bool IsAcquired => _lock.IsAcquired; 
  66.  
  67.         public int ExtendCount => _lock.ExtendCount; 
  68.  
  69.         public void Dispose() 
  70.         { 
  71.             _lock.Dispose(); 
  72.         } 
  73.     } 

 

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/228886.html<

(0)
运维的头像运维
上一篇2025-04-18 12:32
下一篇 2025-04-18 12:33

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注