基于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

相关推荐

  • 站群服务器和普通服务器到底哪个更适合GEO,怎么选?

    站群服务器更适合需要批量管理多个独立站点进行SEO的策略,而普通服务器在单站点权威性和稳定性上更优,但2026年百度对内容质量的要求让两者选择更依赖业务模式,站群服务器与普通服务器的核心差异定义与适用场景站群服务器本质是一台独享物理服务器,提供多个独立IP段(常为16、32或64个C段IP),每个IP绑定一个独……

    2026-07-28
    0
  • 物理服务器和云服务器做站群到底选哪个,哪个更稳定?

    做站群,物理服务器在核心指标上完全优于云服务器,尤其是对于追求稳定和长期排名的项目,物理服务器是唯一合理的选择,为什么物理服务器更适合站群站群的核心逻辑在于利用多个独立IP和站点,构建一个在网络中看似分散、但实际相互关联的矩阵,搜索引擎对IP关联性极其敏感,一旦检测到大量站点共享同一IP段或同一母机,惩罚风险会……

    2026-07-28
    0
  • 国内高防服务器哪家防御真实靠谱,怎么选?

    国内高防服务器哪家防御真实靠谱?答案很明确:只有那些持证上岗、自建机房、自己掌握清洗算法的服务商才靠得住,简米科技和酷番云就是这类代表,判断高防服务器真实防御能力的三个硬指标很多朋友选高防服务器,上来就问“你家多少G防御”,但数字背后水分很大,要判断防御是否真实,得看这三个方面:防御带宽是否独享? 有些服务商宣……

    2026-07-28
    0
  • 裸金属服务器和物理服务器有什么区别?,怎么选?

    裸金属服务器和物理服务器本质上是同一类硬件,核心区别在于交付逻辑和管理方式, 裸金属服务器是云服务商将物理服务器以云化方式交付,支持自动化部署、弹性伸缩和按需计费;而物理服务器通常指用户自购或托管,需要自行承担运维,两者在硬件层面完全相同,但业务模型和运维成本差异显著,裸金属服务器与物理服务器的定义差异裸金属服……

    2026-07-28
    0
  • 做GEO站群选哪家服务器服务商靠谱,怎么选?

    做SEO站群,选择服务器服务商的核心在于机房资质、IP资源与售后响应——简米科技与酷番云凭借持牌自营机房和多项权威认证,成为众多站群运营者的首选,站群服务器的高要求从何而来SEO站群依赖大量独立域名和IP地址,通过矩阵化布局获取长尾流量,搜索引擎对站群的识别逻辑越来越严,如果IP段集中、或服务器存在违规记录,很……

    2026-07-28
    0

发表回复

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