1

サイズ4MBの文字列テキストを返すspringRestWebサービスエンドポイントがあります。このエンドポイントの負荷テストを実行すると、ヒープスパイクが常に発生し、最終的にシステムがクラッシュします。私は考えています-リクエストを行うとき、各リクエストはスレッドによって個別に処理されます。私の仮説は次のとおりです。文字列はグローバル静的変数に保存されるため、各スレッドは4MBのコピーを取得し、約3000リクエスト後、ヒープはすべて消費され、システムはクラッシュします。これは、各4MBを取得する3000スレッドが約12GBであるため、システムがクラッシュするためです。メモリが不足します。しかし、これは私の仮説です。

私の質問:リクエストを処理する各スレッドがその仕事を終えた後、Tomcatはメモリを再利用しませんか?これはGC(ガベージコレクション)と関係がありますか?リクエストのライフサイクルでは、リクエストが来ると、スレッドが作成されます(そのリクエストごとに)スレッドは応答の独自のコピーを取得しますか、それとも単に応答を参照しますか?その巨大な文字列応答が各スレッドにコピーされる場合、それがヒープスパイクが表示されている理由である可能性があります。応答がクライアントに返されるとき、tomcatはどのようにしてそのスレッドのリソースを再利用しますか?いつそれをしますか?GCに関連するリクエストスレッドを要求していますか?

私が観察したもう1つの側面は、socketWrite0()メソッドの遅延です。これには応答時間の70〜95%がかかります。ボトルネックだと思います。では、要求応答のフローでは、誰がソケットに書き込みますか?スレッド?または、スレッドがTomcatに応答を渡し、Tomcatがそれを書き込みますか?

メモリスパイクと巨大な文字列応答に関連するヒントや側面を教えていただければ幸いです。みんなありがとう!

薔薇

4

3 に答える 3

2

静的な最終文字列を宣言した場合、変数はスレッド間で共有する必要があります。コードがなければ、何が起こっているのかを言うことはほとんど不可能です。

JProfilermatなどのプロファイリングツールを使用してみましたか?

于 2012-10-08T18:32:59.520 に答える
2

私はあなたがしていることは

response.getWriter().write(hugeString);

それが問題を引き起こす場合、tomcatが責任を負います、それはおそらくそのような巨大な文字列を予期していませんでした。

文字列を小さな文字列にカットして、毎回1​​つの小さな文字列だけを書くようにすることができます。

int N = hugeString.length();
int CHUNK = 8*1024;
for(int i=0; i<N; i+=CHUNK)
    int end = Math.min(i+CHUNK, N);
    writer.write( hugeString.substring(i, end) );
于 2012-10-08T18:33:34.733 に答える
0

与えられたコメントをみんなに感謝します。この問題は、システムがパフォーマンステストで複数のユーザーにストレスを与えられた場合にのみ発生するため、非常にわかりにくいものでした。キャッシュクライアント、キャッシュ戦略、キャッシュの存続時間、接続タイムアウトにさまざまな変更を加えました。

アルゴリズムを変えてみました。レガシーシステムへの高額な呼び出しを回避するために、より多くのデータをキャッシュします。

データ構造をJSONArrayからStringに変更してみました。

すべてが役に立たなかった!

最後に、問題を引き起こしているのはロードバランサーであることがわかりました。無効にしたところ、すべて正常に機能しました。

私が1つのことを言う機会が与えられた場合、エンタープライズシステムのパフォーマンス/スケーラビリティは、パフォーマンスの低いコンポーネントによってボトルネックになっているため、慎重な経験的テストを行い、正しい問題点を見つけ出すために時間を費やした後、問題を攻撃します。コードを変更するために実行しないでください。

于 2012-10-24T01:29:16.530 に答える