前言:
此时你们对“apache分布式全局锁”都比较关切,姐妹们都想要分析一些“apache分布式全局锁”的相关内容。那么小编在网上汇集了一些有关“apache分布式全局锁””的相关内容,希望兄弟们能喜欢,姐妹们一起来了解一下吧!前言
什么是锁?什么是分布式锁?它们之间有什么样的关系?
什么是锁
加锁(lock)是2018年公布的计算机科学技术名词,是指将控制变量置位,控制共享资源不能被其他线程访问。通过加锁,可以确保在同一时刻只有一个线程在访问被锁住的代码片段,我们在单机部署时可使用最简单的加锁完成资源的独享,如:
public class Program{ private static readonly object Obj = new { }; public static void Main() { lock (obj) { //同一时刻只有一个线程可以访问 } }}什么是分布式锁
但随着业务发展的需要,原单体单机部署的系统被部署成分布式集群系统后,原来的并发控制策略失效,为了解决这个问题就需要引入分布式锁,那分布式锁应该具备哪些条件?
原子性:在分布式环境下,一个方法在同一个时间点只能被一台机器下的一个线程所执行,防止数据资源的并发访问,避免数据不一致情况高可用:具备自动失效机制,防止死锁,获取锁后如果出现错误,并且无法释放锁,则使用租约一段时间后自动释放锁阻塞性:具备非阻塞锁特性(没有获取到锁时直接返回获取锁失败,不会长时间因等待锁导致阻塞)高性能:高性能的获取锁与释放锁可重入性:具备可重入特性,在同一线程外层函数获得锁之后,内层方法会自动获取锁实现
分布式锁是特定于实现的,目前MasaFramework提供了两个实现,分别是 Local 、 Medallion ,下面会介绍如何配置并使用它们
本地锁MedallionAzureFileSystemMySqlOraclePostgreSqlRedisSqlServerWaitHandlesZooKeeper本地锁
是基于 SemaphoreSlim 实现的,它不是真正的分布式锁,我们建议你在开发和测试环境中使用它,不需要联网也不会与其他人冲突
Medallion
是基于 DistributedLock 实现的分布式锁,它提供了很多种技术的实现,包括 Microsoft SQL Server 、 Postgresql 、 MySQL 或 MariaDB 、 Oracle 、 Redis 、 Azure blob 、 Apache ZooKeeper 、 锁文件 、 操作系统全局WaitHandles(Windows) ,我们只需要任选一种实现即可,目前 Medallion 提供的分布式锁并不支持可重入性,点击了解 原因
快速入门安装 .NET 6.0
以 本地锁 单应用锁为例:
新建ASP.NET Core 空项目 Assignment.DistributedLock.Local ,并安装 Masa.Contrib.Data.DistributedLock.Local
dotnet new web -o Assignment.DistributedLock.Localcd Assignment.DistributedLock.Localdotnet add package Masa.Contrib.Data.DistributedLock.Local --version 0.6.0-preview.10注册锁,修改类 Program
builder.Services.AddLocalDistributedLock();//注册本地锁如何使用锁?修改类 Program
app.MapGet("lock", (IDistributedLock distributedLock) =>{ using var @lock = distributedLock.TryGet("test");//获取锁 if (@lock != null) { //todo: 获取锁成功 return "success"; } return "获取超时";});
通过DI获取 IDistributedLock ,并通过 TryGet 方法获取锁,如果获取锁失败,则返回null,如果返回到的对象不为null,则表明获取锁成功,最后在获取锁成功后写自己的业务代码即可
TryGet 方法拥有以下参数
keytimeout
TryGetAsync 方法除了拥有 TryGet 的所有参数之外,还拥有以下参数
cancellationToken : 取消令牌可在触发后取消操作
如果你选择使用 Medallion ,只需要选择一种技术实现,并根据 Readme 注册锁即可,在使用锁上是没有区别的
如何扩展其它的分布式锁新建类库 Masa.Contrib.Data.DistributedLock.{分布式锁名} ,并添加引用 Masa.BuildingBlocks.Data.csproj新建分布式锁实现类 DefaultDistributedLock ,并实现IDistributedLock
public class DefaultDistributedLock : IDistributedLock{ public IDisposable? TryGet(string key, TimeSpan timeout = default) { // 获取锁失败则返回null,当资源被释放时,主动释放锁, 无需人为手动释放 throw new NotImplementedException(); } public Task<IAsyncDisposable?> TryGetAsync(string key, TimeSpan timeout = default, CancellationToken cancellationToken = default) { //获取锁失败则返回null,当资源被释放时,主动释放锁, 无需人为手动释放 throw new NotImplementedException(); }}新建类 ServiceCollectionExtensions ,注册分布式锁到服务集合
public static class ServiceCollectionExtensions{ public static IServiceCollection AddDistributedLock(this IServiceCollection services, Action<MedallionBuilder> builder) { services.TryAddSingleton<IDistributedLock, DefaultDistributedLock>(); return services; }}小知识
为什么 TryGet 、 TryGetAsync 方法的返回类型分别是 IDisposable 、 IAsyncDisposable ?
我们希望使用锁可以足够的简单,在使用完锁之后可以自动释放锁,而不是必须手动释放,当返回类型为 IDisposable 、 IAsyncDisposable 时,使用完毕后会触发 Dispose 或 DisposeAsync ,这样一来就可以使得开发者可以忽略释放锁的逻辑
以本地锁为例:
public class DefaultLocalDistributedLock : IDistributedLock{ private readonly MemoryCache<string, SemaphoreSlim> _localObjects = new(); public IDisposable? TryGet(string key, TimeSpan timeout = default) { var semaphore = GetSemaphoreSlim(key); if (!semaphore.Wait(timeout)) { return null; } return new DisposeAction(semaphore); } //todo: 以下省略 TryGetAsync 方法 private SemaphoreSlim GetSemaphoreSlim(string key) { ArgumentNullOrWhiteSpaceException.ThrowIfNullOrWhiteSpace(key); return _localObjects.GetOrAdd(key, _ => new SemaphoreSlim(1, 1)); }}internal class DisposeAction : IDisposable, IAsyncDisposable{ private readonly SemaphoreSlim _semaphore; public DisposeAction(SemaphoreSlim semaphore) => _semaphore = semaphore; public ValueTask DisposeAsync() { _semaphore.Release(); return ValueTask.CompletedTask; } public void Dispose() => _semaphore.Release();}
标签: #apache分布式全局锁