web-dev-qa-db-ja.com

キューイングとシリアル化は適切に行われていますか?

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

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

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

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

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

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

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

追加情報

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

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

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

  • さらに追加RAMは一時的な措置です。マシンはすでに4GB-> 16GBのRAMであり、続行するためにダウンさせるのがますます難しくなっています。さらに追加します。

  • アプリケーションのスター型ルーティングパターンのため、オブジェクトがポップされてからキューにプッシュされる時間の半分は、まったく変化しません。これは、別の場所にある種のKey-Valueストアにそれを格納し、単にメッセージ識別子を渡すのに役立ちます(IMO)。

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

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

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

13
Bryan Boettcher

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

1
stonemetal

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

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

VMQueueと名付けたキューを設計しました(仮想メモリキューの場合、過去を振り返ると非常に悪い名前です)。 このキューの考え方は、コンシューマープロセスが標準まで実行されている場合、つまり、エンキューされた要素の数を特定のレベル未満に保つことができるのに十分な速さで処理されている場合、基本的に同じパフォーマンスを持つことです。ただし、コンシューマの速度が低下したり、利用できなくなったりして、プロデューサキューが特定のサイズまで大きくなると、キューは自動的にディスクとの間でエレメントのページングを開始します(BinaryFormatterシリアル化を使用)ちなみに、このプロセスはメモリ使用量を完全に制御し続け、ページングプロセスは高速、または少なくともメモリの負荷が高いときに発生する仮想メモリスワップよりもはるかに高速です。コンシューマがキューをしきい値未満に排出した場合、純粋なメモリベースのキューとして動作を再開します

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

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

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

4
sgorozco

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

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

また、正直に言うと、64 GBまたは128 GBのRAM-RAMが安いです。 Greenspun =「スローRAM at at it)」と「スマートMITの教育を受けた人にそれを最適化する」の違いを指摘し、RAMが勝つ。

最終的に、64 GBのRAM=を備えたSQL Serverマシンと、ASP.NETページを実行しているいくつかのフロントエンドマシンが登場しました...サイトswaptree.comは現在のメンバーシップを処理します40万人を超えるユーザー(急成長中)のうち、問題なく...

「マシンはすでに16 GBのRAMに移行している」とは言えず、64 GBのRAMで400k人のユーザーを処理していたサーバーを指摘している記事があります。

1
Marcel Popescu