Top 5 Java パフォーマンスメトリックスを観察し、エンタープライズアプリケーションの中に取り込みたいと思います。

最後の 2-3つの記事は、アプリケーションパフォーマンスマネジメント (APM) が紹介されており、
APM 戦略を効果的に実施するための挑戦が取り挙げられています。この記事は、あなたの企業の Java アプリの健全性を査定し、取り込むために
5つのトップパフォーマンスメトリクスをレビューするというトピックから成り立っています。
特にこの記事は次の点をレビューしています:

  •       ビジネストランザクション
  •       外部依存
  •       キャッシング戦略
  •       ガベージ コレクション
  •       アプリケーショントポロジー

1. ビジネストランザクション
ビジネストランザクションでは、現実のユーザーの行動を洞察します: 現実のユーザーが御社のアプリを使っている時に経験している
リアルタイムパフォーマンスを捕らえます。前の記事で述べたように、ビジネストランザクションのパフォーマンスを測るには、
総体的なビジネストランザクションのレスポンスタイムを捕らえると共に、その構成要素のレスポンスタイムを計ることが含まれています。 それらのレスポンスタイムは
その後、御社のビジネスニーズに最適なベースラインと比較され、正常値を決定します。
もしあなたが御社のアプリケーションの一側面のみを計ろうとしているなら、私は、
御社のビジネストランザクションの動作も測ることをお勧めします。コンテナメトリックスは豊富な情報を提供できる上、 あなたの環境をいつオートスケールにするのか決定するのを助けることができます。
あなたのビジネストランザクションは、御社のアプリケーションのパフォーマンスを決定します。アプリケーションサーバーのスレッドプールの使い方を尋ねる代わりに
御社のユーザーがビジネストランザクションを完了できているか、
そしてビジネストランザクションが正常に作動しているかを尋ねるべきです。
背景を少し説明すると、ビジネストランザクションは、入り口で認証されますが、
それはビジネストランザクションを開始するアプリとの相互作用なのです。ビジネストランザクションの入り口は、ウェブリクエスト、ウェブサービスコール、
メッセージキュー上のメッセージなどの相互作用により定義されます。代わりに、あなたは URL パラメータに基づいた同じウェブリクエストもしくはボディーのコンテンツに基づいたサービスコールによって、
たくさんの入り口を定義することを選択するかもしれません。 重要なポイントは、ビジネストランザクションがあなたのビジネスに
何か意味のある機能と関連している必要がある、ということです。
ビジネストランザクションが一度定義されると、次にその全体のアプリケーションのエコシステムにおけるパフォーマンスが測られます。それぞれのビジネストランザクションのパフォーマンスが
ベースラインに対して評価され、正常性が査定されます。例えば、もしビジネストランザクションのレスポンスが
このベースラインの平均レスポンスタイムからの 2つの標準偏差値より遅ければ、私たちはそれが
図 1 に示しているように異常な作動をしていると判断するかもしれません。

図 1 ベースラインに対する BT レスポンス時間の評価

ビジネストランザクションを評価する際に使用されるベースラインは、ビジネストランザクションが実行している時間に対して一貫しています。
しかし、ビジネストランザクションは各トランザクションの実行によって精錬されていきます。たとえば、ビジネストランザクションを一日の特定の時間、

あるいは一週間の内の該当する日の平均応答時間と比較するベースラインを選択したとします。現在の時間が終わると、
対象の時間に実行されたすべてのビジネストランザクションが翌週のベースラインに取り込まれます。このメカニズムを通して、
オリジナルのベースラインを破棄したり再構築する必要なくアプリケーションは何度も進化することができます。
それは、何度も動かすことの出来るウィンドウを考えてもらって結構です。
つまり、ビジネストランザクションはユーザーエクスペリエンスの測定値を最も良く反映するものであり、
キャプチャする上で最も重要なメトリクスなのです。

2. 外部との依存関係
外部との依存関係は、従属したウェブサービス、従来のシステムやデータベースなど様々な形でみられます。
外部との依存関係とは、アプリケーションが対話するシステムなのです。外部との依存関係の内部で実行するコードは必ずしも制御する必要はありませんが、
時には外部との依存関係の設定を制御することがあります。ですので、どのような時にそれがうまく実行し、
または実行しないのか知ることは重要なのです。さらに、アプリケーションの問題と依存関係における問題を区別できるようになる必要があります。
ビジネストランザクションという観点から、外部の依存関係を独自の層を持つものとして、特定し計測することができます。時には外部サービスのコールを包括する方法を特定するために、
モニタリング・ソリューションを設定しなければいけませんが、HTTPやJDBCのような一般的なプロトコルでは
外部との依存関係を自動で検出することができます。たとえば、私が勤めていた保険会社はAS/400を保有しており、
それと通信するために専用のプロトコルを使用していました。メソッドのコールを外部との依存関係として特定し、
その実行をAS/400への属性としました。しかし、私たちは自動で特定されるウェブサービスのコールも保有していました。ビジネストランザクション、
そしてそれを構成するアプリケーション層と同様に、外部との依存関係の動作はベースライン化され、
そういったベースラインを元に応答時間が評価されるべきなのです。

ビジネストランザクションは、アプリケーションのパフォーマンス全体へのビューを提供し、パフォーマンス問題の切り分けをサポートしてくれます。
しかし、外部との依存関係は、あなたが注視していない限り予期せぬ形でアプリケーションに甚大な影響を与えます。

3. キャッシュ戦略
データベースなどのシステムからオブジェクトを取得するためにネットワークのコールを作成するよりも、メモリからオブジェクトを供給する方が常に早いのです。
キャッシュは、このネットワークのラウンドトリップを回避するために、オブジェクトのインスタンスをローカルに格納するメカニズムを提供します。しかし、キャッシュは適切に設定されていない場合、
キャッシュ自体のパフォーマンス課題を表示することができます。キャッシュの一般的な問題は次のとおりです:
キャッシュへのデータの過剰ロード
キャッシュサイズが適切でない
私は、Object-Relational Mapping (ORM) ツールをあまり理解しておらず、特にレベル2キャッシュを認識していない方々と協力しています。
単一オブジェクトを取得するためにどのデータをメモリへロードするのか決定する場合、ORMツールは余りにも広範囲をカバーし過ぎているというのが総意です。
ツールは関連するデータのグラフを大量にメモリへロードする必要があります。こういったツールに対する多くの関心は、
正常に構成されましたが、特定された問題は本物でした。つまり、
アプリケーションで必要になる相互関係のあるデータのサブセットは少量のみなので、そうしたデータを大量にメモリにロードしたくないのです。
キャッシュのパフォーマンスを測定する場合、キャッシュにロードされるオブジェクトの数を特定し、
使用するオブジェクトの割合を追跡する必要があります。確認する主なメトリックは、キャッシュヒット率と
キャッシュからはじかれたオブジェクトの数です。キャッシュのヒット数やヒット率では、
オブジェクトの取得にネットワークトリップが必要になる代わりに、キャッシュからのオブジェクトリクエスト数をレポートします。キャッシュが大きいと、ヒット率は小さくなります(10%または20%以下)。
キャッシュからはじかれるオブジェクトの数が多くない場合は、キャッシュにロードしているデータが多すぎることを示しています。つまり、
キャッシュの大きさが十分でスラッシュしておらず(以下参照)、使用されないデータを大量に含んでいることになります。
キャッシュパフォーマンスを測定する際に考慮するもう1つの側面は、キャッシュのサイズになります。前の例のようにキャッシュが大きすぎませんか?キャッシュが
小さすぎませんか?もしくは、キャッシュのサイズは適切ですか?
キャッシュのサイズを決めるときの共通の問題は、ユーザーの行動とキャッシュの使用方法を正確に予測しないことです。100個のオブジェクトを
ホストするようにキャッシュを構成しましたが、アプリケーションでは常に300個のオブジェクトが必要ある場合を考えてみましょう。最初の100個のコールでは、
オブジェクトの初期セットをキャッシュにロードしますが、その後のコールでは探しているオブジェクトを見つけることができません。結果として、
キャッシュでは、LRU(最長時間未使用)アルゴリズムを使用するなどで、キャッシュから削除するオブジェクトを選択し、新しくリクエストされたオブジェクトのためにスペースを確保する必要があります。リクエストは
ネットワーク全体でクエリを実行し、オブジェクトを取得してキャッシュに保存する必要があります。結果として
オブジェクトの処理ではなくキャッシュの管理により多くの時間を費やすことになります。
このシナリオでは、キャッシュはパフォーマンスを向上させる代わりに邪魔をしていることになります。問題をさらに悪化させるのは、
Javaの特性とJavaによるガベージコレクションの管理方法によって、キャッシュからオブジェクトを頻繁に追加したり、削除することになるため、実際にはガベージコレクションの頻度を上げてしまうことです(以下参照)。
キャッシュを小さくし過ぎて前述のビヘイビアが発生する場合、キャッシュはスラッシュします。
このシナリオでは、キャッシュをスラッシュするよりもキャッシュを持たない方が得策になります。図2ではこれを図で示しています。

図2:キャッシュのスラッシュ

この状況では、アプリケーションはキャッシュからオブジェクトをリクエストしますが、オブジェクトは見つかりません。その後、
ネットワーク全体でオブジェクトの外部リソースをクエリして、キャッシュに追加します。最終的にキャッシュはフルになり、キャッシュからオブジェクトを削除して、
新しいオブジェクトのためにスペースを作り、その新しいオブジェクトをキャッシュに追加します。

4. ガベージコレクション

初回リリース時にJavaが提供した主要機能の1つがガベージコレクションでした。
ガベージコレクションには長所と短所があります。ガベージコレクションにより、メモリを手動で管理する必要がなくなりました。
オブジェクトを使い終わったら、そのオブジェクトへの参照を削除すると、ガベージコレクションが自動的に空にしてくれます。CやC++などの
手動のメモリ管理が必要な言語を使用する場合は、メモリを割り当てたり、空にする手間が少なくなることに感動することでしょう。
さらに、ガベージコレクションでは、メモリに参照がない場合は自動的に空にするので、
メモリが割り当てられる際に発生する従来のメモリのリークをなくし、メモリへの参照はメモリを空にする前に削除されます。
まるで万能薬のようですか?
ガーベッジコレクションによって手作業でのメモリ管理を不要にするという目標が達成され、従来のメモリリークから解放されたように、
今度は、ガーベッジコレクションの時には退屈なプロセスのコストを削減します。使用している JVM に基づいて、さまざまなガーベッジコレクションの戦略がありますが、それぞれを掘り下げることはこの記事の範疇を超えていまが、
ガーベッジコレクションがどのように機能しており、
どのように設定するのがベストであるかを理解すれば十分です。
ガーベッジコレクションの最大の敵は、いわゆる、メジャー、またはフルのガーベッジコレクションです。Azul JVM を例外として、
あらゆる JVM が、メジャーなガーベッジコレクションで苦労しています。ガーベッジコレクションの一般的な形式は、次の 2 つです:
マイナー
メジャー
マイナーなガーベッジコレクションは、短期的なオブジェクトを解放することを目標として、比較的頻繁に発生します。マイナーなガーベッジコレクションは、実行時に JVM スレッドをフリーズさせることはなく、
一般に、大きな影響を与えることもありません。
これに対して、メジャーなガーベッジコレクションは、時には、「世界をストップさせる (STW) 」ガーベッジコレクションとも呼ばれますが、
これは、実行中に JVM のすべてのスレッドを停止させるからです。何が起こっているかを図示するために、私の著書である「Pro Java EE
5 パフォーマンの管理と最適化」からの図表も含めました。

図 3 到達可能テスト
ガーベッジコレクションが実行されると、図 3 にある到達可能テストと呼ばれる、活動が行われます。これは、すべての実行中のスレッドから直接見えるすべてのオブジェクトを含む、オブジェクトの「ルート」で構成されます。
これは、すべての実行中のスレッドから直接見えるすべてのオブジェクトを含む、オブジェクトの「ルート」で構成されます。次に、ルートセットにあるオブジェクトによって参照されえちるそれぞれのオブジェクトをウォークし、
同様にして、すべてのオブジェクトが参照されるまで、これらのオブジェクトによってオブジェクトを参照します。この実行中に、ライブなオブジェクトによって使用されるメモリの位置を「マーク」し、
使用しなくなった時点で、すべてのメモリから「スイープ」されます。より正確に言えば、
ルートセットからのオブジェクト参照パスがないメモリを削除します。最後に、
新しいメモリが割り当てられるように、メモリをコンパクトにし、デフラグします。
マイナーおよびメジャーなコレクションは使用している JVM によって決まりますが、図 4 および 5 は、マイナーおよびメジャーなコレクションが Sun JVM でどのように作動するかを示しています。

図 4 マイナーなコレクション
マイナーなコレクションでは、 Eden スペースが満杯になるまで、メモリは Eden スペースに割り当てられます。「コピー」 コレクタを実行して、ライブオブジェクト (到達可能なテスト) を Eden から、
2 つの生き残ったスペースの1 つにコピーします (元スペースと先スペース)。Eden に残っているオブジェクトは、
スイープできます。生き残っているスペースが満杯になっても、まだライブオブジェクトがあるので、それらのライブオブジェクトは、保証されたスペースへ移動され、
そこでメジャーなコレクションによって解放されます。

図 5 メジャーなコレクション
結局、保証されたスペースも満杯になり、マイナーなコレクションが実行されますが、
生き残ったスペースにフィットしないライブオブジェクトをコピーできるスペースは、保証されたスペースにはありません。これが発生すると、 JVM は JVM にあるすべてのスレッドをフリーズし、到達可能テストを実行し、
最も若い世代をクリアし (Eden および 2 つの生き残ったスペース)、保証されたスペースをコンパクトにします。これを、メジャーなコレクションと呼びます。
予想されるように、ヒープが若いほど、メジャーなコレクションが発生する頻度は低いですが、
発生すると、小さいヒープの場合より、長い時間がかかります。したがって、ヒープのサイズをチューニングして、ガーベッジコレクションの戦略をアプリケーションの動作に適合させることが重要です。

5. アプリケーションのトポロジー
パフォーマンスで測定する、このトップ 5 のリストで最後のコンポーネントは、アプリケーションのトポロジーです。クラウドが出現したことで、
アプリケーションの特性が弾力的になりました: つまり、ユーザーの需要に応じて、アプリケーションの環境を拡大、縮小できるようになったのです。したがって、
アプリケーションのトポロジーのインベントリを取得して、環境のサイズを最適化できるようにすることが重要です。仮想サーバーのインスタンスが多すぎると、クラウドホスティングのコストが高くなりすぎます。
ただし、十分でなければ、ビジネストランザクションが満足に実行できなくなります

この評価で、2 つの指標を測定することが重要です:
ビジネストランザクションの負荷
コンテナのパフォーマンス
ビジネストランザクションをベースライン化し、ある時点でベースラインを満足させるのに必要なサーバーの数を知る必要があります。
たとえば、通常の負荷より 2 倍の標準偏差など、ビジネストランザクションの負荷が予想外に増加した場合、
そうしたユーザーを満足させるためにサーバーを追加します。
測定するもう1つのメトリックはコンテナーのパフォーマンスです。特にサーバーの階層が
拘束されているかどうかを確認し、拘束されている場合は、その階層に別のサーバーを追加します。ガベージコレクションなどの要因によって

個別のサーバーが拘束されている場合があるため階層全体のサーバーを確認することが重要です。
そして、階層のサーバーの大部分が拘束されている場合は、階層では受信するロードがサポートできないことを示している可能性があります。
アプリケーションのコンポーネントは個別に拡張できるため、
各アプリケーションのコンポーネントにおけるパフォーマンスを分析して、それに従ってトポロジを調整することが重要です。

まとめ
この記事では、アプリケーションの稼働状態を評価する際に測定するメトリックのトップ5について説明しました。まとめると、
そうしたトップ5の項目は次になります。
ビジネストランザクション
外部依存
キャッシング戦略
ガベージ コレクション
アプリケーショントポロジ
次の記事では、このシリーズのトピックすべてをまとめて、
AppDynamicsがAPM戦略を実施するために取ったアプローチを説明します。 これはマーケティング記事ではありません。
それよりも、特定の決断と最適化が行われた理由や、仮想またはクラウドベースのアプリケーションの稼働状態を提供する方法について説明しています。