BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース Zing 4.0よりも性能が80%向上したAzulのJava向け仮想システムZing 4.1

Zing 4.0よりも性能が80%向上したAzulのJava向け仮想システムZing 4.1

ブックマーク

原文(投稿日:2011/05/25)へのリンク

Azul SystemsはGartnerが挙げた2011年の“優れたアプリケーションと統合プラットフォームベンタ”5社のうちの1社だ。同社はJava向け仮想システムであるZingのバージョン4.1を発表した。このバージョンでは前バージョンの4.0より性能が80%以上改善されていると言う。Azul Systemsのバイスプレジデント兼CTOであるGil Tene氏はこの80%という数値について、私たちがここで紹介したLiferayを使ったテストに基づいていると説明した。以前のテストでは800のプログラムが実行でき、秒当たり3.5GBの不要メモリを扱うことができた。Zing 4.1では1500のプログラムが実行できる。氏によればZingのガベージコレクタであるContinuously Concurrent Compacting Collector、別名C4は秒当たり5.5GBの不要メモリを性能劣化することなく扱える。同じハードウエアを使った場合、Oracleが配布する標準的なJVMは、Concurrent Mark Sweepガベージコレクタが動いている間に実行できるプログラムの数は約45だ。Oracleはガベージコレクションを気にしなければならないアプリケーションではこのガベージコレクタの利用を推奨している。

いつもは即時に返ってくる処理が、JVMやその下のシステムスタックがTene氏のいう'ジッタ'な状態になっているとき遅延が発生してしまう。C4の最近のアップデート版ではJVMのジッタはスケジューリングしたりスレッド競合を管理することでガベージコレクションに大きく影響しないようになった。

Zing 4.0からZing 4.1への改善は複数の改良の結果だ。ジャストインタイムコンパイルの改良や、スレッドスケジューリングの強化、性能と持続可能なスループットの向上と返答時間の短縮を実現する先進的なアルゴリズムなどが改善をもたらした。同社が利用している性能改善技法の一例は、読み取りバリア("Loaded Value Barriers"、またはLVBと言われる)の改善だ。LVBは並列コンパクションや再マッピング、更新の追跡などをサポートするためC4アルゴリズムで使われている。例えばオブジェクトの配列を複製する場合、複製される要素の値はLVBである必要があるが、複製元アドレスも複製先アドレスも一度以上LVBになる必要はない。氏曰く、

このパターンは文字列の比較やもっと一般的に書かれるコードでも見られます。配列の内容にアクセスする場合はこれをひとつひとつの要素に対して行います。アクセスにはアクセサメソッドを使います(つまりアクセサを呼び出す毎に配列をLVBにする必要があります)。しかしループ内にインライン展開するアクセサメソッドとループ内でのLVBが冗長であるということが正確に理解できれば、最適化してLVBを一度で済むようにして、ループの外に引き上げることができるはずです。

また、null比較もひとつの例です。nullでない値を検出するコードは頻繁に見つかります。多くの場合、コードは参照(配列やリストなど)をロードして、nullと比較し、nullでなければ先へ進みます。LVB化せずに参照がnullかどうかを判定できると分かれば、すべてのnull参照のLVB化を防げます。LVB化はnullチェック(スパース構造がほとんどのLVBを除去する)を通過した参照にだけ発生します。

また、セーフポイントの扱いも少し手を入れました。スレッドがスタックを読み取ったり、"フィックス"するために必要な参照を修正したりするためのセーフポイントを越えずに先へ進みたくはありません。スレッドがこの一線を"手軽に"越えなければGCは進化できません(私たちのチェックポイントの仕組みもこのセーフポイントを利用しています。コードはセーフポイントに到達するとブロッキングコードになります。スレッド自身が読み取りをできない場合、GCはこのタイミングでスレッドの読み取りを行います)。大きな配列の複製も適度なセーフポイントを持つようにしたいと思っています。しかし、各反復処理でセーフポイントが発生する必要はありません。例えば、セーフポイントの間に256の要素を持つ配列を複製できればいいのです。

これを実現するのに重要なのは(これはすべてのGCの仕組みに言えることですが)スタック上のオブジェクト参照の値はセーフポイントを越えると変更ができる(例えば、ParallelGCのようなStop-The-World方式のGCの場合、セーフポイントまで実行して、参照を新しいロケーションを指すように変更することがあります)ということです。つまり、さまざまな処理や最適化の中では読み込まれた参照は完全に定数として扱われるわけではありません。例えば、現在の参照のアドレスが他の参照の現在のアドレス"より大きい"場合、この両者の関係はセーフポイントを越えると変わる可能性があります。したがって最適化を行う場合、この"より大きい"という関係を前提とした安全なコードは書けません。

しかし、ふたつのセーフポイントの間なら参照は"そのままでは"変わりません(つまり、スタック上のオブジェクト参照の値が変わる心配をしなくていい)。参照はメモリから読み込まれます。また、スレッドの命令によって上書きされたりします。しかし、アドレスが変更されることはありませんし、スレッド自身が変更をしたとき、イベントは発生しません。このようにふたつのセーフポイントの間でなら参照を定数として扱えることでさまざまな最適化が実施できます。冗長な処理を取り除いたり定数であることを利用した最適化ができるのです。

同社はZingのデフォルトの振る舞いも改善した。ガベージコレクタの設定を調整しなくても以前のバージョンより幅広く処理を行うようにしたのだ。スムースに処理できる領域が4.0より1.5から2倍もが広がったと氏は言う。

Zing 4.1は基盤となる仮想化技術の改善も大きな効果があった。例えば、Red Hat Enterprise Linux (RHEL) 6.0上の仮想環境で動作しているJVMは現在は64ものコアをサポートする。氏曰く、

RHEL 5.x上のKVMはゲストOS(Zing仮想化アプライアンス)向けに16の仮想コアをサポートします。RHEL 6上のKVMは64の仮想コアをサポートします。RHEL 6自体のホスト環境は256コアまでです。現代のIntel E7ベースのサーバなら、4ソケットサーバ(Dell/HP/IBM/...などの)で40の物理コアを持ち、80のハイパースレッド(つまり、ホスレベルの仮想コア)を持ちます。8ソケットのE7システム(HPが出荷している)80の物理コアと160の仮想コアを持ちます。

氏はシンプルだが独創的なオープンソースのツールを作った。これはクライアントとJavaアプリケーションのノードの間の遅延を計測するためのツールでJitterMeterと呼ばれている。JitterMeterはスレッドは1ミリ秒スリープさせ再起動にどの程度かかるかを計測する。1ミリ秒ちょうどの完全な停止とその後の経過時間の差異が明確に計測できる。このウェビナーでより詳しい説明が見られる(登録が必要)。

JitterMeterはシンプルなオープンソースツールで、どんなJavaアプリケーション、JVMでも利用できます。このツールはアプリケーションの応答速度に基盤のプラットフォームがどの程度貢献しているのかを確認できます。JVMにアプリケーションがロードさているときに空の処理を実行して検出されるジッタを計測することで、JitterMeterはアプリケーションに発生する、プラットフォームに起因するジッタ(JVM、OS、仮想環境、ハードウエアなどに起因する)を検出します。コードや配置の変更、負荷の計測のような一般的な方法は必要ありません。このツールが提供する情報はアプリケーションの応答時間の問題の原因を調べるのに有用です。開発者はや性能担当エンジニアそれぞれの分野の仕事に専念できます。例えば、プラットフォームのジッタが少ない(10ミリ秒程度)の場合、アプリケーションのコードや振る舞いに注力して性能改善する方がいいでしょう。アプリケーションのジッタがプラットフォームの原因の場合(JitterMeterではよく検出されます)アプリケーションのコードのチューニングは行わずに、プラットフォームの調整に注力したほうがいいでしょう。JitterMeterを使えばとても簡単に観察できます。独立したJavaスレッドでの空の処理で遅延のよる"一時的な停止"を検出したなら、どんな理由であれ(2秒のGCによる停止、1/2秒の仮想環境のVMotionイベント、スケジューリングのオーバヘッドによる遅延)そのJVMで動作しているほかのJavaスレッドでも同じ大きさの"一時的な停止"が発生していると考えた方がいいでしょう。そしてアプリケーションの応答時間は、最低でもその空の処理の計測結果と同じくらいになるはずです。空の処理から検出した応答時間の分布のヒストグラムを詳細にレポートすることでJitterMeterは、すなわち同じ時間、同じシステム上でアプリケーションのトランザクションが経験しているジッタの分布図を作成します。

私たちの経験ではJavaアプリケーションの応答時間の分布は"マルチモデル"になる傾向が強いです。つまり、複数のピークがあり、多くの人が考える普通の分布図とは全く似ていません。普通、応答時間が良い場合は同じような分布図になります("典型値"、"代表値"、"平均値"、そして90%'ileはすべてこの同じような傾向の中に収まります)。その場合は集中して応答時間が上がる"最頻値"があります。分布の一番下の10ミリ秒はOSのスケジューリングに関係します。仮想環境は下の10ミリ秒から100ミリ秒です。分布の上限のはっきりと応答時間がおかしいのが分かる部分は、普通はGCに関係があります。GCの小さなイベント(新世代のコレクションのような)が100ミリ秒くらいの範囲で関わっています。数秒単位で関わっているのはFull GCイベントやpermgenのコレクション、プロモーションの失敗が関わっています。分布の上の方ほど、発生頻度は少ないですが、どれも数分間に発生する、2秒から5秒もかかるイベントです。どれもアプリケーションチューニングの専門家を悩ませます。

Zing 4.1は来週出荷される。値段は変更せず、サーバ単位の年次のサブスクリプションで決まる。無料トライアルはwww.azulsystems.com/trialから手に入る。

この記事に星をつける

おすすめ度
スタイル

BT