0

我们有一个 Windows 服务,每分钟运行一次石英作业,以处理 3 小时前提交的评论。该应用程序使用最新的 ServiceStack.Redis v3 库与另一台机器上的 Redis 2.8.12 实例进行交互。

提交新评论时,新评论的 ID 存储在 Redis 中的排序集中,我们使用NewReview.DateCreated.Ticks作为分数。当作业运行时,它会执行以下代码以获取要处理的评论列表:

using (var redisClient = RedisClientManager.GetClient())
{
    ...
    var cutOff = DateTime.Now.AddHours(-3);
    redisClient.GetRangeFromSortedSetByLowestScore("pending_reviews", 0L, cutOff);
    ...
}

通常,这工作正常,如果排序集中有 3 小时或更早之前的任何评论,它们的 ID 会被返回,并且作业会正常处理它们。但是,相同的确切代码会间歇性地导致以下异常发生:

ServiceStack.Redis.RedisResponseException: Unknown reply on multi-request: ...
at ServiceStack.Redis.RedisNativeClient.CreateResponseError(String error)
at ServiceStack.Redis.RedisNativeClient.ReadMultiData()
at ServiceStack.Redis.RedisNativeClient.SendExpectMultiData(Byte[][] cmdWithBinaryArgs)
at ServiceStack.Redis.RedisNativeClient.GetRangeByScore(Byte[] commandBytes, String setId, Int64 min, Int64 max, Nullable`1 skip, Nullable`1 take, Boolean withScores)
at ServiceStack.Redis.RedisNativeClient.ZRangeByScore(String setId, Int64 min, Int64 max, Nullable`1 skip, Nullable`1 take)
at ServiceStack.Redis.RedisClient.GetRangeFromSortedSetByLowestScore(String setId, Int64 fromScore, Int64 toScore, Nullable`1 skip, Nullable`1 take)
at ServiceStack.Redis.RedisClient.GetRangeFromSortedSetByLowestScore(String setId, Int64 fromScore, Int64 toScore)

我尝试下载并进入 ServiceStack 源代码,但在调试时问题从未发生过,否则我似乎无法重现它。RedisClientManager是一个单例PooledRedisClientManager ,据我所知,我正在正确地创建和处理客户端,并且我也没有使用事务或管道。

我的理解是,池化客户端管理器正在做一些棘手的连接共享工作,因为 Redis 实际上是单线程的。感觉它可能会从另一个连接或其他一些线程或连接共享问题返回错误的结果。

关于可能导致这种情况的任何想法?

4

1 回答 1

1

好的,我想通了。

后来在工作中,在检索到 id 后,它实际上是在使用事务。当我更仔细地查看事务代码时,我意识到多个客户端调用是在单个 QueueCommand 的上下文中进行的。尽管在初始作业调用期间没有发生错误,但在下一次作业运行时,它总是会收到错误。

因此,我只是将每个客户端调用分解为自己的 QueueCommand 和 Voila,错误就消失了。经验教训:使用事务/管道时要非常小心,每个 redis 客户端调用都在它自己的专用 QueueCommand 中!就我而言,它被隐藏在一个辅助方法中,我不得不挖掘一下才能找到它。

于 2015-06-11T01:21:20.280 回答