如何优雅地实现.NET 分布式锁?DistributedLock 让你轻松搞定!

B站影视 电影资讯 2025-08-28 08:40 2

摘要:使用 Redis 分布式锁var RedisConnectionString = "localhost:6379,abortConnect=false";var LockName = "MyResourceLock";var connection = awai

在分布式系统中,经常会遇到多个实例同时访问同一份资源的情况,例如:

• 多个服务节点同时写入数据库同一行数据

• 定时任务在多个节点上同时运行,导致重复执行

• 多实例写缓存时出现数据覆盖问题

为了解决 并发冲突数据一致性问题,就需要用到分布式锁

今天给大家介绍一个 .NET 里非常好用的分布式锁库 —— Distributedlock

DistributedLock是一个轻量级、线程安全的 .NET 库,用来在分布式环境下实现锁的功能。支持多种后端存储,包括: • RedisSQL ServerPostgreSQLMySQLMongoDB内存模式(本地锁)

只需要更换存储提供程序,就能无缝地在不同的环境下使用。

安装 NuGet 包

在项目中引入需要的后端依赖,如:

dotnet add package DistributedLock --包含所有实现的元包
dotnet add package DistributedLock.Redis
dotnet add package DistributedLock.SqlServer

(Redis 和 SQL Server 是最常见的场景,也可以选择别的实现)

使用 Redis 分布式锁 var RedisConnectionString = "localhost:6379,abortConnect=false";
var LockName = "MyResourceLock";
var connection = await ConnectionMultiplexer.ConnectAsync(RedisConnectionString); // uses StackExchange.Redis
var @lock = new RedisDistributedLock(LockName, connection.GetDatabase);
await using (var handle = await @lock.TryAcquireAsync)
{
if (handle != null) { /* I have the lock */ }
}只要使用Acquire/AcquireAsync获取锁,代码块执行完毕后会自动释放,非常优雅。使用 SQL Server 分布式锁using Medallion.Threading.SqlServer;
using System;
using System.Threading;
using System.Threading.Tasks;

namespaceDistributedLockDemo
{
internalclassProgram
{
static async Task Main(string args)
{
var connectionString = "Server=myServerAddress;Database=Locks;User Id=myUsername;Password=myPassword;";
var lockName = "MyResourceLock";

// 创建分布式锁对象(不需要 using,因为它不实现 IDisposable)
var sqlLock = new SqlDistributedLock(lockName, connectionString);

// 尝试获取锁,返回的锁句柄(LockHandle)实现了 IDisposable
using (var lockHandle = sqlLock.TryAcquire(TimeSpan.FromSeconds(30)))
{
if (lockHandle != null) // 判断是否成功获取锁
{
// 持有锁,执行需要同步的代码
Console.WriteLine("Lock acquired, performing operation...");
// 模拟业务操作
await Task.Delay(1000); // 建议使用异步延迟而非 Thread.Sleep
}
else
{
Console.WriteLine("Failed to acquire lock within the timeout.");
}
} // 此处会自动释放锁(lockHandle.Dispose)
}
}
}

定时任务(Quartz、Hangfire 等)场景中,特别适合用来避免多节点重复执行。

appsettings.json

{
"ConnectionStrings": {
"SqlServer": "Server=myServerAddress;Database=Locks;User Id=myUsername;Password=myPassword;",
"Redis": "localhost:6379"
}
}

DistributedLock 支持依赖注入,适合在项目中使用。

// Startup.cs 或 Program.cs
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("SqlServer");
services.AddSingleton
new SqlDistributedSynchronizationProvider(connectionString));
services.AddTransient
}

// SomeService.cs
publicclassSomeService
{
privatereadonly IDistributedLockProvider _lockProvider;

public SomeService(IDistributedLockProvider lockProvider)
{
_lockProvider = lockProvider;
}

public async Task InitializeUserAccountAsync(int id)
{
var @lock = _lockProvider.CreateLock($"UserAccount{id}");
awaitusing (await @lock.AcquireAsync)
{
// 执行需要同步的操作
Console.WriteLine($"Initializing user account {id}...");
await Task.Delay(1000);
}
}
}

DistributedLock 的 Redis 实现内置了“看门狗”机制,定期检查锁是否仍由当前线程持有,并自动延长锁的过期时间,避免因业务处理时间过长导致锁失效。

DistributedLock 的 Redis 实现支持 RedLock 算法,通过在多个 Redis 节点上获取锁(至少 N/2+1 个节点)来确保高可靠性。RedLock 适合对一致性要求极高的场景。

DistributedLock是一个简单易用的分布式锁库,支持多种后端,特别适合用在微服务和分布式任务中。

如果你正在开发 分布式系统,强烈建议把它加入到你的工具库里。

·············· END ··············

来源:opendotnet

相关推荐