我在StackExchange.Redis中使用锁功能(LockTake和LockRelease),但需要保持基本上不断轮询。我让它从0到10毫秒的随机间隔睡觉然后再试一次。我打赌这基本上会阻碍连接。
我发现的文档建议(几乎)总是只使用1个ConnectionMultiplexer,它只能与Redis建立1个连接,但我也认为推荐是由于该连接的预期可用性。我最多可以说125个可能需要同时调用Redis的潜在线程。我可以使用连接池,但在这种情况下,池中应该有多少ConnectionMultiplexers?
修改
在下面的评论中与Marc讨论后,切换到Pub / Sub,但仍然使用连接池,这里是代码:
这是TakeLock方法
private Task TakeLockAsync(string key, string value)
{
TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();
var task = taskCompletionSource.Task;
var db = _dbFactory.GetDatabase();
//if we can get the lock, do it and return
bool gotLockTry1 = db.LockTake(key, value, _redisLockConfig.RedisLockMaxAgeTimeSpan);
if (gotLockTry1)
{
taskCompletionSource.SetResult(true);
return task;
}
// if we failed to get the lock,
// set up a subscriber to listen for lock release publish
var subscriber = db.Multiplexer.GetSubscriber();
Action<RedisChannel, RedisValue> handler = null;
handler = (redisChannel, redisValue) =>
{
bool gotLockTry3 = db.LockTake(key, value, _redisLockConfig.RedisLockMaxAgeTimeSpan);
if (gotLockTry3)
{
subscriber.Unsubscribe(_subscriptionChannelName, handler);
taskCompletionSource.SetResult(true);
}
};
subscriber.Subscribe(_subscriptionChannelName, handler);
// double check to make sure a release didn't come through while subscribing
bool gotLockTry2 = db.LockTake(key, value, _redisLockConfig.RedisLockMaxAgeTimeSpan);
if (gotLockTry2)
{
subscriber.Unsubscribe(_subscriptionChannelName, handler);
taskCompletionSource.SetResult(true);
return task;
}
return task;
}
和Dispose:
public void Dispose()
{
if (string.IsNullOrEmpty(_key) || string.IsNullOrEmpty(_value))
{
return;
}
var db = _dbFactory.GetDatabase();
//nested transactions not allowed, so can't call LockReleaseAsync
var trans = db.CreateTransaction();
// http://redis.io/topics/distlock
// remove the key only if it exists and the value matches key's value
trans.AddCondition(Condition.StringEqual(_key, _value));
trans.KeyDeleteAsync(_key);
trans.PublishAsync(_subscriptionChannelName, "something else here");
//runs only when execute called
trans.Execute();
}