Presentation is loading. Please wait.

Presentation is loading. Please wait.

部分的再ロードによる Java プログラムの再起動の高速化手法

Similar presentations


Presentation on theme: "部分的再ロードによる Java プログラムの再起動の高速化手法"— Presentation transcript:

1 部分的再ロードによる Java プログラムの再起動の高速化手法
数理・計算科学専攻 千葉研究室 09M37264 別役 浩平 指導教員 千葉 滋 教授

2 Java プログラムの再起動 アプリを JVM 上に再ロード、再実行 HOT deploy アプリケーションサーバや DI コンテナで利用
例)JBoss AS、Seasar2 HOT deploy サーバを稼働させたままコンポーネントを再配備 例)リクエストの度にアプリを再ロード 対話的な開発に有用 本研究において Java プログラムの再起動とは、アプリケーションを再ロードして再び実行し直すという一連の動作を表しています。この技術は Jboss アプリケーションサーバや Seasar2 のような DI コンテナで Hot deploy として利用されています。Hot deploy とはサーバを稼働させたままコンポーネントを自動的に再配備させる技術です。この技術を用いてユーザからのリクエストの度にアプリを再ロードすることで対話的な開発ができるため開発効率が向上します。

3 修正したアプリケーションの再ロード 新たに作成したクラスローダでロード 全クラスを再ロード 同じローダで同一名のクラスの再ロード不可能
サーバのパフォーマンスを低下させる HealthWatcher [Greenwoodら ‘07] を使った実測値 Java 言語では同じクラスローダを用いて同一名のクラスを再ロードできないため、Hot deploy が行っているように修正したアプリケーションを再ロードするには、新たに作成したクラスローダでアプリケーションをロードし直す必要があります。Java の HotSwap という技術を用いれば同じクラスローダで同一名のクラスを再ロードすることができますが、メソッドボディしか定義を変更できないという制限があります。先ほど述べたようにリクエストの度にアプリケーションを再ロードすれば対話的な開発が可能ですが、毎回全クラスを再ロードするためサーバのパフォーマンスを低下させるという問題があります。このグラフは HeatlhWatcher という Web アプリケーションの平均応答時間を測定した結果です。リクエストの度にアプリケーションを再ロードした場合はそうでない場合に比べて 20 倍以上遅いため、実用的でないといえます。 リクエストの度に 平均応答時間(ms)

4 ロード済みクラスの再利用 ローダは親ローダにクラスのロードを委譲可能 クラスのロード手順
親ローダがクラスをロード済みなら子ローダは ロードせずに済む クラスのロード手順 自身でロード済みならば、そのクラスを使用 独自の探索方法でクラスを探索する 親ローダの loadClass メソッドを呼び出す このように全クラスを何度も再ロードするとプログラムの実行速度が低下するので、ロード済みのクラスを再利用する必要があります。Java の全てのクラスローダは親子関係を持っていて、親ローダにクラスのロードを委譲することができます。そして、委譲された親ローダがそのクラスを既にロード済みならば子ローダはロードせずにそのクラスを利用することができます。子クラスローダに JVM からクラスのロード要求があった際、このような手順で親クラスローダのクラスを再利用します。まず、自身でクラスをロード済みならばそのクラスを使用します。次にそのクラスローダに定義された探索方法でクラスを探します。そして、その他のクラスは親ローダでロード済みのものを再利用します。

5 再ロードするクラス数の削減法 変更したクラスと依存しているクラスのみを 新ローダでロード 旧版アプリの部分的な再利用
手法 1 変更したクラスと依存しているクラスのみを 新ローダでロード その他は親ローダでロード済みのクラスを再利用 旧版アプリの部分的な再利用 アプリのロードを複数ローダに分割 ロード済みのクラスを出来るだけ再利用 アプリの再起動を高速化 手法 2 本研究では、このクラスローダのアーキテクチャを利用して再ロードするクラス数を削減し、再起動を高速化する 2 つの手法を提案します。1 つ目の手法は、変更したクラスと依存しているクラスのみを新たに作成したクラスローダでロードし直し、その他のクラスは親ローダでロード済みのクラスを再利用する手法で、2 つ目の手法は、変更したクラス毎にそれをロードするクラスローダを作成し、それらを後の再起動時に部分的に親ローダとして活用する手法です。これらの手法を用いて、できるだけロード済みのクラスを再利用することでアプリケーションの再起動を高速化します。

6 依存しているクラスもロード クラス内の参照はそのクラスをロードした ローダが動的に解決 シンプルな実装では期待する動作は得られない 手法 1
クラス内の参照はそのクラスをロードした ローダが動的に解決 シンプルな実装では期待する動作は得られない A は親がロードした B を参照 A B C アプリの 開始ノード アプリの 開始ノード 手法 1 では変更したクラスだけでなく、それに依存しているクラスを子クラスローダでロードし直し、その他のクラスは親クラスローダでロード済みのものを再利用します。なぜ依存しているクラスもロードする必要があるかというと Java にはクラス内の参照はそのクラスを定義したクラスローダが動的に解決するという仕様があるためです。これを図を使って説明します。まず、クラス B の定義を変更し子クラスローダでロードし直したとします。しかし、クラスローダの仕様から A 内の参照は親ローダによって解決されるため変更された B は参照されず親ローダでロード済みの B が参照されてしまいます。これでは B への変更をアプリケーションに反映することができません。そこで B に依存しているクラスである A も子クラスローダでロードすれば A 内の参照は子クラスローダ自身で解決されるため、変更した B を参照することができます。 変更したBは 参照不可 変更したBを 参照可能 A B B A は変更した B を参照

7 旧版アプリの部分的な再利用 前提 アイデア 手法 2 各クラスに異なる機能を実現する複数の版がある
各クラス異なる版の組み合わせで何度も再起動 例)クラス A は版 1、クラス B は版 2 で再起動    次は A は版 2、B は版 1 で再起動 ユーザによるヒント どのクラスの版を変更するか アイデア クラスの版毎にクラスローダを作成 再起動時に親ローダとして活用 特定の条件下では手法 1 よりもさらに再ロードするクラス数を削減することができます。前提条件として、アプリケーションの各クラスに異なる機能を実現する複数のバージョンがあるということ、そして各クラスのバージョンの組み合わせを変えて何度も再起動する状況であるということ、例えば、クラス A はバージョン 1、クラス B はバージョン 2 で再起動し、次は A はバージョン 2、B バージョン 1 で再起動するといった状況です。そして、最後にどのクラスを変更するかというユーザによるヒントがあるという状況です。このような状況下ではクラスのバージョン毎にそれをロードするクラスローダを作成し、再起動時にそれらを部分的に親ローダとして活用することでロード済みのクラスを再利用することができます。

8 再起動時に使用する子ローダの作成 (1) クラスの版の集合とそれぞれの優先度 アプリケーションを再ロードするクラスローダ
手法 2 再起動時に使用する子ローダの作成 (1) 入力 クラスの版の集合とそれぞれの優先度 優先度は事前に計算しておく 例 1)クラスの版と依存するクラスのサイズの合計 例 2)クラスの版の利用されやすさ アプリケーションを再ロードするクラスローダ 旧版アプリのローダ群を親ローダとして活用 出力 次に手法 2 において再起動時にどのようにクラスローダを作成し、どのクラスローダに再ロードさせるかについて説明します。このアルゴリズムの入力は、再起動時に使用するクラスのバージョンの集合とそれぞれの優先度です。優先度は事前に設定し、計算しておきます。例えば、クラスのバージョンとそれに依存しているクラスのファイルサイズの合計であるとか、そのクラスのバージョンの利用されやすさなどを優先度として用います。出力はアプリケーションを再ロードするクラスローダで、既存のクラスローダ群をできるだけ親ローダとして活用します。

9 再起動時に使用する子ローダの作成 (2) [初期状態] システムクラスローダ1個 原版クラス(A0、B0、C0、…)をロード済み 手法 2
System Aの版 1 をロード B2 B2、E3は親に依頼 B2は親に依頼 入力 B2、E3、C1 (優先度: B2 > E3 > C1) B2、E3、D2 (優先度: B2 > E3 > D2) B2、A1 (優先度: B2 > A1) 例を使ってどのようにクラスローダを出力するかを説明します。初期状態はシステムクラスローダ 1 個でオリジナルのアプリケーションのクラスを全てロード済みであるとします。まず、クラスのバージョン A1 、B2 を再起動時に用いるとき、優先度が B2 の方が高いとすると、この図のように B2 をロードするクラスローダを親に A1 をロードするクラスローダを子にして、アプリケーションを再起動します。次に、B2、E3、D2 を使うとすると、B2 をロードしたローダを親ローダとして活用し、E3 をロードするローダ、D2 をロードするローダの順にクラスローダを作成し、アプリケーションを再起動します。こうすることで B2 のロードを省略することができます。そして、B2、E3、C1 を用いるときは、B2、E3 をロードしたローダを親ローダとして活用し、C1 をロードするローダを新たに作成します。先程と同様に B2、E3 のロード省略することが出来ます。 A1 E3 出力 D2 C1 出力 出力

10 優先度による再ロードするクラスの削減 例) 各クラスに依存しているクラス数
手法 2 優先度による再ロードするクラスの削減 例) 各クラスに依存しているクラス数 A1 = 52、B2 = 38、C1 = 27 (優先度 A1 > B2 > C1) 依存しているクラス数 System System 52 38 入力 B2 A1 A1 B2 A1、C1 B2、C1 次に、優先度を設定することでどの程度再ロードするクラスを削減することが出来るかについて例を使って説明します。クラスのバージョン A1、B2、C1 に依存しているクラスをそれぞれ 52、38、27 とし、それを優先度とします。図の右側が優先度順にクラスローダを作成した場合、左側がそうでない場合です。この状況下でB2、C1 を用いて再起動とすると、左側では B2 をロードするローダを親ローダとして活用することが出来、C1 をロードするクラスローダを作成します。この時再ロードするクラスは 27 です。右側では B2 をロードするクラスローダを活用できないため B2、C1 をロードするローダをそれぞれ作成します。再ロードするクラスは 65 となります。次に、A1、C1 を用いて再起動とすると、左側では A1 をロードするクラスローダを活用できないため A1、C1 をロードするローダをそれぞれ作成します。再ロードするクラスは 79 で累計 106 クラスとなります。右側では A1 をロードするローダを親ローダとして活用することが出来、C1 をロードするクラスローダを作成します。再ロードするクラスは 27 で累計 92 クラスとなります。このように優先度どおりにクラスローダを作成した方が再ロードするクラス数が少なくなります。これは簡単な例ですが、要は優先度どおりにクラスローダを作成した場合もそうでない場合も次回再起動時に利用できる親ローダの期待個数は同じですが、優先度どおりに作成した場合の方がより多くのクラスをロード済みのローダを親として活用できるということです。 27 27 27 27 C1 A1 C1 C1 B2 C1 27 + 79 = 106 65 + 27 = 92 再ロードするクラス数

11 クラスの版毎のクラスローダ 各ローダがロードするアプリは異なる ローダ L がロードするクラス群 S クラス間の依存関係も異なる 手法 2
あるクラスの版 C と C の原版に依存しているクラスの集合を SC と表現する ローダ L がクラスの版 C をロードをするとき、S ← SC L の全ての親ローダについて、 親ローダがロードするクラスの版 D が S 内のクラスに参照を持つとき S ← S + SD とする 手法 2 において各バージョン毎に作られるクラスローダでは、そのローダがロードするクラスのバージョンとそれに依存しているクラス群をロードさせます。しかし、各クラスローダがロードするアプリケーションは異なるため、それぞれの依存関係を考慮して、クラスローダがロードするクラス群を決定する必要があります。クラスローダ L があるクラスのバージョン C をロードする時、初期値として SC を与えます。SC とは C と C の原版に依存しているクラスの集合です。そして、L の全ての親ローダについてしらべ、親ローダがロードを担当するクラスのバージョン D が S 内のクラスに参照を持つ時、S に SD を追加します。オリジナルのアプリケーションの依存関係はあらかじめ調べておけるので、クラスローダがつくられる度にこのように部分的に依存関係を修正していきます。

12 応用:Per-session AOP フレームワーク
手法 2 応用:Per-session AOP フレームワーク [戸部ら ’08] ユーザ毎に機能が拡張された Web アプリを実現 リクエストの度にクラスローダの作成 ユーザが選択した機能を実装したクラスの版で置換 全クラスを再ロード 例)iGoogle 手法 2 の応用例として per-sessin AOP フレームワークがあります。このフレームワークではリクエストの度にクラスローダを作成し、ユーザが選択した機能を実装するクラスのバージョンでそのクラスを置換し、ロードし直すことで、ユーザ毎に拡張された Web アプリケーションを実現しています。しかし、リクエストの度にアプリケーションの全クラスを再ロードするため、パフォーマンスの面で問題があります。 Per-session AOP フレームワークは例えば iGoogle のようなユーザ毎に見栄えや機能が拡張された Web アプリケーションや、 見え方や機能が異なる リクエスト サーバ ユーザ

13 大規模ホスティングサービス 例)ショッピングサイト サイト(各サイトのユーザ全体)毎に機能を拡張 フレームワークの適用例 サイト A
サイト B ホスティングサービスに利用できると考えています。この例では、サービスベンダーが基本機能のみを備えたアプリケーションを提供し、サイト運営者がクラスを追加したり、ベースアプリのクラスを変更するなど独自の拡張をします。サイトのユーザからリクエストがきた際には、その URL などのサイト固有の識別子毎にクラスローダを作成し、この例で言うところの赤の点線部分をロードし、アプリを実行します。各サイト毎に Web アプリケーションを起動するという方法でもこのようなサービスは実現できますが、一つのベンダーを多くのサイトが利用する場合、非常に多くのリソースを消費してしまうので、クラスローダを切り替える手法が有効であるといえます。 追加したクラス 異なるローダでロード ベースアプリ サーバ サービスベンダー

14 手法 1 と手法 2 の比較 例)1 回目は A1、B1、C0 を用いて再起動 2 回目は A1、B0、C1 を用いて再起動 System
次に、手法 1 と 2 の特徴を比較したいと思います。例として、1 回目の再起動では A1、B1、C0 を用いて再起動、2 回目は A1、B0、C1 を用いて再起動する状況を考えます。1 回目の再起動で手法 1 では A1 と B1 とそれらに依存しているクラスをロードするクラスローダを作成します。手法 2 では A1、B1 毎にクラスローダを作成します。2 回目の再起動で手法 1 では 1 回目に作成したクラスローダが B1 をロードしてしまっているため、親ローダとして活用できません。そこで、A1 と C1 をロードするクラスローダを新たに作成しなおす必要があります。一方、手法 2 では分割してクラスローダを作成しているため、A1 をロードするクラスローダを親ローダとして活用することが出来ます。結果として、再ロードするクラス数は手法 1 の方が多く、作成されるクラスローダインスタンスの数は手法 2 の方が多くなります。再ロードするクラス数は手法 2 の方が必ず少なくなりますが、多くのクラスを変更する場合にはクラスローダの作成コストにより、手法 2 の方が遅くなる可能性があります。 C1 C1 B1 再ロードするクラス数 : 手法 1 > 手法 2 クラスローダ数 : 手法 1 < 手法 2

15 実験 フレームワークに提案手法をそれぞれ実装 全クラスを再ロード(手法 0)、手法 1、手法 2
実験環境 Client マシン OS : Windows Server 2003 CPU : Core 2 Duo 3.00 GHz Memory : 4 GB Server マシン OS : Linux CPU : Xeon 2.83 GHz Memory : 4 GB 実験 フレームワークに提案手法をそれぞれ実装 全クラスを再ロード(手法 0)、手法 1、手法 2 HealthWatcher を動作(100 ユーザ) 健康管理用 Web アプリ(9 KLOC) アプリの各クラス用に新版を 1 つ用意 新版と原版の 2 バージョンを持つ 優先度 クラスの版と依存しているクラスのサイズ × 版の利用者数 これを検証するために、リクエストの度に全クラスをロードする場合を手法 0 として、3 つの手法を per-session AOP フレームワークにそれぞれ実装して、その上で動作する Health Watcher アプリケーションにリクエストを送る実験を行いました。Health Watcher とは 9000 行程度の健康管理用 Web アプリケーションです。アプリケーションの各クラスに新版を 1 つ用意しました。つまり、各クラスには拡張された新版と原版の 2 つのバージョンが存在する状況です。またクラスの版の優先度は、クラスの版とそれに依存しているクラス群のファイルサイズの合計に、その版の利用者数をかけたものとしました。実験環境はこのようになっています。

16 新版クラスの選択パターン 選択パターン(n, m)毎に平均応答時間を測定 例)実験(2, 5) n … Servlet クラスの新版の選択数
さらにフレームワークの各実装において新版クラスの選択パターンごとに平均応答時間を測定しました。新版クラスの選択パターン(n、m)の n とは Web アプリの Servlet クラスの新版の選択数、m はそのコールグラフ上にあるクラスの新版の選択数です。例えば、実験 (2、5) では全ユーザが Servlet クラスの新版からランダムに 2 個選び、さらにそのコールグラフ上のクラスの新版から 5 個ランダムに選んで平均応答時間を測定します。選択パターンをこのように定義したのは、Web アプリのメインロジックを担う Servlet のクラスが最も変更されやすく、次いでそのコールグラフ上のクラスが変更されやすいと考えたからです。 D B A C E H G I F Servlet

17 平均応答時間(手法 2)と新版クラス使用数 新版クラス使用数 = n + m 平均応答時間は変更されるクラス数に比例
横軸:新版クラスの選択パターン 平均応答時間で昇順にソート 手法 2 の実験結果です。左のグラフは平均応答時間の測定結果で、縦軸は平均応答時間、横軸は新版クラスの選択パターンです。このグラフでは平均応答時間の短い順に横軸の新版クラスの選択パターンをソートしています。以後のグラフはこの横軸に対応するようにソートしています。右のグラフは新版クラスの使用数です。このグラフから平均応答時間は新版クラスの使用数、つまり変更されるクラス数に比例することがわかります。 新版クラス使用数 (線形回帰直線)

18 3 つの手法の平均応答時間の比較 どの選択パターンでも手法 1 と 2 は手法 0 より高速
手法 1 と 2 は選択パターンによって使い分ける必要 このグラフは、3 つの手法の平均応答時間を比較したグラフです。ほぼどの選択パターンにおいても手法 0 より手法 1 と 2 の方が高速であり、パフォーマンスを改善できていることが分かります。手法 1 と 2 ではいくつかの選択パターンにおいて手法 1 の方が早くなる場合があるため使い分ける必要があります。 手法 0 (線形回帰直線) 手法 1 (線形回帰直線)

19 手法 1 と手法 2 の使い分け ほとんどの選択パターンで手法 2 が高速
新版クラス使用数が 56 個(全クラスの 76%)以上の とき手法 1 が高速 但し、n << m のときは手法 2 が高速 56 手法 1 の平均応答時間 (線形回帰直線) このグラフは新版クラスの使用数のグラフに手法 1 と 2 の平均応答時間を重ねたものです。グラフ上の点は新版クラスの使用数を表しています。手法 1 と 2 の優劣が分かれる交点における新版クラスの使用数は 56 個であり、これは Health Watcher 全クラスの内の 76 %を変更しているときでした。これ以上のクラス数を変更するときは手法 1 の方が高速であるとわかりました。但し、グラフの左上の領域に着目すると新版クラスの使用数が多いにも関わらず、平均応答時間が短い場合があります。これらのほとんどが n に対して m が非常に大きい時でした。 手法 2 の平均応答時間 新版クラス使用数 新版クラス使用数 (線形回帰直線)

20 n << m の状況 例)(n、m) = (1、5) n … Servlet クラスの新版の選択数
A A A A G G G G D D D D I I I I この状況を図を使って説明します。一般にアプリケーションのコールグラフには多くの共通部分があります。例えば、(n、m) = (1、5)の状況で、まずあるユーザが Servlet クラス A の新版を選択し、そのコールグラフ上のクラスの新版を 5 個選択したとします。この時、これらをロードするローダがそれぞれ作られます。次に他のユーザが C の新版を選択し、これらに対する新版を選択したとすると、先ほど作られたクラスローダの内 4 個を再利用できます。このように、n より m が非常に大きい時は、ロード済みの多くのクラスを再利用でき、再起動が高速になります。 B B B B H H H H E E E E F F F F C C C C 再利用可能 Servlet クラス

21 関連研究 Dynamic Class Loading in the Java Virtual Machine [Liangら'98]
クラスローダのアーキテクチャを提示 ロードのメカニズムや型の安全性など JAsCo [Suvéeら'03] HotSwap を用いた DAOP システム JVM にロード済みの特定クラスの定義を置換可能 メソッド本体しか変更できない Sister Namespace [佐藤ら'05] 異なるローダでロードされたクラス間のバージョンバリアを緩和 あるクラスの版のインスタンスを異なる版の変数に代入可能 関連研究です。Dynamic Class Loading in the Java Virtual Machine では Java クラスローダのアーキテクチャやロードのメカニズム、型の安全性などについて述べています。本研究ではこのロードアルゴリズムを利用しアプリケーションの再起動を高速化しました。 JAsCo は HotSwap を用いた動的アスペクト指向システムです。HotSwap を用いることで同じクラスローダを用いて同一名のクラスを再ロードすることができますが、メソッドボディしか定義を変更できないという問題点があります。本研究では新しくクラスローダを作成し直すというアプローチで再ロードを実現しています。 その他のクラスローダの研究として Sister Namespace があります。この研究では異なるローダでロードされたクラス間のバージョンバリアを緩和することで、あるバージョンのインスタンスを異なるバージョンの変数に代入可能にしています。この研究のアプローチを利用すれば、異なるバージョンを同じクラスローダの名前空間で扱えるため、再ロードするクラス数をさらに削減できる可能性がありますが、これについてはまだ検証できていません。

22 まとめ 再起動を高速化するための手法を提案 これまでの活動 変更対象クラスと依存しているクラスを再ロード 旧版アプリを部分的に再利用 実験
既存手法のパフォーマンスを改善 2 手法の優劣が状況によってわかれることが判明 これまでの活動 論文 SWoPP 仙台 PRO 宮古島(投稿中) ポスター PPL 高山 AOSD Saint-Malo まとめです。アプリケーションの再起動を高速化するための手法として、変更されたクラスとそれに依存しているクラスを再ロードするというシンプルな手法と、クラスのバージョン毎にクラスローダを作成し、それらを後に部分的に再利用するという 2 つの手法を提案しました。また、実験によりパフォーマンスが向上していることを確かめ、提案した 2 つの手法は状況により使い分けるべきであることを示しました。これまでの活動は論文発表が 2 回、ポスター発表が 2 回あります。


Download ppt "部分的再ロードによる Java プログラムの再起動の高速化手法"

Similar presentations


Ads by Google