发布于2026-07-23 阅读(0)
扫一扫,手机访问
分布式系统里,最头疼的问题之一就是“抢资源”。举个简单的例子:多个服务节点同时往数据库同一行写数据,或者定时任务在多台机器上同时被触发,再或者多个实例同时更新缓存导致互相覆盖——这些场景下,并发冲突和数据一致性就成了绕不开的坎。要解决这类问题,最直接的手段就是分布式锁。
今天想聊的是一个在 .NET 生态里非常趁手的分布式锁库——DistributedLock。它设计得足够轻量,线程安全,且支持多种后端存储,几乎涵盖了主流中间件:Redis、SQL Server、PostgreSQL、MySQL、MongoDB,甚至还包括本地内存模式。切换后端只需要换一个提供程序,代码基本不用动,这才是真正意义上的“一次编写,到处运行”。
简单说,它是一个专门用来在分布式环境下实现锁机制的库。支持的后端列表在前面已经提到了,关键是它的 API 设计非常简洁,获取锁、释放锁的逻辑都能用 using 块优雅地完成,不必手动处理超时和异常。
在项目中引入对应的后端包即可。最经典的组合就是 Redis 和 SQL Server:
dotnet add package DistributedLock dotnet add package DistributedLock.Redis dotnet add package DistributedLock.SqlServer
当然,如果你只用其中一种,单独装对应的包就够了。
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 ha ve the lock */ }
}
核心就两步:创建锁对象,然后调用 TryAcquireAsync。拿到 handle 代表获锁成功,代码块执行完自动释放,不需要手动清理资源。
using Medallion.Threading.SqlServer;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace DistributedLockDemo
{
internal class Program
{
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 等)场景下,用 SQL Server 锁可以有效防止多节点重复执行——抢到锁的节点干活,其他节点乖乖等待或跳过。
在实际项目中,通常会通过依赖注入统一管理锁提供程序。先配好连接字符串:
{
"ConnectionStrings": {
"SqlServer": "Server=myServerAddress;Database=Locks;User Id=myUsername;Password=myPassword;",
"Redis": "localhost:6379"
}
}
然后在 DI 容器里注册 IDistributedLockProvider:
// Startup.cs 或 Program.cs
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("SqlServer");
services.AddSingleton(_ =>
new SqlDistributedSynchronizationProvider(connectionString));
services.AddTransient();
}
// SomeService.cs
public class SomeService
{
private readonly IDistributedLockProvider _lockProvider;
public SomeService(IDistributedLockProvider lockProvider)
{
_lockProvider = lockProvider;
}
public async Task InitializeUserAccountAsync(int id)
{
var @lock = _lockProvider.CreateLock($"UserAccount{id}");
await using (await @lock.AcquireAsync())
{
// 执行需要同步的操作
Console.WriteLine($"Initializing user account {id}...");
await Task.Delay(1000);
}
}
}
这样一来,所有需要锁的地方只要注入 IDistributedLockProvider 就行,业务代码完全不用关心后端是 Redis 还是 SQL Server。
DistributedLock 的 Redis 实现自带“看门狗”机制:它会定期检查锁是否仍由当前线程持有,并自动续期。避免因为业务处理时间超出锁的初始过期时间,导致锁被提前释放,出现并发问题。
此外,它还支持 RedLock 算法——在多个 Redis 节点上同时获取锁,至少需要 N/2+1 个节点成功才算获锁成功。这种方案适合对一致性要求极高的场景,比如金融交易或订单处理。
总的来说,DistributedLock 是一个开箱即用的分布式锁解决方案,API 干净,后端选择丰富。如果你正在构建 .NET 微服务或分布式系统,这个库值得放进工具箱。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8