適切にキューに入れてシリアル化していますか?


13

さまざまなサービスを通じてメッセージを処理します(1つのメッセージは、完了する前におそらく9つのサービスに触れ、それぞれが特定のIO関連機能を実行します)。現在、パフォーマンスに関して最悪のケース(XMLデータコントラクトシリアル化)とベストケース(メモリ内MSMQ)の組み合わせがあります。

メッセージの性質は、シリアル化されたデータが約12〜15キロバイトになり、週に約400万のメッセージを処理することを意味します。MSMQの永続メッセージは私たちにとって遅すぎました。データが大きくなるにつれて、MSMQのメモリマップファイルからのプレッシャーを感じています。 サーバーのメモリ使用量は16 GBで、キューイングのためだけに増加しています。 メモリの使用量が多い場合、マシンがスワップを開始するため、パフォーマンスも低下します。既にMSMQの自己クリーンアップ動作を実行しています。

ここで間違っている部分があるように感じます。RavenDBを使用してメッセージを永続化し、識別子をキューに入れようとしましたが、パフォーマンスは非常に遅くなりました(せいぜい毎分1000メッセージ)。それが開発バージョンを使用した結果なのかどうかはわかりませんが、より高いスループットが必要です[1]。コンセプトは理論上は非常にうまく機能しましたが、パフォーマンスはタスクに応じていませんでした。

使用パターンには、すべての読み取りを行うルーターとして機能する1つのサービスがあります。他のサービスは、サードパーティのフックに基づいて情報を添付し、ルーターに送り返します。ほとんどのオブジェクトは9〜12回タッチされますが、約10%は、サードパーティが適切に応答するまで、このシステムでしばらくループすることを強制されます。この理由でメッセージの優先度フィールドを使用するため、サービスは現在これを考慮しており、適切なスリープ動作を持っています。

だから、私の質問は、C#/ Windows環境でディスクリートだがLAN接続されたマシン間でメッセージを渡すための理想的なスタックは何ですか? 通常、XMLシリアル化ではなくBinaryFormatterから始めますが、シリアル化をドキュメントストアにオフロードするのがより良い方法である場合、それはうさぎの穴です。したがって、私の質問。

[1]:私たちのビジネスの性質は、メッセージをより早く処理するほど、より多くのお金を稼ぐことを意味します。週の後半にメッセージを処理すると、そのお金を稼ぐ可能性が低くなることを経験的に証明しています。「1分あたり1000」というパフォーマンスは非常に高速に聞こえますが、実際にはその数が10k /分以上必要です。1週間あたりのメッセージ数を指定しているからといって、それらのメッセージを処理するのに1週間あるというわけではありません。

===============編集:

追加情報

コメントに基づいて、いくつかの説明を追加します。

  • シリアル化がボトルネックであるかどうかはわかりません。アプリケーションのベンチマークを行ったところ、シリアル化はヒートグラフに表示されますが、サービスのCPU使用率の2.5〜3%にしか関与していません。

  • 私は、私たちのメッセージの永続性とMSMQの潜在的な誤用についてほとんど心配しています。キューのパフォーマンスを維持できるように、非トランザクション、非永続メッセージを使用していますが、少なくとも永続メッセージが再起動後も存続できるようにしたいです。

  • RAMを追加することは一時的な対策です。マシンはすでに4GBから16GBのRAMに移行しており、追加を続けるためにマシンを停止することはますます難しくなっています。

  • アプリケーションのスタールーティングパターンにより、オブジェクトがポップされてからキューにプッシュされる時間の半分は、まったく変化しません。これは、他の場所の何らかのキー値ストアにそれを保存し、メッセージ識別子を単に渡すことに再び役立ちます(IMO)。

  • スタールーティングパターンはアプリケーションに不可欠であり、変更されません。途中のすべてのピースが非同期に(ポーリング方式で)動作し、再試行動作を1か所に集中させたいため、アプリケーションをムカデにすることはできません。

  • アプリケーションロジックはC#で記述され、オブジェクトは不変のPOCO、ターゲット展開環境はWindows Server 2012です。特定のソフトウェアがLinuxでのみサポートされている場合、追加のマシンを立ち上げることができます。

  • 私の目標は、現在のスループットを維持しながら、最小限の資本でメモリフットプリントを削減し、フォールトトレランスを向上させることです。


関連するポイントが質問に組み込まれたため、コメントは整理されました。
ChrisF

キューサブシステムの交換を心配する前に、最も差し迫った問題に対処することは理にかなっています(ただし、最終的に行う価値はあります)。メモリが制御不能に成長しているという事実は、どこかにリークがあることを示唆しています。(もしあれば)何のメモリプロファイリングが行われましたか?
ダンライオンズ

@DanLyons:メモリの増加はMSMQのみです。誰も実際にそれについて話すことはありませんが、それはすべてメモリマップされた非永続的なメッセージのためであるようです。大量のデータをシリアル化するため、かなりの量のメモリが割り当てられたままになります。メッセージが消費され、MSMQの内部クリーンアップが実行されると、メモリは(最終的に)再利用されます。
ブライアンベッチャー

回答:


1

興味のあるキューベンチマークを次に示します 。MSMQは1秒あたり10Kメッセージを処理できる必要があります。構成の問題かもしれませんか、おそらくクライアントがキューの読み取りに追いついていないのでしょうか?また、これらのベンチマークでZeroMQが非常に高速(1秒あたり約10万メッセージ)であることに注意してください。永続オプションはありませんが、パフォーマンスを向上させたい場所に到達するはずです。


4

数年前、メッセージシステム(キューの場合はオーディオフィンガープリント)がキューに入れられていて、似たような状況がありました。エンキューされたデータパケットの永続性を強く評価しましたが、すべてをディスクにエンキューし、ディスクからキューを消費すると非常にコストがかかることがわかりました。

メモリベースのキューに切り替えた場合、パフォーマンスは例外的でしたが、大きな問題がありました。時々、キューのコンシューマーがかなりの時間利用できなくなります(この場合のコンシューマーとプロデューサーの要素はWANを介して接続されます)。メモリ消費が非常に多くなると、スワッピング中の過度のメモリスラッシングによりシステムが完全にクロールされました。

クリスチャンと命名したキューを設計しましたVMQueue (仮想メモリキューのために、振り返ってみると非常に悪い名前です)。このキューの考え方は、コンシューマープロセスがパーまで実行されている場合、つまり、キューに入れられた要素の数を特定のレベル以下に維持できるほど高速に処理されている場合、基本的にメモリのパフォーマンスと同じです。ベースのキュー。ただし、コンシューマーの速度が低下するか使用できなくなり、プロデューサーキューが特定のサイズに達すると、キューは自動的にディスクとの間で要素のページングを開始します(BinaryFormatterところでシリアル化)。このプロセスにより、メモリ使用量が完全に制御され、ページングプロセスが高速になります。または、少なくともメモリの負荷が高いときに発生する仮想メモリスワッピングよりもはるかに高速です。コンシューマーがなんとかしきい値を下回ってキューを排出すると、純粋なメモリベースのキューとしての動作を再開します

システムがクラッシュまたは再起動した場合、キューはディスクに保存されたすべてのページ要素を回復できます。クラッシュ前にメモリに保持されていた要素のみが失われます。クラッシュまたはリブート中に限られた数のパケットを失う余裕がある場合、このキューが役立ちます。

興味があれば、VMQueueクラスのソースコードを共有して、試してみてください。キューは、Serializableとしてマークされているすべてのクラスを受け入れます。キューの作成時に、要素の数でページのサイズを設定します。クラスインターフェイスは、標準のQueueクラスとほぼ同じです。ただし、コードは非常に古い(.net 1.1)ため、残念ながらジェネリックインターフェイスは存在しません。

実績のあるMSMQテクノロジーからの移行が大きな賭けであることは知っていますが、このキューはほぼ6年間確実に機能しており、プロデューサーマシンが数週間オフラインであったシナリオから生き残り、回復することができました!興味があれば教えてください。:)


1

HP ProLiant ML350G5システムは、1分あたり82kのトランザクションを取得します。つまり、先ほど述べた「10k /分」のスループットの8倍を超えています。

パフォーマンス:82,774 tpmC

また、正直なところ、64 GBまたは128 GBのRAMを使用しただけです。RAMは安価です。Greenspunは、「RAMを投げる」と「賢いMITの教育を受けた人に最適化を依頼する」の違いを指摘し、RAMが勝ちました。

最終的に、64 GBのRAMを搭載したSQL Serverマシンと、ASP.NETページを実行する少数のフロントエンドマシンになりました。難なく...

「マシンはすでに16 GBのRAMになっています」では不十分で、64 GBのRAMで40万人のユーザーを処理していたサーバーについての記事があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.