前言
什么是锁?什么是分布式锁?它们之间有什么样的联络?
什么是锁
加锁(lock)是2018年发布的计算机科学技能名词,是指将控制变量置位,控制共享资源不能被其他线程拜访。通过加锁,能够确保在同一时刻只要一个线程在拜访被锁住的代码片段,咱们在单机布置时可运用最简略的加锁完成资源的独享,如:
public class Program
{
private static readonly object Obj = new { };
public static void Main()
{
lock (obj)
{
//同一时刻只要一个线程能够拜访
}
}
}
什么是分布式锁
但随着业务发展的需要,原单体单机布置的体系被布置成分布式集群体系后,原来的并发控制战略失效,为了处理这个问题就需要引进分布式锁,那分布式锁应该具有哪些条件?
- 原子性:在分布式环境下,一个办法在同一个时刻点只能被一台机器下的一个线程所执行,避免数据资源的并发拜访,避免数据不一致状况
- 高可用:具有自动失效机制,避免死锁,获取锁后假如出现错误,而且无法开释锁,则运用租约一段时刻后自动开释锁
- 堵塞性:具有非堵塞锁特性(没有获取到锁时直接回来获取锁失利,不会长期因等候锁导致堵塞)
- 高性能:高性能的获取锁与开释锁
- 可重入性:具有可重入特性,在同一线程外层函数取得锁之后,内层办法会自动获取锁
完成
分布式锁是特定于完成的,现在MasaFramework供给了两个完成,分别是Local
、Medallion
,下面会介绍怎么配置并运用它们
- 本地锁
-
Medallion
- Azure
- FileSystem
- MySql
- Oracle
- PostgreSql
- Redis
- SqlServer
- WaitHandles
- ZooKeeper
本地锁
是基于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.Local
cd Assignment.DistributedLock.Local
dotnet 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
办法具有以下参数
-
key
(string, 有必要): 锁的仅有名称,可通过key来拜访不同的资源,执行不同的业务 -
timeout
(TimeSpan): 等候获取锁的最大超时时刻. 默认值为: TimeSpan.Zero(代表假如锁已经被另一个应用程序具有, 它不会等候.)
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();
}
本章源码
Assignment09
github.com/zhenlei520/…
开源地址
MASA.Framework:github.com/masastack/M…
假如你对咱们的 MASA Framework 感兴趣,无论是代码贡献、运用、提 Issue,欢迎联络咱们
- WeChat:MasaStackTechOps
- QQ:7424099