原文:
目录
系统分布式锁的用法
公司框架新增功能分布式锁:
锁的性能之王: 缓存 > Zookeeper >= 数据库
锁的实现
实现原理:核心采用StackExchange.Redis的LockTake方法实现。
支持同步获取锁,或者等待直到超时获取锁。////// 分布式锁,提供全局分布式锁支持,以resource redis为基础 /// 这个锁只能通过RpcContext来获取,通过自己手动释放 /// public sealed class DistributedLock { private static readonly TimeSpan DefaultAbandonmentCheckFrequency = TimeSpan.FromSeconds(2); public readonly string lockName; private readonly string lockValue; private readonly int checkTimeSpan = 50; //ms private readonly int autoDelete; private DistributedLock() { } ////// /// /// /// 自动删除,ms,默认 60s /// 如果不能获取锁,重复检查间隔:默认 50ms internal DistributedLock(string lockName, int autoDelete = 60000,int checkTimeSpan = 50) { // note that just Global\ is not a valid name if (string.IsNullOrEmpty(lockName)) throw new ArgumentNullException("lockName不能为空"); if (null == ResourceCache.Instance) throw new Exception(@"ResourceCache 没有配置或无法连接"); this.checkTimeSpan = Math.Max(checkTimeSpan,1); this.autoDelete = Math.Max(autoDelete,1); this.lockName = lockName; this.lockValue = lockName; } ////// 获取锁 /// /// 超时为null,则尝试一次即返回 ///获取锁成功? internal bool Acquire(TimeSpan? timeout = null) { bool bLock = false; var dtStart = DateTime.Now.Ticks; while (!bLock) { bLock = TryAcquireOnce(); if (timeout == null) { break; } if (!bLock) { Thread.Sleep(this.checkTimeSpan); } var ts = new TimeSpan(DateTime.Now.Ticks - dtStart); if (ts >= timeout) { break; } } return bLock; } //此处采用框架上下文管理分布式事务锁的释放,代码略。 //public void Dispose() //{ // LockManager.ReleaseLock(this); //} internal void Release() { try { var bRtn = ResourceCache.Instance.LockRelease(this.lockName, this.lockValue); Trace.WriteLine($"释放锁 {this.lockName}:{bRtn}"); } catch (Exception e) { LogTextWriter.Write($"释放锁失败,系统自动超时释放:{this.lockName}"); } } ////// 释放锁 /// public void ReleaseLock() { LockManager.ReleaseLock(this); } private bool TryAcquireOnce() { try { Trace.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:TryAcquireOnce"); var @lock = ResourceCache.Instance.LockTake(this.lockName, this.lockValue, new TimeSpan(0, 0, 0, 0, this.autoDelete)); return @lock; } catch (Exception e) { return false; } } }
锁的使用
在当前上下文中获取一个分布式锁,第一个获取锁的将执行依赖当前key(一般为业务主键)的完整业务流程(包括多个微服务之间的调用和数据库的访问;
后来者将无法获取锁,根据返回的结果来判断是否进入流程,如果返回的锁为null将不能执行下面的流程,要么重试等待锁释放,要么返回错误.
锁的调用一般流程:
var qtLock=TryGetLock(lockKey); if(qtLock==null) { //提示不能同时执行操作 return; } else { //进行业务流程 } //最后别忘了 qtLock.ReleaseLock();
API内的范例:
code = StatusCode.OK; //传入超时时间,可以一直等待到超时过期 var lockSaveReceipt = this.Context.TryGetLock($"{nameof(SaveReceipt)}.{valueArgs.ReceiptArgs.ReceiptId}"); if (lockSaveReceipt == null) { code = PublicErrorCode.SaveReceiptByUsed.ToCode(); return null; } try{ //todo 业务操作1 //todo 业务操作2 //... } finally { lockSaveReceipt.ReleaseLock(); }
在此我向大家推荐一个微服务架构学习交流群。交流学习群号:864759589 里面会分享一些资深架构师录制的视频录像:高并发、高性能、分布式、微服务架构的原理,分布式架构等这些成为架构师必备的知识体系。
引用链接
- 本节源码:
posted on 2019-01-18 10:32 阅读( ...) 评论( ...)