Моя проблема очень похожа на это: Protocol errors, "no more data" errors, "Zero length response" errors while using servicestack.redis in a high volume scenarioНеожиданный ответ на сценарии большого объема с использованием ServiceStack.Redis
Я использую ServiceStack v3.9.54.0 в C# веб-приложений, работающих на IIS. Я видел ошибки в версиях Redis 2.8.17 и 3.0.501.
Ошибки я получал следующие:
ServiceStack.Redis.RedisResponseException: Unexpected reply: +PONG, sPort: 65197, LastCommand: GET EX:KEY:230
at ServiceStack.Redis.RedisNativeClient.CreateResponseError(String error)
at ServiceStack.Redis.RedisNativeClient.ParseSingleLine(String r)
at ServiceStack.Redis.RedisNativeClient.ReadData()
at ServiceStack.Redis.RedisNativeClient.SendExpectData(Byte[][] cmdWithBinaryArgs)
at ServiceStack.Redis.RedisNativeClient.GetBytes(String key)
at ServiceStack.Redis.RedisNativeClient.Get(String key)
И:
ServiceStack.Redis.RedisResponseException: Unknown reply on integer response: 43PONG, sPort: 59017, LastCommand: EXISTS EX:AnKey:Cmp6
at ServiceStack.Redis.RedisNativeClient.CreateResponseError(String error)
at ServiceStack.Redis.RedisNativeClient.ReadLong()
at ServiceStack.Redis.RedisNativeClient.SendExpectLong(Byte[][] cmdWithBinaryArgs)
at ServiceStack.Redis.RedisNativeClient.Exists(String key)
at Redis.Documentos.RedisBaseType.Exists(String key)
Первое, что я думал, что я делил соединение Redis через несколько потоков, но Я не вижу проблемы с моей одноэлементной реализацией PooledRedisClientManager
(Configs
- это статический класс, который хранит информацию о соединении):
public class RedisProvider
{
public PooledRedisClientManager Pool { get; set; }
private RedisProvider()
{
var srv = new List<string> { $"{Configs.Server}:{Configs.Port}" };
Pool = new PooledRedisClientManager(srv, srv, null,
Configs.Database, Configs.PoolSize, Configs.PoolTimeout);
}
public IRedisClient GetClient()
{
try
{
var connection = (RedisClient)Pool.GetClient();
return connection;
}
catch (TimeoutException)
{
return null;
}
}
private static RedisProvider _instance;
public static object _providerLock = new object();
public static RedisProvider Provider
{
get
{
lock (_providerLock)
{
if (_instance == null)
{
var instance = new RedisProvider();
_instance = instance;
return _instance;
}
else
{
return _instance;
}
}
}
}
}
Все клиенты получают через бассейн, следующим образом:
var redis = (RedisClient)RedisProvider.Provider.GetClient();
Я уверен, что redis
вар не разделяется на несколько потоков, и, насколько я могу видеть, этот код показывает надлежащая потокобезопасная реализация ...
Любая помощь будет высоко оценена.
Edit: В соответствии с некоторыми технологиями, которые я использую, у меня нет доступа к коду приложения Startup не может использовать using
блоки. Таким образом, я обернуть все клиенты так:
RedisClient redis;
try {
redis = (RedisClient)RedisProvider.Provider.GetClient();
// Do stuff
} finally {
redis.Dispose();
}
Спасибо, ответив на миф. Пожалуйста, взгляните на мое редактирование. Хотя я понимаю и согласен с вашими предложениями, могу ли я предположить, что реализация singleton как потокобезопасная, тогда как я помещаю клиент в блок finally try и гарантирую, что я не использую его для нескольких потоков? Есть ли еще одна возможная причина проблемы, помимо совместного использования клиента в нескольких потоках? – Dinei
@ DineiA.Rockenbach Эта ошибка говорит, что не получает ожидаемого ответа, который всегда был признаком того, что один и тот же экземпляр клиента использовался для отправки новой команды в другой поток. Я не буду рассказывать, где в вашей базе кода проблема, но если вы можете собрать небольшое автономное репо (например, на GitHub), показывающее ошибку, я могу сообщить вам, в чем проблема. – mythz
@mythz, где я должен использовать статический 'IRedisClientsManager'? Я вообще не использую рамки DI. Я создавал и удалял 'IRedisClientsManager' за вызов (с помощью' using' statement), а также 'IRedisClient'. Разве это не использовать singleton для менеджера клиентов? – Alisson