Java パフォーマンスの決定版ガイド - 概要 2
性能試験方法
原則 2: バッチの経過時間、スループット、および応答時間を理解する
パフォーマンス テストの 2 番目の原則は、アプリケーションのパフォーマンスを複数の角度から検査することです。どのメトリックを測定する必要があるかは、アプリケーションにとって何が最も重要かによって異なります。
バッチ経過時間
アプリケーションのパフォーマンスを測定する最も簡単な方法は、10,000 株の 25 年間の過去の価格を取得して標準偏差を計算する、企業内の 50,000 人の従業員に対する報酬と福利厚生のレポートを生成する、1,000,000 ループ時間を実行するなどのタスクを完了するのにどれくらい時間がかかるかを確認することです。等
Java 以外の世界では、経過時間のテストは簡単です。アプリケーションは実行時間を測定するために時点を記録します。しかし、Java の世界では、ジャストインタイム コンパイル (JIT) が原因で、このアプローチには多少の問題があります。ここで重要なのは、仮想マシンがコードを完全に最適化し、最高のパフォーマンスで実行するまでに数分 (またはそれ以上) かかるということです。このような (およびその他の) 理由により、Java でのパフォーマンスの最適化を研究する際には、コード最適化のウォームアップ期間に細心の注意を払う必要があります。ほとんどの場合、パフォーマンスは、実行中のコードがコンパイルおよび最適化されるまで十分な時間実行された後に測定する必要があります。
其他影响应用热身的因素
通常认为的应用热身,指的就是等待编译器优化运行代码,不过基于代码的运行时长还有其他一些影响性能的因素。
例如,JPA通常都会缓存从数据库读取的数据,由于这些数据可以从缓存中获取而不需要到数据库,所以通常再次使
用时,操作就会变得更快。与此类似,应用程序读文件时,操作系统就会将文件载入内存。随后再次读取相同文件就
会变得更快,这是因为数据已经驻留在计算机主内存中,并不需要从磁盘实际读取。
一般来说,应用热身过程中有许多地方会缓存数据,虽然并不都那么明显
。
一方、多くの場合、アプリケーションの最初から最後までの全体的なパフォーマンスの方が重要です。レポート ジェネレーターが 10,000 個のデータ要素を処理するには時間がかかりますが、エンド ユーザーにとっては、最初の 5,000 要素の処理が最後の 5,000 要素より 50% 遅くても問題ありません。時間の経過とともにパフォーマンスが向上するアプリケーション サーバーのようなシステムであっても、初期パフォーマンスは依然として重要です。ある構成のアプリケーション サーバーは、ピーク パフォーマンスに達するまでに 45 分かかりました。ウォームアップ期間中のパフォーマンスは、この期間中にアプリケーションにアクセスするユーザーにとって重要です。これらの理由から、例の多くはバッチ指向になっています (それが珍しいように見えても)。
スループットテスト
スループット テストは、一定期間内に実行できる作業量に基づいて行われます。最も一般的なスループット テストは、クライアントによって生成されたデータを処理するサーバーですが、これは絶対的なものではありません。単一のスタンドアロン アプリケーションでもスループットと経過時間を測定できます。
クライアント/サーバーのスループット テストでは、クライアントの思考時間は考慮されません。クライアントはサーバーにリクエストを送信し、応答を受信すると、すぐに新しいリクエストを送信します。このプロセスは、テストの終了時にクライアントが完了した操作の合計数を報告するまで続きます。クライアントは複数のスレッドで処理されることが多いため、スループットはすべてのクライアントによって実行された操作の合計数になります。通常、この数値は、測定期間中の合計操作数ではなく、1 秒あたりに実行された操作の数です。この指標は、多くの場合、1 秒あたりのトランザクション数 (TPS)、1 秒あたりのリクエスト数 (RPS)、または 1 秒あたりの操作数 (OPS) と呼ばれます。
すべてのクライアント/サーバー テストには、クライアントが十分な速度でサーバーにデータを送信できないというリスクがあります。これは、クライアント マシンの CPU が必要なクライアント スレッド数をサポートするのに十分ではないこと、またはクライアントが新しいリクエストを送信する前に応答の処理にかなりの時間を費やしていることが原因である可能性があります。これらのシナリオでは、テストではサーバーのパフォーマンスではなくクライアントのパフォーマンスが実際に測定されますが、これは本来の目的ではありません。
リスクは、各スレッドによって実行される作業量 (スレッドの数とクライアント マシンの構成) によって異なります。クライアント スレッドで実行する必要がある作業量が多いため、この問題は思考時間ゼロ (スループット重視) テストで発生する可能性が高くなります。したがって、スループット テストは通常、応答時間テストよりもスレッドが少なく、スレッド負荷も小さくなります。
多くの場合、スループット テストでは、リクエストの平均応答時間も報告されます。これは重要な情報ですが、報告されたスループットが同じでない限り、情報が変化してもパフォーマンスの問題を示すものではありません。0.5 秒の応答時間で 500 OPS を維持できるサーバーは、0.3 秒の応答時間でも 400 OPS しかないサーバーよりも優れたパフォーマンスを発揮します。
特に測定対象が固定されていないため、スループット テストは常に適切なウォームアップ期間の後に行われます。
応答時間のテスト
一般的に使用される最後のテスト指標は応答時間です。これは、クライアントが要求を送信してから応答を受信するまでの経過時間です。
応答時間テストとスループット テスト (後者はクライアント/サーバー モデルに基づいていると仮定) の違いは、応答時間テストのクライアント スレッドが操作間の一定期間スリープすることです。これを思考時間といいます。応答時間テストは、ユーザーの動作を可能な限りシミュレートすることです。ユーザーはブラウザーに URL を入力し、返された Web ページを読んでしばらく時間を費やしてから、ページ上のリンクをクリックし、返された Web ページを読んでしばらく時間を費やします。すぐ。
テストに思考時間が導入されると、スループットは固定されます。つまり、指定された数のクライアントは、指定された思考時間に対して常に同じ TPS (わずかな差はありますが) を取得します。この時点で、リクエストの応答時間を測定することが重要になります。サーバーの効率は、一定の負荷にどれだけ早く応答するかによって決まります。
思考时间和吞吐量
有两种方法可以测试客户端包括思考时间时的吞吐量。最简单的方法就是客户端在请求之间休眠一段时间。
while(!done){
time = executeOperation();
Thread.currentThread().sleep(30 * 1000);
}
这种情况下,吞吐量一定程度上依赖响应时间。如果响应时间是1秒,就意味着客户端每31秒发送一个请求,产生的吞吐量就是0.032 OPS。如果响应时间是2秒,客户端就是每32秒发送一个请求,吞吐量就是0.031OPS。
另外一种方法是周期时间(Cycle Time)。周期时间设置请求之间的总时间为30秒,所以客户端休眠的时间依赖于响应时间:
while(!done){
time = executeoperation();
Thread.currentThread().sleep(30 * 1000 - time);
}
无论响应时间是多少,这种方法都会产生固定的吞吐量,每个客户端0.033 OPS(假设本例中的响应时间都少于30秒)。
测试工具中的思考时间时常有变,平均值为特定值,但会加入随机变化以更好地模拟用户行为。另外,线程调度从来不会严格实时,所以客户端请求之间的时间也会略有不同。
因此,即便工具提供周期时间而不是思考时间,测试所报告的吞吐量也相差无几。但是,如果吞吐量远超预期,说明测试中一定有什么出错了。
応答時間を測定するには 2 つの方法があります。応答時間は、リクエスト時間の合計をリクエスト数で割った平均値としてレポートできます。応答時間は、90 パーセンタイル応答時間などのパーセンタイル要求としてレポートすることもできます。リクエストの 90% が 1.5 秒未満で応答され、リクエストの 10% が 1.5 秒未満で応答される場合、1.5 秒が 90 パーセンタイルの応答時間になります。
2 つの方法の違いの 1 つは、平均が外れ値の影響を受けることです。これは、平均値を計算するときに外れ値が含まれるためです。外れ値が大きいほど、平均応答時間への影響が大きくなります。
以下の図は、20 個のリクエストと一般的な応答時間の範囲を示しています。応答時間は 1 ~ 5 秒です。平均応答時間 (太線が平行で X 軸に近い) は 2.35 秒で、リクエストの 90% が 4 秒以内に発生しました (太い線が平行で X 軸から遠い)。
これは、正常に動作するテストの一般的なシナリオです。以下に示すデータの場合、外れ値が分析の精度に影響を与える可能性があります。
このデータ セットには、1 つの大きな外れ値が含まれています。つまり、1 つのリクエストに 100 秒かかりました。その結果、90 パーセンタイル応答時間と平均応答時間の太線が入れ替わります。平均応答時間は 5.95 秒に跳ね上がりましたが、90 パーセンタイルの応答時間は 1.0 秒でした。このような場合、外れ値の影響を軽減することを考慮する必要があります (結果として平均応答時間が短縮されます)。
一般に、このような異常値はまれですが、Java アプリケーションでは GC (ガベージ コレクション) によって発生する一時停止により異常値が発生する傾向が高くなります。(GC によって 100 秒の遅延が発生するからではありませんが、特に平均応答時間が短いテストの場合、GC の一時停止により大きな外れ値が生じる可能性があります。) パフォーマンス テストは通常、90 パーセンタイルの応答時間に焦点を当てます (95 パーセンタイルまたは 99 パーセンタイルの応答時間の場合もあります) 。ここで 90 パーセンタイルと言うのは魔法のようなものではありません)。1 つの数値のみに注目できる場合は、パーセンタイルに基づいて応答時間を選択することをお勧めします。応答時間を短縮すると、ほとんどのユーザーにメリットが得られるからです。大きな外れ値のあるシナリオを見逃さないように、平均応答時間と少なくとも 1 パーセンタイルの応答時間の両方を考慮することをお勧めします。
簡単な概要
- バッチ指向のテスト (またはウォームアップ期間のないテスト) が Java パフォーマンス テストで使用されることはほとんどありませんが、貴重な結果が得られる可能性があります。
- スループットや応答時間を測定する他のテストは、負荷が一定の速度で読み込まれるかどうか (つまり、シミュレートされたクライアントの思考時間に基づくかどうか) に依存します。
原則 3: 統計的手法を使用してパフォーマンスの変化に対処する
原則 3 は、パフォーマンス テストの結果は時間の経過とともに変化するということです。プログラムが毎回同じデータセットを処理したとしても、生成される結果は依然として異なります。マシン上のバックグラウンド プロセス、時々発生するネットワークの混雑など、プログラムの動作に影響を与える要因が多数あるためです。優れたベンチマークは、毎回同じデータセットで実行されるのではなく、テスト中にランダムな動作を作成して現実世界を模倣します。これにより、実行結果の違いはパフォーマンスの変化によるものなのか、それともテストのランダム性によるものなのかという疑問が生じます
この問題は、テストを複数回実行し、結果を平均することで解決できます。テスト対象のコードが変更されると、テストが複数回実行され、結果が平均され、2 つの平均が比較されます。しかし、物事は想像ほど単純ではありません。テスト間の違いが実際のパフォーマンスの変動なのかランダムな変動なのかを判断するのは簡単ではありません。これがパフォーマンス チューニングの鍵となります。
ベンチマーク結果を比較する場合、平均値の違いが実際のパフォーマンスの違いなのか、それともランダムな変動なのかを知ることはできません。これを行うための最良の方法は、「手段は同じである」と仮定し、このステートメントが真である確率を判断することです。命題が偽である可能性が高い場合、真である平均値には差があるという確信があります (ただし、100% 確実であることは決してあり得ません)。
このようにコード変更によるテストを回帰テストと呼びます。回帰テストでは、元のコードをベースライン(ベースライン)、新しいコードをサンプル(標本)と呼びます。バッチ プログラムの場合を考慮すると、ベースラインとサンプルの両方が 3 回実行され、かかる時間が次の表に示されます。
サンプルの平均では、コードのパフォーマンスが 25% 向上していることがわかります。このテストに反映された 25% の改善をどの程度信じられますか? サンプル内の 3 つの値のうち 2 つがベースライン平均よりも小さく、これは大きな改善のように見えますが、これらの結果の分析により結論が導き出されます。サンプルとベースラインのパフォーマンスが同じになる確率は 43% です。観察された数値は、2 セットのテストの基本パフォーマンスが 43% の確率で同じであるため、パフォーマンスが異なるのは 57% の確率だけであることを示しています。57% の確率で同じパフォーマンスが得られないことと、25% のパフォーマンスが向上することは、後から考えるとまったく同じではありません。
テスト結果には大きなばらつきがあるため、上記の確率は予想とは異なるようです。一般に、結果として得られるデータが多様になればなるほど、平均値間の差異が実際の差異であるのか、それともランダムな変動であるのかを判断することが難しくなります。ここでの 43% という数字は、一連のデータとその変化の統計分析である Student の t 検定 (以下、t 検定) の結果です。「学生」は、最初にテストを公開した科学者のペンネームです⁵。t
検定によって計算される値はp
、帰無仮説が成立する確率を指します。
回帰テストにおける帰無仮説は、2 セットのテストのパフォーマンスが同じであると仮定することを指します。この例の p 値は約 43% であり、2 つの検定平均値が同じであると信じる確率が 43% であることを意味します。逆に、手段が異なると信じる確率は 57% です。57% は、2 セットのテストの平均値が同じではないことを意味しますか? 厳密に言うと、これは、パフォーマンスが 25% 向上したと信じる確率が 57% あるという意味ではなく、単にパフォーマンスが 25% 向上したということを意味します。結果が異なると信じる確率は 57% です。パフォーマンスは 25% 改善される場合もあれば、125% 改善される場合もあり、あるいはサンプルの実際のパフォーマンスがベースラインよりも悪化する場合もあります。最も可能性が高いのは、測定された差が実際の差に近いということです (特に p 値が減少するため) が、それを確信することはできません。
统计学及其语义
正确表述`t`检验结果的语句应該像这样:试样与基线有差别的可能性为57%,差别预计最大有25%。
t
通常、テストはα
値を指定して使用されます。値α
は、結果がその点に達した場合に統計的に有意となる点です。通常α
、値は 0.1 に設定されます。つまり、サンプルとベースラインが 10% (0.1) の確率でのみ一致する場合 (または逆に、サンプルとベースラインが 90% の確率で異なる場合)、結果は統計的に有意であると見なされます。 。その他の一般的に使用されるアルファ値は、0.05 (95% 信頼水準) または 0.01 (99% 信頼水準) です。p 値が 1-alpha 値より小さい場合、検定は統計的に有意であると見なされます。
したがって、コードのパフォーマンスの変化を探す適切な方法は、まず有意水準 (0.1 など) を決定し、次に検定を使用してt
サンプルがこの有意水準でベースラインと異なるかどうかを判断することです。この例では、p 値は 0.43 ですが、90% の信頼水準では有意な差があるとは言えず、結果は平均が同じではないことを示しています。テストに大きな違いがないという事実は、結果が重要ではないという意味ではなく、テストが決定的ではないことを意味しているだけです。
統計的に言えば、決定的なテストが行われないのは通常、サンプル データが不十分であることが原因です。これまでの例では、ベースラインとサンプルに対してそれぞれ 3 回の反復を考慮しました。さらに 3 回の反復を追加すると、結果は次のようになります: ベースラインの反復結果は 1、1.2、および 0.8 秒で、サンプルの反復結果は 0.5、1.25、および 0.5 秒でした? データが増加するにつれて、p -値は 0.43 から 0.19 に変化しました。これは、結果が異なる確率が 57% から 81% に上昇したことを意味します。さらにテストを繰り返し実行し、3 つのデータ ポイントを追加した後、確率は 91% に増加し、統計的有意性の通常のレベルを超えました。
特定の統計的有意性レベルに達するために、より多くのテスト反復を実行できるとは限りません。厳密に言えば、そうする必要はありません。実際、統計的有意性を決定するために使用される α の値は任意に選択できますが、通常は一般的に受け入れられている値が選択されます。p 値 0.11 は、90% の信頼水準では統計的に有意ではありませんが、89% の信頼水準では統計的に有意です。
ここで結論が得られます。回帰テストは白黒はっきり付ける科学ではありません。一連のデータは、統計的に分析しなければ数値の意味を理解することができず、比較や判断ができません。さらに、統計分析であっても、確率の不確実性により、完全に信頼できる結果を与えることはできません。パフォーマンス チューニング エンジニアの仕事は、大量のデータ (またはその平均) を検討し、さまざまな確率を計算し、どこで作業するかを決定することです。
簡単な概要
- テスト結果間の差異を適切に判断するには、これらの差異がランダムな要因によるものかどうかを判断するための統計分析が必要です。
- これは、厳密なテストを使用してテスト結果を比較することで実現できます
t
。 t
テストでは、変動が存在する確率を知ることができますが、どの変動を無視し、どの変動を追求すべきかはわかりません。この 2 つのバランスをいかに見つけるかが、パフォーマンス チューニング エンジニアリングの芸術的な魅力です。