ブログ

JMX監視+Javaカスタムメトリクス

JMX監視+Javaカスタムメトリクス

本文の内容は、2019年4月24日にFede Barcelonaが投稿したブログ(https://sysdig.com/blog/jmx-monitoring-custom-metrics/)を元に日本語に翻訳・再構成した内容となっております。

このチュートリアルでは、JMXモニタリングを使用してアプリケーションのメトリクスを公開するためにJavaコードをインストルメントする方法を学んでいきたいと思います。コードの例に従うと、Javaアプリケーションの可用性、健全性、パフォーマンスを監視することができます。

Java 1.5では、JMX - Java Management eXtensions - JREの世界でコードを計測するための標準的な方法です。これにより、MBeansを使用して標準的なメトリクスとカスタムメトリクスをモニタリングシステムにエクスポートすることができ、アプリケーションがどのように実行されているかを理解することができます(メモリ使用量、CPU使用量、スレッド数、RESTエンドポイントでのAPIコール...計測したいものは何でも、実際に)。

このブログでは、JMXモニタリングがどのように機能するか、また、JavaアプリケーションにJMXメトリクスを実装する方法について説明します。

JMXモニタリング - Java JMXとは何か?

大規模なJavaアプリケーションは、さまざまなメトリクスのニーズをもたらします。すべてがあるべき姿で動作していることを確認したいのか、パフォーマンス情報を収集したいのか、接続されているユーザー数などの使用パターンを理解したいのか、どのエンドポイントがREST APIで最も使用されているのか、などです。

例えば、データベースから毎秒何度も読み書きするような大規模なアプリケーションでは、出力メッセージをログに記録する代わりに、Java Management Extensions のようなモニタリング・インターフェースを提供するのが良い方法です。カスタムJavaメトリクスは、メンテナンス、トラブルシューティング、外部監視ツールとの統合が容易になります。JMX にデータをエクスポートするクラスは、マネージド・ビーン(MBean)と呼ばれます。これらの MBean は、Java プラットフォームによって提供される MBean サーバにそのメトリクスを公開(エクスポート)します。

MBeanServerは、構成されたエンドポイント(MBeans)をスクレイプし、Java RMIやHTTP/SOAPのような異なるプロトコルを使用してメトリクスを公開するメトリクス収集エージェントに同化することができます。

これは、JMX モニタリング/MBean アーキテクチャの基本的な表現になります。

0.png

Java MBean とは何ですか?

MBeanは、情報を返すメソッドを持つオブジェクトで、MBeanServerを介して外部に情報をエクスポートすることができます。

MBeanには4つのタイプがあります。

Standard MBean:

Standard MBean: これは、アプリケーションをインストルメントする最も一般的で簡単な方法です。これは、メトリクスの現在の値を取得し、それらを変更することができます。標準MBeansはまた、実行中にプログラムの外部から呼び出すことができるいくつかの操作を実装しています。

余分な動作を必要としない場合は、これを使用してください。必要なのは、必要な情報をエクスポートするゲッター関数を持つインターフェイスを作成することだけです。

ダイナミック MBean:

この種のMBeanは、javax.management.DynamicMBeanインターフェイスを実装することで自動検出されるメトリクスを取得または変更するためのゲッターとセッターも実装しています。

これらは、メトリクスを公開するためにMBean標準に従っていないクラスがある場合に便利です。MBeanServer がこのクラス内でどのように値を公開しなければならないかを手動で定義することができます。

インターフェイスをコーディングしたくない場合や、どのフィールドをエクスポートする必要があるか事前にわからない場合は、このクラスを使用してください。

モデル MBean:

これは、リソースを計測するために使用されるMBeanの一般的で、動的で、実行時に設定可能なタイプのMBeanです。これにより、Java Dynamic Managementエージェントに接続されているマネージャは、MBeanを動的に作成して設定することができます。

JMXに接続している誰もがプログラムでMBeanをインスタンス化したり設定したりできるようにする必要がある場合に使用してください。

Open MBean:

これらは Dynamic MBean の一種であるため、javax.management.DynamicMBean インターフェースを実装する必要があります。

このタイプでは、事前に定義されたJavaクラスのセットのみを使用して、実行時に発見されるオブジェクトをインストルメントすることができます。

  • java.lang.Boolean
  • java.lang.Byte
  • java.lang.Character
  • java.lang.Short
  • java.lang.Integer
  • java.lang.Long
  • java.lang.Float
  • java.lang.Double
  • java.lang.String
  • java.math.BigInteger
  • java.math.BigDecimal
  • javax.management.ObjectName
  • javax.management.openmbean.CompositeData
  • javax.management.openmbean.TabularData

アプリケーションから特定のJavaクラスをロードする必要がないので、JMX仕様を使用するアプリケーションの広い範囲に開放する必要があるリソースを計装する柔軟な手段が必要な場合は、この1つを使用してください。

Java JMX監視、コード例

これがどのように実装されているかを理解するために、標準MBeanを利用した小さなサンプル・アプリケーションを作成します。

まず、MBeanServer が情報を取得するインターフェイスを作成する必要があります。

public interface SystemStatusMBean {
       Integer getNumberOfSecondsRunning();
       String getProgramName();
       Long getNumberOfUnixSecondsRunning();
       Boolean getSwitchStatus();
    } 

これは、依存性インジェクションを使用して、このオブジェクトが4つのメトリクスをエクスポートすることをMBeansServerに伝えます。

  • NumberOfSecondsRunning
  • ProgramName
  • NumberOfUnixSecondsRunning
  • SwitchStatus

実際にこの動作を実装したオブジェクトを書いてみましょう:

先ほどのコードを見ると、インターフェイスのすべてのメトリクスを実装したオブジェクトを作成しているだけで、バックグラウンド・スレッドを使って毎秒更新していることがわかります。

最後に、MBeanオブジェクトのインスタンスを作成し、MBeanServerに登録します。

MBean は、MBeanServer 内で識別するための ObjectName が必要です。名前には、衝突やキーを避けるためにドメインを含める必要があります。この例では、ドメインは com.sysdig.app、キーは name=SystemStatusExample となります。

Dockerで試してみる

ローカル環境にJavaコンパイラやランタイムがない場合は、Dockerを使うことができます。

$ docker run -d --rm --name jmx -p 5000:5000 sysdiglabs/jmx-metrics:0.1

jconsoleを実行してローカルプロセスに接続し、jmxのモニタリングメトリクスをチェックします。

1.png

Jconsole JMXセキュリティ警告(no-SSL endpoint)が表示されますが、この場合は続行しても問題ありません。

今すぐMBeansタブに移動し、左側のパネルを使用してcom.sysdig.app, SystemStatusExample, Attributesに移動します。

2.png

Jconsole mbeans私たちが作成したカスタムJMXメトリクスを見ることができ、その値をライブで更新することができるはずです。

jconsoleインターフェイスを使用して見ることができるように、余分なインスツルメンテーションなしですぐに監視できるいくつかのデフォルトのメトリクスがあり、これらのデフォルトのMBeansについて詳しく知りたい場合は、このドキュメントの付録があります。

Sysdig MonitorでのJava JMXモニタリング

JREやPrometheusやStatsDのような他のモニタリングシステムと一緒に、モニタリングシステムにJMXメトリクスを表示させたいと思うでしょう。コンテナ内でJavaアプリケーションを実行したり、Kubernetesの上でJavaアプリケーションを実行したりすると、より複雑になる可能性があります。

これらは、JMXメトリクスを使用してJavaコードを計測する際に遭遇する可能性のある障害のいくつかです。

  • JMXポートを公開し、Dockerfileを変更し、Kubernetesのデプロイメント定義を更新する必要があります。
  • 複数のポッドがKubernetesノードの周りを移動し、これらのメトリクスを公開していますが、どのようにしてJavaアプリのIP/ポートを知っていますか?
  • メトリクスのポートを公開するには、認証やTLSなどのセキュリティを実装する必要があります。

それはもう簡単ではありませんよね?Sysdig Monitorはここであなたを助けてくれます。開発者の視点から見ると、Sysdig Monitorを使用することで、いくつかの直接的な利点があります。

  • マイクロサービスアプリケーションの異なるコンポーネントを自動的に発見し、それらがどのように相互作用しているかを可視化し、アプリケーションがどのように動作しているかを高いレベルから理解することができます。
  • それ以上のコード変更は必要ありません。Sysdig Monitorは、ホストやコンテナごとのリソース使用量のメトリクスや、サービスの健全性とパフォーマンス(接続、応答時間、エラーなど)を監視するGolden Signalなど、必要なすべてのメトリクスをすぐに提供します。
  • JMX モニタリングメトリクスを一箇所で自動的に収集! Sysdigエージェントは、実行中のコンテナのプロセス・ネームスペースに動的に入力し、ローカルホスト・インターフェースにバインドされたポートからMBeansメトリクスを収集します。JMXポートを公開したり、DockerfilesやKubernetesマニフェストを変更する必要はありません。Sysdig Monitorを使えば、JMXメトリックの収集はとてもシンプルで安全です。

Sysdigエージェントは、JMXカスタムメトリックコレクションを起動して実行するためにいくつかの設定が必要です。

この例では、先ほどの例からいくつかのカスタムJMXメトリックを収集する方法を示しています。dragent.yamlまたはそれを扱うKubernetes ConfigMapで、jmxセクションの下に追加します。

jmx:
  per_process_beans:
    systemStatus:
    pattern: "Main"
    beans:
        - query: "com.sysdig.app:name=SystemStatusExample"
          attributes:
            - name: NumberOfSecondsRunning
            alias: java.app.numberOfSecondsRunning
            - name: NumberOfUnixSecondsRunning
            alias: java.app.numberOfUnixSecondsRunning
            - name: SwitchStatus
            alias: java.app.switchStatus 

ご覧のように、クエリはMBeanServerに登録されているMBeanの名前で、属性はMBeanがエクスポートしているメトリクスだけです。

数秒後には、メトリクスがSysdig Monitorのインターフェイスに表示されるので、ライブで参照することもできます。

3.png

またはダッシュボードで整理することができます。

まとめ

Java Monitoring Extensions を使用すると、Java アプリケーションにプロファイリングとアプリケーションレベルのモニタリングを簡単に追加することができます。また、CPU 負荷、メモリ使用量、クラスロード、スレッドをトラブルシューティングするための一般的な JMX メトリクスのセットが装備されています。

JavaアプリケーションからJMXメトリクスをインポートしたいが、Prometheusやstatsdのような他のメトリクスソースも持っていますか?Sysdig MonitorJMXメトリクスのスクレイピングをサポートしているので、すべてのメトリクスを統一し、単一のプラットフォームからダッシュボードやアラートを生成することができます。SysdigのJMXクエリ言語を使用することで、環境上でスポーンする新しいJavaプロセスやメトリクスを自動的にスクレイピングすることができます(例えば、DockerやKubernetesでサービスの自動スケーリングを使用している場合など)。

付録:JMX デフォルトの MBeans の監視

MBeansを通じてエクスポートされるクラスのプロパティは属性と呼ばれ、MBeansを通じてエクスポートされるメソッドは操作と呼ばれます。

MBeans と属性の集合体がありますが、これらはすでに Java プラットフォームによって提供されています。独自のメトリクスを作成する前に、これらのクラスから収集できるパフォーマンスとトラブルシューティング情報を見てみましょう。

LoadedClassCount

MBean: java.lang:type=ClassLoading

これは現在JVMにロードされているクラスの数です。

この数が増え続ける場合、複数のクラスローダが異なる時間に同じクラスをロードすることに問題がある可能性があります。

TotalLoadedClassCount

MBean: java.lang:type=ClassLoading

これは、JVMが起動してからロードされたクラスの数です。

UnloadedClassCount

MBean: java.lang:type=ClassLoading

クラスは、それらをロードしたクラスローダがガーベージコレクトされたときにアンロードされます。これは、JVMが起動してからアンロードされたクラスの数です。

TotalCompilationTime

MBean: java.lang:type=コンパイル

TotalCompilationTimeは、JITのコンパイルに費やした時間をミリ秒単位で累積したものです。これは、シナリオの JIT パフォーマンスを監視するために使用できます。

Garbage Collector - CollectionCount

MBean: java.lang:type=GarbageCollector,name=[あなたのGC名]です。

これは、JVMが起動してから発生したガベージコレクションイベントの数です。

ガベージコレクタ - CollectionTime

MBean: java.lang:type=GarbageCollector,name=[あなたのGC名]です。

CollectionTimeは、ミリ秒単位でのガベージコレクションの実行に費やされた時間の合計で、Javaアプリケーションの動作をプロファイルするためのもう一つの良い候補です。

4.png

Sysdig MonitorでJava GCの収集時間(PS Scavengeアルゴリズム)を監視する。

Garbage Collector - LastGcInfo

MBean: java.lang:type=GarbageCollector,name=[あなたのGC名]です。

LastGcInfoは、以下のデータで実行された最後のガベージコレクションイベントに関する情報の構造体です。

GcThreadCount

GCを実行したスレッド数

durarion

GCイベントの合計期間

startTime

JVMが起動してからの起動時間(ミリ秒単位)

endTime

JVMが起動してからの終了時間(ミリ秒単位

memoryUsageBeforeGc

イベント前にコミットされたメモリ、初期メモリ、最大メモリ、使用済みメモリに関する情報の構造

memoryUsageAfterGc

イベント後にコミットされたメモリ、初期メモリ、最大メモリ、使用済みメモリに関する情報の構造

Arch

MBean: java.lang:type=OperatingSystem

プロセッサのアーキテクチャ。

AvailableProcessors

MBean: java.lang:type=OperatingSystem

利用可能な中央処理装置の数。

CommittedVirtualMemorySize

MBean: java.lang:type=OperatingSystem

これは、JVMが使用可能であることが保証されているメモリ量(バイト単位)を表します。

FreePhysicalMemorySize

MBean: java.lang:type=OperatingSystem

これは、ホスト内の空き物理メモリのメモリ量を表します(free = total - (used + shared + cached + buffered) )。

MaxFileDescriptorCount

MBean: java.lang:type=OperatingSystem

これは、オペレーティングシステムによって決定される、同じプロセスで開くことができるファイル記述子の数です。この数以上のファイルディスクリプタを持つことはできません。

OpenFileDescriptorCount

MBean: java.lang:type=OperatingSystem

これは現時点で開いているファイルディスクリプタの数で、これがMaxFileDescriptorCountに達するとアプリケーションはIOExceptionをスローします。開いているファイルが多すぎます。これは、ファイルディスクリプタを開いているのに閉じていないことを意味します。この変数を監視し、MaxFileDescriptorCountの値に近づいた場合に警告を出すことができます。

FreeSwapSpaceSize

MBean: java.lang:type=OperatingSystem

FreeSwapSpaceSizeは、ホストで利用可能なスワップメモリの量(バイト単位)です。

ProcessCpuLoad

MBean: java.lang:type=OperatingSystem

ProcessCpuLoadは、このプロセスのCPU負荷を表します。

ProcessCpuTime

MBean: java.lang:type=OperatingSystem

これは、CPUがこのプロセスを実行するのに費やした時間です。

SystemCpuLoad

MBean: java.lang:type=OperatingSystem

ホストシステムのCPUの現在の負荷を表します。

SystemLoadAverage

MBean: java.lang:type=OperatingSystem

ホストシステムの平均負荷を表します。コマンドで与えられた値と一致します: cat /proc/loadavg | awk '{print $1}'

TotalPhysicalMemorySize

MBean: java.lang:type=OperatingSystem

ホストのメモリサイズをバイト単位で指定します。

TotalSwapSpaceSize

MBean: java.lang:type=OperatingSystem

ホストのスワップメモリサイズをバイト単位で指定します。

Version

MBean: java.lang:type=OperatingSystem

ホストのカーネルバージョン。uname -r で指定された値と一致します。

InputArguments

MBean: java.lang:type=Runtime

InputArgumentsは、JVMが起動された引数の配列です。

SpecVersion

MBean: java.lang:type=Runtime

SpecVersion は JVM のバージョンを表します。

StartTime

MBean: java.lang:type=Runtime

JVMがUnix Epoch形式で起動した時刻。

Uptime

MBean: java.lang:type=Runtime

JVMが実行されているミリ秒数。

DaemonThreadCount

MBean: java.lang:type=Threading

実行しているデーモンのスレッド数。

PeakThreadCount

MBean: java.lang:type=Threading

JVMが起動されてから、またはピークがリセットされてから、同時に実行されているスレッドの最大数。このメトリック(次の2つと同様に)は、Javaアプリケーションの動的な動作を監視し、プロファイリングするのに役立ちます。

ThreadCount

MBean: java.lang:type=Threading

TotalStartedThreadCount

TotalStartedThreadCount

MBean: java.lang:type=Threading

JVMが起動してから開始されたスレッドの数です。

ご質問・お問い合わせはこちら

top