An implementation of the Redlock distributed lock algorithm in C#.
Makes use of the excellent StackExchange.Redis library.
Distributed locks are useful for ensuring only one process is using a particular resource at any given time (even if the processes are running on different machines).
RedLock.net is available using NuGet - search for RedLock.net.
Note: RedLock 2.2.0+ requires StackExchange.Redis 2.0+ - if you need to use StackExchange.Redis 1.x please continue to use RedLock.net 2.1.0.
Construct a RedLockFactory
, passing in a set of Redis endpoints. Each endpoint passed to the constructor should be independent (i.e. not replicated masters/slaves). See below for more information on using RedLock.net with replicated instances.
You should keep hold of the RedLockFactory
and reuse it in your application. Each instance maintains its own connections with the configured Redis instances. Remember to dispose it when your app shuts down.
With the factory, create a RedLock
in a using block, making sure to check that that the lock IsAcquired
inside the block before performing any actions. A lock is acquired if RedLock
can set a lock key in more than half of the redis instances.
Internally RedLock
has a timer that automatically tries to keep the redis lock key alive. In the worst case of a process crashing without releasing the lock, it will automatically be expired by redis after the specified expiry time.
var endPoints = new List<RedLockEndPoint>
{
new DnsEndPoint("redis1", 6379),
new DnsEndPoint("redis2", 6379),
new DnsEndPoint("redis3", 6379)
};
var redlockFactory = RedLockFactory.Create(endPoints);
var existingConnectionMultiplexer1 = ConnectionMultiplexer.Connect("redis1:6379");
var existingConnectionMultiplexer2 = ConnectionMultiplexer.Connect("redis2:6379");
var existingConnectionMultiplexer3 = ConnectionMultiplexer.Connect("redis3:6379");
var multiplexers = new List<RedLockMultiplexer>
{
existingConnectionMultiplexer1,
existingConnectionMultiplexer2,
existingConnectionMultiplexer3
};
var redlockFactory = RedLockFactory.Create(multiplexers);
If you require more detailed configuration for the redis instances you are connecting to (e.g. password, SSL, connection timeout, redis database, key format), you can use the RedLockEndPoint
or RedLockMultiplexer
classes.
var resource = "the-thing-we-are-locking-on";
var expiry = TimeSpan.FromSeconds(30);
await using (var redLock = await redlockFactory.CreateLockAsync(resource, expiry)) // there are also non async Create() methods
{
// make sure we got the lock
if (redLock.IsAcquired)
{
// do stuff
}
}
// the lock is automatically released at the end of the using block
retry
seconds until the lock is available, or wait
seconds have passed):var resource = "the-thing-we-are-locking-on";
var expiry = TimeSpan.FromSeconds(30);
var wait = TimeSpan.FromSeconds(10);
var retry = TimeSpan.FromSeconds(1);
// blocks until acquired or 'wait' timeout
await using (var redLock = await redlockFactory.CreateLockAsync(resource, expiry, wait, retry)) // there are also non async Create() methods
{
// make sure we got the lock
if (redLock.IsAcquired)
{
// do stuff
}
}
// the lock is automatically released at the end of the using block
You can also pass a CancellationToken
to the blocking CreateLock
methods if you want to be able to cancel the blocking wait.
redlockFactory.Dispose();
If you are connecting to Azure Redis Cache, use the following configuration settings:
var azureEndPoint = new RedLockEndPoint
{
EndPoint = new DnsEndPoint("YOUR_CACHE.redis.cache.windows.net", 6380),
Password = "YOUR_ACCESS_KEY",
Ssl = true
};
The Redlock algorithm is designed to be used with multiple independent Redis instances (see http://redis.io/topics/distlock#why-failover-based-implementations-are-not-enough for more detail on why this is the case).
However, since RedLock.net 1.7.3 there is support for replicated master/slave instances. To do so, configure RedLock using the RedLockEndPoint
class, providing the replicated redis instances with the EndPoints
property.Each RedLockEndPoint
that is passed to the RedLockFactory
constructor will be treated as a single unit as far as the RedLock algorithm is concerned.
If you have multiple independent sets of replicated Redis instances, you can use those with RedLock.net in the same way you would use multiple non-replicated independent Redis instances:
var redlockEndPoints = new List<RedLockEndPoint>
{
new RedLockEndPoint
{
EndPoints =
{
new DnsEndPoint("replicatedset1-server1", 6379),
new DnsEndPoint("replicatedset1-server2", 6379),
new DnsEndPoint("replicatedset1-server3", 6379)
}
},
new RedLockEndPoint
{
EndPoints =
{
new DnsEndPoint("replicatedset2-server1", 6379),
new DnsEndPoint("replicatedset2-server2", 6379),
new DnsEndPoint("replicatedset2-server3", 6379)
}
},
new RedLockEndPoint
{
EndPoint = new DnsEndPoint("independent-server", 6379)
}
};
var redlockFactory = RedLockFactory.Create(redlockEndPoints);
or, if you have existing redis connections:
var existingConnectionMultiplexer1 = ConnectionMultiplexer.Connect("replicatedset1-server1:6379,replicatedset1-server2:6379,replicatedset1-server3:6379");
var existingConnectionMultiplexer2 = ConnectionMultiplexer.Connect("replicatedset2-server1:6379,replicatedset2-server2:6379,replicatedset2-server3:6379");
var existingConnectionMultiplexer3 = ConnectionMultiplexer.Connect("independent-server:6379");
var multiplexers = new List<RedLockMultiplexer>
{
existingConnectionMultiplexer1,
existingConnectionMultiplexer2,
existingConnectionMultiplexer3
};
var redlockFactory = RedLockFactory.Create(multiplexers);
Using replicated instances is not the suggested way to use RedLock, however if your environment is configured that way and you are aware of the potential risks it is possible to configure.
Since all operations that RedLock.net performs in Redis (Lock, Extend and Unlock) require writing, they can only be performed on the master. If your replicated Redis instances are not configured to automatically promote one of the slaves to master in the case of the master becoming inaccessible, the replicated instances will be unable to be used by RedLock until there is manual intervention to reinstate a master.
There is the potential for a master to become inaccessible after acquiring a lock, but before that lock is propogated to the replicated slaves. If one of the slaves is then promoted to master, the lock will not have been acquired within Redis, and there is the possibility that another process could also acquire the lock, resulting in two processes running within the lock section at the same time. Running with multiple independent instances (or multiple independent replicated instances) should mitigate this somewhat, as the RedLock quorum is still required before another process can acquire the lock.
There is the potential for a master to become inaccessible after releasing a lock, but before the lock removal is propogated to the replicated slaves. This will result in the lock continuing to be held until the Redis key expires after the specified expiry time.
Redlock在一些不同进程必须操作共享资源的环境中特别适用。 实现DLM(Distributed Lock Manager)官方链接 一、安装 Install-Package RedLock.net -Version 2.0.0 二、使用 通过一组Redis终端构造一个RedLockFactory. 在程序中重复使用RedLockFactory。每一个实例维持它自己配置中的连接。当你的应用停用时
⒈简介 RedLock 分布式锁算法由 Redis 的作者提出,大部分语言都有对应的实现,查看,RedLock.net 是 RedLock 分布式锁算法的 .NET 版实现,用来解决分布式下的并发问题。 RedLock 的思想是使用多台 Redis Master ,节点之间完全独立,节点间不需要进行数据同步,因为 Master-Slave 架构一旦 Master 发生故障时数据没有复制到
Redis 作者为了解决因为主备切换、脑裂导致 Redis 单集群分布式锁不安全的问题,提出了 redlock 算法,下面是针对 文章 的翻译和一些自我理解。 一、安全性和可用性保证 用三个属性来建模我们的设计方案,在我看来,这是有效使用分布式锁的最小保证: 安全性:互斥性。在任意时刻,只有一个客户端可以持有锁; 可用性1:无死锁。即时获取锁的客户端崩溃或者发生网络分区,最终也是可以获取锁资源的;
在多线程共享临界资源的场景下,分布式锁是一种非常重要的组件。 许多库使用不同的方式使用redis实现一个分布式锁管理。 其中有一部分简单的实现方式可靠性不足,可以通过一些简单的修改提高其可靠性。 这篇文章介绍了一种指导性的redis分布式锁算法RedLock,RedLock比起单实例的实现方式更加安全。 在介绍RedLock算法之前,我们列出了一些已经实现了分布式锁的类库供大家参考。 Redloc
获取锁: SET resource_name my_random_value NX PX 30000 释放锁: if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end RedLock.net 集成: 创建 .NETCore API 项目 NuGet 安