sql >> データベース >  >> NoSQL >> Redis

BookSleeve / RedisでPubSubはどのように機能しますか?

    1:例にはチャネルが1つだけあります(Test );チャネルは、特定のパブ/サブ交換に使用される名前です。ただし、2つの接続を使用する必要があります redisAPIの動作の詳細によるものです。 いずれかの接続 サブスクリプションは、以下を除いて他に何もできません:

    • メッセージを聞く
    • 独自のサブスクリプションを管理する(subscribepsubscribeunsubscribepunsubscribe

    しかし、私はこれを理解していません:

    private static Dictionary<string, RedisSubscriberConnection>
    

    自分に固有の何かに対応しているのでない限り、複数のサブスクライバー接続は必要ありません。 1つのサブスクライバー接続で、任意の数のサブスクリプションを処理できます。 client listの簡単なチェック 私のサーバーの1つで、(執筆時点で)23,002のサブスクリプションとの接続が1つあります。これはおそらく減らすことができますが、それは機能します。

    2:パターンサブスクリプションはワイルドカードをサポートします。したがって、/topic/1にサブスクライブするのではなく 、/topic/2/ など、/topic/*を購読できます 。 実際のの名前 publishが使用するチャネル コールバック署名の一部として受信者に提供されます。

    どちらも動作します。 publishのパフォーマンスに注意する必要があります 一意のサブスクリプションの総数の影響を受けますが、率直に言って、subscribeを使用して数万のサブスクライブされたチャネルがある場合でも、それはまだばかげて高速です(0msのように)。 psubscribeではなく 。

    しかし、publishから

    時間計算量:O(N + M)ここで、Nは受信チャネルにサブスクライブされたクライアントの数であり、Mは(任意のクライアントによって)サブスクライブされたパターンの総数です。

    pub/subのredisドキュメントを読むことをお勧めします。

    質問をフォローするために編集します:

    a)アイテムを受信するときに同じ発行元からのアイテムの送信順序が維持されることを保証したい場合は、同期的に(ResultまたはWait()を使用して)「発行」する必要があると思います。

    それはまったく違いはありません。 Resultに言及しているので / Wait() 、BookSleeveについて話していると思います。この場合、マルチプレクサはすでにコマンドの順序を保持しています。 Redis自体はシングルスレッドであり、常に単一の接続でコマンドを順番に処理します。ただし、サブスクライバーのコールバックは非同期で実行され、ワー​​カースレッドに(個別に)渡される場合があります。現在、これをRedisSubscriberConnectionから順番に並べることができるかどうかを調査しています。 。

    更新:1.3.22以降、CompletionModeを設定できます PreserveOrderへ -その後、すべてのコールバックは同時にではなく順番に完了します。

    b)あなたの提案に従って調整した後、ペイロードのサイズに関係なく、いくつかのアイテムを公開すると素晴らしいパフォーマンスが得られます。ただし、同じ発行元から100,000以上のアイテムを送信すると、パフォーマンスが急速に低下します(私のマシンから送信するだけで7〜8秒になります)。

    まず、その時間は長く聞こえます-ローカルでテストすると(すべての応答を待つことを含め、100,000の出版物に対して)1766ms(ローカル)または1219ms(リモート)(直感に反するように聞こえるかもしれませんが、私の「ローカル」はそうではありません」同じバージョンのredisを実行しています。Centosでは「リモート」は2.6.12、Windowsでは「ローカル」は2.6.8-pre2です。

    実際のサーバーを高速化またはネットワーク化することはできませんが、これがパケットの断片化である場合に備えて、SuspendFlush()を追加しました(あなたのためだけに)。 / ResumeFlush() ペア。これにより、イーガーフラッシングが無効になります(つまり、送信キューが空の場合、他のタイプのフラッシングが引き続き発生します)。これが役立つと思うかもしれません:

    conn.SuspendFlush();
    try {
        // start lots of operations...
    } finally {
        conn.ResumeFlush();
    }
    

    Waitべきではないことに注意してください ResumeFlush()を呼び出すまでは、再開するまで send-bufferにはまだいくつかの操作がある可能性があります。これで、(100,000回の操作で)次のようになります。

    local: 1766ms (eager-flush) vs 1554ms (suspend-flush)
    remote: 1219ms (eager-flush) vs 796ms (suspend-flush)
    

    ご覧のとおり、ネットワークを通過するパケットが少なくなるため、リモートサーバーでより役立ちます。

    後で公開するアイテムが一度にすべて利用できるわけではないため、トランザクションを使用できません。その知識を念頭に置いて最適化する方法はありますか?

    私は考える これは上記で対処されていますが、最近CreateBatchに注意してください も追加されました。バッチはトランザクションのように動作します-ただ:トランザクションなしで。繰り返しますが、これはパケットの断片化を減らすためのもう1つのメカニズムです。あなたの特定のケースでは、サスペンド/レジューム(フラッシュ時)が最善の策だと思います。

    このようなラッパーに目的の機能を実行させるために、1つの一般的なRedisConnectionと1つのRedisSubscriberConnectionまたはその他の構成を使用することをお勧めしますか?

    ブロッキング操作(blpop)を実行していない限り 、brpopbrpoplpush など)、または特大のBLOBをネットワークに配置する(クリアする間、他の操作を遅らせる可能性があります)場合、通常、各タイプの単一の接続は非常にうまく機能します。ただし、YMMVは、正確な使用要件によって異なります。




    1. 最初のアドバイザーを書く

    2. セットのRedisのスコアとランキング機能のユースケース

    3. MongoDB $ hour

    4. 公式C#ドライバーを使用したMongoDBでのアップサーティング