分布式锁
DistributedLock 是一个 .NET 库,它基于各种底层技术,提供了健壮并且易于使用的分布式互斥锁、读写锁和信号量。DistributedLock包含基于各种技术的实现,包括 SqlServer, Redis, Postgres, MySql 等,您可以根据自己的场景不同的实现库。
• DistributedLock.SqlServer
• DistributedLock.Postgres
• DistributedLock.MySql
• DistributedLock.Oracle
• DistributedLock.Redis
• DistributedLock.Azure
• DistributedLock.ZooKeeper
• DistributedLock.FileSystem
• DistributedLock.WaitHandles
如何使用
在分布式场景中,使用 DistributedLock,跨多个应用程序/机器,控制对某个代码块的访问非常简单,如下
await using (await myDistributedLock.AcquireAsync())
{
// 获取锁, 执行代码
}
DistributedLock.SqlServer 示例
var @lock = new SqlDistributedLock("MyLockName", connectionString);
await using (await @lock.AcquireAsync())
{
// 获取锁, 执行代码
}
DistributedLock.Redis 示例
var connection = await ConnectionMultiplexer.ConnectAsync(connectionString);
// StackExchange.Redis
// 堆代码 duidaima.com
var @lock = new RedisDistributedLock("MyLockName", connection.GetDatabase());
await using (var handle = await @lock.TryAcquireAsync())
{
if (handle != null)
{
// 获取锁, 执行代码
}
}
Reader-writer locks 读写锁
DistributedLock 的读写锁实现和 .NET 中的 ReaderWriterLockSlim 类相似。读写锁允许多个读取者或一个写入者在任何给定时间持有该锁。对于在可以安全进行并发访问,但有的时候又需要锁定的资源,是非常有用的,读写锁可用于在分布式缓存中提供线程安全性。
class DistributedCache
{
// 使用 Sql Server 实现
private readonly SqlDistributedReaderWriterLock _cacheLock =
new SqlDistributedReaderWriterLock("DistributedCache", connectionString);
// 如果缓存中存在 key, 则返回,否则,生成新的 key,写入后并返回
public async Task<object> GetOrCreateAsync(string key, Func<string, object> valueFactory)
{
// 首先,用 Read 锁尝试获取缓存数据
await using (await this._cacheLock.AcquireReadLockAsync())
{
var cached = await this.GetValueOrDefaultNoLockAsync(key);
if (cached != null) { return cached; }
}
// 缓存不存在,用 Write 锁, 写入数据并返回
await using (await this._cacheLock.AcquireWriteLockAsync())
{
// double-check: 检查是否已经被其他的进程写入数据
var cached = await this.GetValueOrDefaultNoLockAsync(key);
if (cached != null) { return cached; }
// 写入数据并返回
var generated = valueFactory(key);
await this.SetValueAsync(key, generated);
return generated;
}
}
private async Task<object?> GetValueOrDefaultNoLockAsync(string key) { /* 读取数据 */ }
private async Task SetValueAsync(string key, object value) { /* 写入数据 */ }
}