KVM上のJavaが異様に遅い!? そんなときは

以前、Java のWebアプリケーションサーバ ( Apache Tomcat ) をKVMゲスト上に構築した際に、パフォーマンスが非常に悪い状態になった事があります。
その際に問題を解決するに至った方法に関して書いてみます。

はじめに

弊社は社内サーバの多くを仮想環境 (KVM) 上に構築して利用しています。
アイコン認証Webサービス 等を動作させるための Java のアプリケーションサーバもKVMゲスト上で動作させているのですが、以前

「遅い 実に! 遅いぞ」

という事がありました。
別の仮想マシンで動作していたPHPのオープンソースCMSと比べても、体感で20倍は動作が重い感じです。

アプリケーションサーバとしては Apache Tomcat、DBにはMySQLを利用していたのですが、これらのチューニングを行っても、一向に改善する様子はありませんでした。

結果的には KVM の設定を変更する事で、この問題は解決するに至りました。


※今回も 写真素材ぱくたそ 様から画像素材を頂きましたが、ゾンビじゃなくなってしまった orz

解決策

色々と解決策を探ってWeb上で同様の問題がないか探していたのですが、以下のページがヒントになりました。

Slow performance on VMWare Linux server after Tomcat install

Java tends to confuse the VMWare memory management systems, as it adds yet another layer of memory management.

There is a KB article, linked below. But the key one is to size the reserved VM memory (not just the VM memory size) to be >= to the memory of Java (tomcat).

http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1008480

超意訳すると、「VMWareのメモリ管理とJavaのメモリ管理は相性が悪い。
仮想マシンのメモリサイズはJava ( Tomcat ) のメモリサイズより大きくしとけ!」

って感じの事が書いてあります。

VMWare に関しての内容ですが、仮想化環境全般で同様の事が言えるのではないかと考え、問題が発生している環境でもパラメータの調整を行ってみました。

変更前の状態

Javaの開発者ならご存じでしょうが、Javaプログラムは Java VM上で実行されます。
JavaVMは独自にメモリ管理を行っており、メモリサイズに関しては起動時にオプションで指定可能です。
このとき、使用メモリサイズを動的に変更可能な形で設定する事もできます。(初期サイズ、及び、最大サイズを指定可能)

パフォーマンスに問題があったとき、KVMゲスト ( 仮想マシン )、及び、JavaVMのメモリ設定は以下のようになっていました。

KVMゲストCurrent allocation256MB
最大割り当て1024MB
JavaVMヒープ初期256MB
ヒープ最大512MB

上記のように設定した理由ですが、以下のようになると思っていたからです。

  • JavaVMはTomcatサーバ ( 上で動作するWebアプリケーション含む ) の状態に応じてメモリ管理を行う
  • KVMゲストのメモリも適切に管理される。JavaVMのメモリ使用量が増加した場合、KVMゲストのメモリもこれに応じて適切な量に調整される。

しかし、実際にはKVMゲストのメモリサイズが適切に調整される事はなく、スワップが発生してパフォーマンスが悪化していたものと思われます。

変更後の状態

前述のヒントを参考に、仮想マシン、及び、JavaVMのメモリ設定を以下のように変更。

KVMゲストCurrent allocation512MB
最大割り当て512MB
JavaVMヒープ初期256MB
ヒープ最大256MB

仮想マシンのメモリ設定変更は仮想マシンマネージャを使うのが簡単です。
( 要仮想マシンのシャットダウン )

Apache Tomcat の設定は以下のような感じにしました。
メモリ設定変更後、Tomcat は必要に応じて再起動します。

# set java environment variables.
export JAVA_HOME=/usr/java/default
export JAVA_OPTS="-server -Xms256M -Xmx256M"
export CATALINA_OPTS="-server -Xms256M -Xmx256M"

結果

上記設定変更を行う事で、パフォーマンスは劇的に改善されました。

この時はアイコン認証Webサービスでパフォーマンス検証を行っていたのですが、上記 PHP 製の CMS と比べてもサクサク動作するようになりました。

まとめ

上述の変更前状態における私の考え

「仮想環境、及び、JavaVM の双方が上手い事連携してメモリ管理をしてくれる ( 多分 ) 」

というのは、私の思い込み ( = 期待 ) に過ぎなかったという事です。

 

Java のアプリケーションを仮想環境で動作させた場合に、

  • 異様に遅い
  • 想定していたパフォーマンスが全然でない

といった場合、メモリ管理機能が上手く動いていないかもしれません。
こういった場合、仮想環境、及び、JavaVMのメモリ設定を見直す事で解決するかもしれません。