ユーザ毎にカスタマイズ可能な Web アプリケーション用のフレームワークの実装 別役 浩平 千葉 滋 東京工業大学 情報理工学研究科数理・計算科学専攻
Web アプリケーションのための AOP AOP (Aspect Oriented Programming)の従来の用途 横断的関心事の分離 ロギング、トランザクション管理、例外処理 etc. 本研究での AOP の用途 アプリケーションのカスタマイズ (横断的関心事の一種) 修正点を別モジュール(アスペクト)にまとめて保守性を上げる サーバ リクエスト ユーザ Class Webapp { void doGet(..){ this.table(); … }} アスペクトの取得 @Glue class Customizer{ @Around(“{return (html コード)}”) Pointcut pc = Pcd.call(“Webapp#table(..)”);} アプリ weave
ユーザ毎のカスタマイズの実現に向けて weave アスペクトを リクエスト 適用しないユーザ アスペクトを リクエスト 適用するユーザ アスペクトの取得 実行 Class Webapp { void doGet(..){ setbgColor(..); showLinks(..); … }} @Glue class Customizer{ @Around(“{背景色の変更}") Pointcut pc1 = Pcd.call(“Webapp#setbgColor(..)"); @Before(“{リンクの追加}") Pointcut pc2 = Pcd.call(“Webapp#showLinks(..)");} weave
Per-session AOP [戸部ら ‘08] ユーザ毎に異なるアスペクトを Web アプリに weave Web アプリを細かな粒度でカスタマイズ可能 ユーザ毎に振る舞いが異なる Web アプリを実現 クラスローダをユーザ毎に作成 セッションからユーザのアスペクトを特定 リクエストの度にアプリにアスペクトを weave して再ロード サーバ ロード リクエスト ローダ A ユーザ A アスペクト A Web アプリ ローダ B アスペクト B ユーザ B weave
実装上の問題点 オーバヘッドが大きい リクエストの度にクラスローダを作成 アプリの実行に必要なクラスを全て再ロード (例)掲示板アプリへのリクエスト送信 平均応答時間
Per-session AOP の効率的実装の提案 Web アプリの類似部分の共通化 再ロードが必要なのは weave 対象クラスのみ Weave 対象に依存しているクラスも再ロード クラスローダのキャッシュ アスペクトの変更がなければ再ロードは不必要 共通の親クラスローダ weave 対象クラス 委譲 C ユーザ専用ローダ A B ユーザ X ユーザ Y ユーザ Z
Per-session AOP の効率的実装の提案 Web アプリの類似部分の共通化 再ロードが必要なのは weave 対象クラスのみ Weave 対象に依存しているクラスも再ロード クラスローダのキャッシュ アスペクトの変更がなければ再ロードは不必要 共通の親クラスローダ weave 対象クラス 委譲 E C H ユーザ専用ローダ D A B 依存 F G ユーザ X ユーザ Y ユーザ Z
クラスローダの親子関係 クラスのロードは親子関係をもつ 複数のクラスローダが実行 一般的なロード Java 言語の標準仕様 クラスローダの親子関係 クラスのロードは親子関係をもつ 複数のクラスローダが実行 一般的なロード 自身で既にロード済みならば、 そのクラスを返す 親ローダの loadClass メソッドを 呼び出す 独自の探索方法でクラスを探す 1 3 2 Not Found クラスのロード要求 1 3
独自のユーザ専用ローダ アスペクトの weave を可能にする ロード要求時に先に自身で探索 if (weave 対象 or 依存しているクラス) ロード済みならば、それを返す 独自の探索方法でクラスを探し、 アスペクトを weave 親ローダの loadClass メソッドを呼び出す else 共通ローダにはあらかじめ 全クラスをロードさせる その他のクラスは 親がロード 共通ローダ else ユーザ専用ローダ 1 2 weave 対象及び 依存しているクラス クラスのロード要求
B で使われる C は ユーザ専用ローダでロードされたもの Java 言語の標準仕様 クラス内で参照される他のクラスのロード そのクラスをロードしたローダを起点として探す 子クラスローダを起点とすると問題有り 例) 共通ローダとユーザ専用ローダにロードされる C は各々異なる実装を持つ B、C が同一ライブラリ内のクラスである 場合など予期せぬ動作を引き起こす 依存 B C 共通ローダ B で使われる C は ユーザ専用ローダでロードされたもの C ユーザ専用ローダ
ユーザ専用ローダでロードするクラス Weave 対象クラス Weave 対象クラスに依存しているクラス B に依存 その他のクラス A B C A B C 共通ローダ 問題無し weave 対象クラス A B A のメソッドを実行 ユーザ X ユーザ Y ユーザ専用ローダ
共通ローダにロードさせると問題有り(1) ユーザ毎に異なるアスペクトを weave できない B に依存 その他のクラス A B C ユーザ X 専用に A B C 共通ローダ B にアスペクトをweave 不可能 weave 対象クラス A A のメソッドを実行 ユーザ X ユーザ Y ユーザ専用ローダ
共通ローダにロードさせると問題有り(2) ユーザ毎に異なるアスペクトを weave できない A B C A のメソッドを実行 ユーザ X 専用に 共通ローダ B にアスペクトをweave 不可能 B に依存 その他のクラス A B C B weave 対象クラス ユーザ X ユーザ Y ユーザ専用ローダ
分類アルゴリズム クラス間の依存関係の探索 全クラスについて、依存しているクラス群を決定 即座に子ローダでロードすべきクラス群が判明 クラス間の依存関係を表すグラフ G=(V, E) の ∀v ∈ V について、Sv = ϕ を作成し、 Sv ← Sv + v. ∀u ∈ {u|(u, v) ∈ E} について, Su ≠ ϕ ならば,Sv ← Sv + Su. Su = ϕ ならば,u について 1 から同様の操作を行い, Sv ← Sv + Su.
クラスローダのキャッシュ フレームワークではリクエストの度にローダを作成 アスペクトの変更がなければ再ロードの必要なし 同じクラスの再ロードによるオーバヘッド アスペクトの変更がなければ再ロードの必要なし Web アプリ毎にローダ用のキャッシュを設ける 設定ファイルでエントリ数を指定 共通ローダ ユーザ専用ローダ キャッシュ 破棄
実験 掲示板アプリ (BBS クラス) へのリクエスト送信実験 フレームワークの使用・不使用、 効率的実装の有無に分けて測定 フレームワークの使用・不使用、 効率的実装の有無に分けて測定 100 ユーザが 100 スレッドで、 各ユーザが 10 リクエストを並列に送信 キャッシュエントリ数別に測定 実験環境 Client マシン OS : Windows Server 2003 CPU : Core 2 Duo 3.00 GHz Memory : 4 GB Server マシン OS : Linux 2.6.26 CPU : Xeon 2.83 GHz DBAccesser 5285 byte 依存 BBS ResDate 1088 byte BBSLogger weave 対象クラス 600 byte 計 6973 byte
平均応答時間 キャッシュを大きくすればオーバヘッドは 10% 程度 Tomcatのみ(100 apps) : 100 個の同一アプリ 100 ユーザが静的にカスタマイズした場合を想定 Tomcatのみ(1 app) : 1 個のアプリ カスタマイズをしない Web アプリ、3 倍高速 19832 (ms) 効率化無し Tomcatのみ (100 apps) Tomcatのみ (1 app) キャッシュエントリ数
ローダ分割による効果 一回当たり 6973 byte のロードを削減 リクエストの処理は BBS クラスから始まる BBS クラスの実行には ResDate、DBAccesser、BBSLogger クラスが必要 キャッシュエントリ数
関連研究 : プラグイン機構(1) Web アプリの拡張ポイント毎にインタフェースを設定 プラグインをインタフェースを介して呼び出す void doGet(){ Customizer c = webapp.getCustomizer(uid); c.setbgColor(..); c.showLinks(..); : Interface Customizer{ void setbgColor(..); void showLinks(..); : 拡張ポイント プラグインの呼び出し Class Custom1 impl. Customizer{ void setbgColor(..){..} void showLinks(..){..} : <Config> <Custom class=“Custom1”/> </Config> Class Custom1 impl. Customizer{ void setbgColor(..){..} void showLinks(..){..} : ユーザの設定(xml ファイル)
関連研究 : プラグイン機構(2) Web アプリ開発者の実装コストが大きい プラグイン開発者の自由度が低い 本フレームワークではアスペクトを用いるため 機構に合わせた実装は必要ない プラグイン開発者の自由度が低い アスペクトを用いれば細かな粒度でカスタマイズ可能
関連研究 : DI コンテナ コンポーネント間の依存関係を設定ファイル を用いて注入 ユーザ毎のカスタマイズ機能が提供されない コンポーネント間の依存関係を設定ファイル を用いて注入 クラスのフィールドを自動的に初期化 ユーザ毎のカスタマイズ機能が提供されない 本フレームワークではユーザ毎にクラスローダを作成 ユーザ毎に異なる Web アプリをロード可能
その他の関連研究 PROSE[Popovici ら ‘02] QoSWeaver[光来ら ‘07] イベント通知を用いた DAOP システム 時間的コストが大きい QoSWeaver[光来ら ‘07] アスペクトを用いてスケジューリングコードを Web アプリに weave Web アプリの実行時性能を向上
まとめ Per-session AOP の効率的実装について提案した Web アプリのユーザ毎のカスタマイズを実現 再ロードによるオーバヘッドが大きかった リクエスト毎にローダを作り直す Web アプリの類似部分の共通化により 実行時性能を向上させた クラスローダのアーキテクチャを利用
今後の課題 さらなる実験 セキュリティ対策 クラス間の依存関係は Web アプリにより様々 ユーザ専用ローダでロードすべきクラスは weave 対象クラスに依存する セキュリティ対策 現状:プラグイン開発者は自由にアスペクトを 記述可能 アプリの拡張者に対する信頼が必要 Java 言語のセキュリティマネージャーを利用 アスペクトのバイトコードを走査