13

私はredisを使用して、ハッシュごとに最大10万レコードのハッシュを保存しています。指定されたハッシュ内のレコードのフィルタリング(ファセット)を実装したいと思います。ハッシュエントリはn個のフィルターに属することができることに注意してください。

これこれを読んだ後、私はすべきであるように見えます:

  1. フィルタごとにソートされたSETを実装します。SET内の値は、HASH内のキーに対応します。
  2. 指定されたフィルターSETからHASHキーを取得します。
  3. SETからHASHキーを取得したら、HASHから対応するエントリをフェッチします。これにより、フィルターに属するすべてのエントリが得られます。

まず、上記のアプローチは大まかに正しいですか?

アプローチがOKであると仮定すると、私が見逃しているビットは、HASHエントリを取得するための最も効率的な実装は何ですか?HASHキーを取得したら、PIPELINEを使用して、各HASHキーを通過する複数のHGETALLコマンドをキューに入れる必要があると考えていますか?より良いアプローチはありますか?

PIPELINEの使用に関する私の懸念は、コマンドの処理中に他のすべてのクライアントをブロックすると信じていることです。フィルタリングされた結果を1ページあたり500件の結果でページングします。複数のブラウザベースのクライアントがフィルタリングを実行している場合、SETとHASHを設定するバックエンドプロセスは言うまでもなく、PIPELINEがブロックすると、多くの競合が発生する可能性があるように思われます。誰かがこれについての見解を提供できますか?

それが役立つ場合は、2.2.4 redis、Webクライアント用のpredis、バックエンド用のservicestackを使用しています。

ありがとう、ポール

4

3 に答える 3

5

個々の操作はブロックされますが、長時間実行されるべきではないため、問題ではありません。実際に必要な情報よりも多くの情報を取得しているようです。HGETALLは、500個しか必要ない場合に100,000個のアイテムを返します。

500のHGET操作の送信は機能する可能性があります(セットがハッシュとキーの両方を格納していると仮定)が、ハッシュの使用は時期尚早の最適化のケースである可能性があります-通常のキーとMGETを使用する方が良い場合があります。

于 2011-04-18T05:35:38.747 に答える
5

Redisはロックフリーのノンブロッキング非同期サーバーであるため、パイプラインを使用するときに追加の競合は発生しません。Redisは、各操作を受信するとすぐに喜んで処理するので、実際には複数のパイプライン操作を処理できます。本質的に、redis-serverは、操作がパイプライン化されているかどうかを実際には気にせず、受信時に各操作を処理するだけです。

パイプライン化の利点は、次の操作を送信する前に各操作のredis-serverからの応答を待つ代わりに、クライアントが1回の書き込みですべての操作を一度にポンピングしてからすべての応答を読み戻すことができるクライアントの待ち時間を短縮することです。シングルリード。

この動作の例は、私のRedis mini StackOverflowクローンにあります。クリックするたびに呼び出しがToQuestionResults()行われ、操作がパイプライン化されているため、すべての操作が1ソケット書き込み呼び出しで送信され、結果が1ソケットブロッキング読み取りで読み取られます。これは、ブロッキングではなく効率的です。呼び出しごとに読み取る:

https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/RedisStackOverflow/RedisStackOverflow.ServiceInterface/IRepository.cs#L180

PIPELINEの使用に関する私の懸念は、コマンドの処理中に他のすべてのクライアントをブロックすると信じていることです。

これは有効な懸念事項ではなく、パイプラインが他のクライアントコマンドの処理をブロックしない場合に、Redisが最も効率的に機能していると仮定して、Redisがここでどのように機能するかを考えすぎません。概念的には、redis-serverが各コマンド(パイプライン化されているかどうかに関係なく)をFIFO順に処理すると考えることができます(つまり、パイプライン全体の待機/読み取りに時間を浪費することはありません)。

あなたは、RedisサーバーがEXEC(つまり、EOFトランザクション)を読み取るとすぐにすべての操作が一度に実行される、MULTI / EXEC(つまり、Redisトランザクション)に近いものを説明しています。これも問題ではありません。redis-serverは、トランザクション全体を受信するのを待つ時間を無駄にすることはありません。最終的なEXECを受信するまで、部分的なコマンドセットを一時キューに入れて、一度に処理します。

これは、redisがコマンドを受信するとすぐに、各コマンドを一度に1つずつ処理することにより、原子性を実現する方法です。他のスレッドがないため、スレッドコンテキストの切り替え、ロック、マルチスレッドの問題はありません。基本的に、各コマンドを非常に高速に処理することで同時実行性を実現します。

したがって、この場合はパイプラインを使用します。これは常に勝利であるため、パイプラインを使用するコマンドが増えるほどです(ブロッキング読み取り数を減らすため)。

于 2011-05-05T02:34:29.190 に答える
2

パイプラインが何をするのか誤解していると思います。すべてのコマンドが送信されている間はブロックされません。コマンドをバッファリングし、最後に一度に実行するだけなので、1つのコマンドであるかのように実行されます。ブロッキングは発生していません。multi同じことがredis /にも当てはまりますexec。redisでのブロック/ロックに最も近いのはwatch、を使用した楽観的ロックです。これは、execを呼び出してからredisキーが書き込まれている場合に失敗しますwatch

hgetパイプラインブロック内で500回呼び出すよりもさらに効率的なのは、検索している500個のハッシュキーの配列がhmget('hash-key',*keys)どこにあるかを呼び出すだけです。keysこれにより、redisへの単一の呼び出しが発生します。これはパイプライン化された場合と同じですが、rubyでループしていないため、実行が高速になります。

于 2011-06-14T22:32:18.813 に答える