Kon*_*kov 6 c# redis stackexchange.redis
在Redis连接丢失后,我正在寻找恢复[在多线程环境中]的参考实现.到目前为止无法找到任何有意义的东西.
安装程序:我有一个Azure辅助角色,它在多个线程中运行相同的代码(ThreadProc).最初,我有每个Redis操作之前的静态ConnectionMultiplexer和.GetDatabase().这根本没有通过压力测试(一旦负载从低到中增加,就会出现大量的"无法连接"错误).我把它改成了这个:
static readonly ConnectionMultiplexer _connection = ConnectionMultiplexer.Connect(...);
static readonly IDatabase _cache = _connection.GetDatabase();
void ThreadProc() // running in multiple threads
{
while (true)
{
// using _cache here
}
}
Run Code Online (Sandbox Code Playgroud)
即使在高负载(每个工作者角色实例1000个操作/秒)之前,这仍然很好,直到我得到"没有连接可用于服务此操作",并且事情无法恢复.
请告诉我可以从间歇性连接问题中恢复的正确/推荐代码.
Ken*_*ith 10
编辑2015-05-02:虽然StackExchange.Redis客户端的更高版本明确地应该在内部和自动地处理这种"丢失的连接" - >"重新连接"逻辑,但我的测试已经超出任何真正的怀疑,他们不会设法成功地将其拉下来,因此至少在繁忙的环境中仍然需要这种东西.我将下面的代码从我的缓存层中抽出一段时间,最终导致成千上万的连接失败错误.我把它放回去了,那些都消失了.
编辑2015-02-24:不再需要此方法.最新版本的StackExchange.Redis客户端正确处理断开连接 - 它们将自动重新连接,下面的解决方法只会干扰事情.为了历史目的将它保存在这里,但我的建议是忽略它.
以下是我的SimpleCacheRedis<T>包装器中的一些方法,它们展示了我如何处理问题:
public async Task<TValue> GetAsync(string key, Func<Task<TValue>> missingFunc)
{
key = GetKey(key);
var value = default(TValue);
try
{
var db = _connection.GetDatabase();
var str = await db.StringGetAsync(key);
if (!str.IsNullOrEmpty)
{
value = _jsonSerializer.Deserialize<TValue>(str);
}
}
catch (RedisConnectionException ex)
{
HandleRedisConnectionError(ex);
}
catch (Exception ex)
{
_logger.Error("Error retrieving item '" + key +
"' from Redis cache; falling back to missingFunc(). Error = " + ex);
}
if (value == default(TValue))
{
present = false;
value = await missingFunc();
await PerformAddAsync(key, value);
}
return value;
}
private void HandleRedisConnectionError(RedisConnectionException ex)
{
_logger.Error("Connection error with Redis cache; recreating connection for the next try, and falling back to missingFunc() for this one. Error = " + ex.Message);
Task.Run(async () =>
{
try
{
await CreateConnectionAsync();
}
catch (Exception genEx)
{
_logger.Error("Unable to recreate redis connection (sigh); bailing for now: " + genEx.Message);
}
});
}
private async Task CreateConnectionAsync()
{
if (_attemptingToConnect) return;
var sw = new StringWriter();
try
{
_attemptingToConnect = true;
_connection = await ConnectionMultiplexer.ConnectAsync(_redisCs, sw);
}
catch (Exception ex)
{
_logger.Error("Unable to connect to redis async: " + ex);
_logger.Debug("internal log: \r\n" + sw);
throw;
}
finally
{
_attemptingToConnect = false;
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,如果我发现由于a而无法连接到Redis RedisConnectionException,我会分离一个单独的async任务来重新创建共享连接.当然,这个电话可能会失败,但无论如何,电话会在那段时间内失败.一旦成功,任何新的调用都将使用新的(重新)创建的连接.就像我上面说的那样,有点无聊.
我的情况可能与你的情况有点不同,因为我不是将Redis用作永久存储,而是将其作为缓存.这意味着丢失的redis连接的唯一影响是我需要从DB而不是从缓存中检索结果.所以我可以稍稍松懈地对待某些事情.
| 归档时间: |
|
| 查看次数: |
8292 次 |
| 最近记录: |