.net - ServiceStack.Redis 对整数响应和零长度响应的未知回复
问题描述
我在生产中使用 ServiceStack 的 Redis 客户端时遇到了错误。
错误是 RedisClient.ContainsKey 的“整数响应上的未知回复:43OK”和RedisClient.Get的“零长度响应” 。
该应用程序使用 Redis Sentinel 和 PoolRedisClientManager。我有包装类来初始化 Redis 实例以及 Redis 操作:
public class RedisFactory : IRedisFactory
{
private RedisSentinel redisSentinel;
private IRedisClientsManager clientsManager;
public void Init()
{
RedisConfig.DefaultRetryTimeout = RETRY_TIMEOUT; //5000ms
RedisClientManagerConfig config = new RedisClientManagerConfig()
{
MaxReadPoolSize = MAX_POOL_SIZE, //40
MaxWritePoolSize = MAX_POOL_SIZE, //40
DefaultDb = DEFAUTL_DB
};
redisSentinel = new RedisSentinel(sentinelHosts, masterName: masterName)
{
RedisManagerFactory = (master, slaves) => new PooledRedisClientManager(master.ToList(), slaves.ToList(), config)
{
NamespacePrefix = NAMESPACE_PREFIX
},
OnFailover = manager => _log.Info($"Fail over at {DateTime.Now}"),
OnWorkerError = ex => _log.Error($"Sentinel worker error \n {ex}"),
OnSentinelMessageReceived = (channel, msg) => _log.Info($"Received '{channel}' on channel '{msg}' from Sentinel")
};
clientsManager = redisSentinel.Start();
}
public bool KeyExisted(string key)
{
Func<string, bool> keyExisted = delegate (string k)
{
using (var slave = clientsManager.GetReadonlyClient())
{
var existed = slave.ContainsKey(k);
return existed;
}
};
return Execute(nameof(keyExisted), key, keyExisted);
}
public T Get<T>(string key)
{
Func<string, T> get = delegate (string k)
{
using (var slave = clientsManager.GetReadonlyClient())
{
var value = slave.Get<T>(k);
return value;
}
};
return Execute(nameof(get), key, get);
}
private T Execute<T>(string operation, string key, Func<string, T> func)
{
int retry = 0;
while (true)
{
try
{
return func(key);
}
catch (Exception ex)
{
_log.Error($"Redis operation: {operation} error \n {ex}");
if (ex is RedisException)
{
if (retry >= 3)
{
throw;
}
retry++;
}
else
{
throw;
}
}
}
}
}
包装器在 AppHost 中注册为单例实例
public class AppHost : AppHostBase { public override void Configure(Container container){
var redisFactory = new RedisFactory
{
MaxPoolSize = AppSettings.Get("MaxPoolSize", 40),
MaxRetryAttempts = AppSettings.Get("MaxRetryAttempts", 3),
RetryTimeout = AppSettings.Get("RetryTimeout", 5000),
NameSpacePrefix = AppSettings.GetString("NameSpacePrefix"),
DefaultDB = 13
}; redisFactory.Init(); container.Register<IRedisFactory>(redisFactory);}}
Redis 工厂使用
public class MyService
{
private IRedisFactory cacheClient = HostContext.TryResolve<IRedisFactory>();
public object SomeMethod(string key) => cacheClient.Get<object>(key);
}
我有一个 RedisFactory::Execute 中的重试功能。我注意到第一次尝试会抛出如下异常,但第二次尝试会成功。
ServiceStack.Redis.RedisResponseException: Unknown reply on integer response: 43OK
at ServiceStack.Redis.RedisNativeClient.ReadLong()
at ServiceStack.Redis.RedisNativeClient.SendReceive[T](Byte[][] cmdWithBinaryArgs, Func`1 fn, Action`1 completePipelineFn, Boolean sendWithoutRead)
at ServiceStack.Redis.RedisNativeClient.SendExpectLong(Byte[][] cmdWithBinaryArgs)
at ServiceStack.Redis.RedisClient.ContainsKey(String key)
at RedisLibrary.RedisFactory.<KeyExisted>b__30_0(String k)
ServiceStack.Redis.RedisResponseException: Zero length response
at ServiceStack.Redis.RedisNativeClient.ParseSingleLine(String r)
at ServiceStack.Redis.RedisNativeClient.SendReceive[T](Byte[][] cmdWithBinaryArgs, Func`1 fn, Action`1 completePipelineFn, Boolean sendWithoutRead)
at ServiceStack.Redis.RedisNativeClient.SendExpectData(Byte[][] cmdWithBinaryArgs)
at ServiceStack.Redis.RedisClient.<>c__DisplayClass131_0`1.<Get>b__0(RedisClient r)
at ServiceStack.Redis.RedisClient.Exec[T](Func`2 action)
at RedisLibrary.RedisFactory.<Get>b__31_0[T](String k)
这只发生在 ContainsKey 和 Get 操作中。添加、删除或替换仍然正常工作。
需要注意的重要一点是,自从我们更改 Redis 服务器配置后,在生产中发现了这些错误,如下所示:
// Redis 服务器配置更改
Fail over – timeout redis -cluster 5000 ->15000
Tcp-keepalive 0 ->300
Repl -blacklog-size 10mb -> 50mb
我尝试在测试环境中使用与生产环境相同的 Redis 配置重现该问题,但失败了。我也一直在寻找其他类似的问题,例如在ServiceStack.Redis Client Unknown reply on integer response: 430k但没有任何帮助。
谁能帮我指出我的实现或 Redis 配置有什么问题?感谢你的帮助。
解决方案
推荐阅读
- linux - 添加中断时,UIO 设备不再打开
- git - git实践练习(合并两个分支并处理冲突)
- c++ - 如何在不位于其命名空间中的情况下覆盖类的 << 运算符?
- javascript - 无法从 nodejs 访问 Azure SQL 服务器
- django - 创建具有与其他字段中的整数一样多的字段的 django 模型
- nginx - 在 NGINX 中测试负载均衡
- mysql - 不导入 CSV
- php - 如何让返回按钮在父页面上工作,而不是在 iframe 中
- php - 使用带有 floccus 的 sabre/dav 服务器
- twilio - 如何修复 Twilio 称之为我的 webhook 的 403 错误?