0

3 時間以上前に送信されたレビューを処理するために、Quartz ジョブを毎分実行する Windows サービスがあります。このアプリケーションは、最新の 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 が取得された後、実際にはトランザクションを使用していました。トランザクション コードを詳しく調べたところ、1 つの QueueCommand のコンテキスト内で複数のクライアント呼び出しが行われていることがわかりました。最初のジョブ呼び出しではエラーは発生しませんでしたが、次回ジョブを実行すると常にエラーが発生します。

したがって、各クライアントの呼び出しを独自の QueueCommand と Voila に分けただけで、エラーはなくなりました。教訓: トランザクション/パイプラインを使用する場合は、各 redis クライアント呼び出しが専用の QueueCommand にあることに十分注意してください! 私の場合、それはヘルパー メソッドに隠されていたため、それを見つけるために少し掘り下げる必要がありました。

于 2015-06-11T01:21:20.280 に答える