基于 .NET 实现的分布式锁DistributedLock

分布式锁

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

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) { /* 写入数据 */ }
}

项目地址

https://github.com/madelson/DistributedLock