240 likes | 390 Views
ソフトウェアを動的に進化できる Negligent Class Loader. 佐藤 芳樹、千葉 滋 ( 東工大 ). 動作を止めずに・・・ 部分的に・・・ 高速に・・・. ソフトウェアの HotSwap 技術. 実行時にコードを差し替える技術 Sun J2SDK1.4 JPDA Sun J2SDK5 java.lang.instrument 実行時に差し込むだけ Dynamic class loading Dynamic library linking ニーズ サービス停止は大損害 Rapid prototyping
E N D
ソフトウェアを動的に進化できる Negligent Class Loader 佐藤 芳樹、千葉 滋 (東工大) 動作を止めずに・・・ 部分的に・・・ 高速に・・・ JSSST04@東工大
ソフトウェアのHotSwap技術 • 実行時にコードを差し替える技術 • Sun J2SDK1.4 JPDA • Sun J2SDK5 java.lang.instrument • 実行時に差し込むだけ • Dynamic class loading • Dynamic library linking • ニーズ • サービス停止は大損害 • Rapid prototyping • Autonomic computing Hot Standby Hot Spare Hot Deploy Hot Plug Hot Swap JSSST04@東工大
典型的なHotSwapは大がかり (クラス単位のHotSwap) クラス A A F F A F B B B 上書き 再定義 再リンク D D D C E G C E G C E G 参照リンク インスタンスアップデート A A F インスタンス F B B D D G G C A C E • JITなどの最適化を犠牲・やり直し • 参照リンク切断・再構築のオーバーヘッド • ヒープ巡回を伴うインスタンスアップデート A F E F B B D D G G C C E E JSSST04@東工大
提案:Swap-lessアップデート • Negligentなクラスローダ • 古いクラスを破棄しない • 古いインスタンスをアップデートしない • しかし、ソフトウェアをアップデートできる!! JSSST04@東工大
Hot Standby Hot Spare Class Loader A 代入 A A F F F B B B D D G G D C C E E A 代入 F B D G C E G C E 提案:Swap-lessアップデート 動作を止めずに・・・ 部分的に・・・ 高速に・・・ • 別のクラスローダにスタンバイした新バージョンのアプリケーション(インスタンス)を受け取ってアップデート • 別クラスローダで新しいクラスをロード • 別クラスローダ内で新クラスのインスタンスを生成 • 新しいインスタンスを受け取り共存させる Class Loader(アプリケーション) A F B D A F B D C E G G C E JSSST04@東工大
容易にできない理由 loader = new MyClassLoader(…); Class clazz = loader.load(“Car”); Object newCar = clazz.newInstance(); Car c = (Car) newCar; • Javaのバージョンバリア • 別バージョンを代入させない仕組み • 名前空間を分離 • applet, servlet, eclipse-plugin etc.. • 型詐称を防ぐ (e.g. JDK1.1 saraswat problem) • 不正なメモリアクセスでJVMをクラッシュ • ClassCastException • 別のローダで定義される • 同名クラスは異なる型 loader1 old Car Car new loader2 incompatible JSSST04@東工大
c has run()? c has wiper()? c has turn()? => NoSuchMethod 安全にアクセスさせる方法 • 毎インスタンスアクセスでスキーマチェック • 型詐称されても不正なメモリアクセスを防げる • Type-less language の素朴な実現手法 • 過度のスキーマチェックでオーバーヘッド大 loader1 loader2 Car c = (Car) newCar; c.run(); c.wiper(); c.turn(RIGHT); Car Car +run() +turn(int) +wiper() +run() +turnRight() +turnLeft() +wiper() Segmentation Fault JSSST04@東工大
提案手法:Twins room • 安全に効率良くアップデートできる場所(クラス群) • 二つのNegligentな兄弟クラスローダによって形成 • 二つのバージョンのクラスが相互に互換 • インスタンスが相互に代入可、スキーマチェック無しでアクセス • 名前空間も分離 Twins room sibling loader1 sibling loader2 Vehicle Vehicle Truck Truck Car Car Car c = newCar; Car c = oldCar; JSSST04@東工大
Twins room を実現するために • スキーマ互換ローディング • クラスロード時にクラススキーマを互換アップデート • メソッド呼び出し(invokevirtual/nonvirtual..)、フィールドアクセス(get/putfield)で逐一スキーマチェックしない • キャスト時バージョンチェック • インスタンスをTwins room(スキーマ互換されたクラス)に閉じ込める • スキーマ互換していない型の変数に代入させない • 代入演算(astore)で逐一バージョンチェックしない Parent CL Twins room Sibling CL Sibling CL Sibling CL Sibling CL Car Car Car Car JSSST04@東工大
SSP NoSuchMethod Exception turnLeft SSP turnRight wiper wiper turn SSP run run compatible スキーマ互換ローディング • クラスロード時に二つのバージョンのTIBを互換させる - クラスのJVM内表現で仮想メソッドテーブル情報を保持 • 同じTIBインデックスエントリにシグニチャの等しいメソッドを配置 • 不正なアクセスを正常に扱うために空エントリへSSPを挿入 (TIB: type information block) (SSP: Secure Schema Padding) Car < Vehicle Car < Vehicle +turn(int) +wiper() +turnRight() +turnLeft() +wiper() tib[4] tib[3] wiper tib[2] wiper turnLeft tib[1] turn turnRight tib[0] run run JSSST04@東工大
キャスト時バージョンチェック • Twins room内の明示的キャストだけでバージョンチェック • インスタンスフローを追跡しない • 他ローダのキャストではバージョンチェックしない • Bridge-safety [saraswat’97] • 兄弟間の代入はダウンキャストを伴う • 必ず親にロードされたスーパークラス、インタフェースを介す Parent CL Object newCar = (Car) newCar; clazz.newInstance(); Car c = checkcast Twins room JSSST04@東工大
手軽にDynamic AOP、リフレクション コード変換されたクラスを別クラスローダでロード ホットデプロイの改良 ホットデプロイ後に旧コンポーネントのインスタンスを扱える(cache,cookie) 具体的にうれしいこと Twins room Twins room EAR,WAR Servlet Servlet Car Car Weaving Product Product LogAspect newInstance() Hot Deployment JSSST04@東工大
Twins roomの実装 • 実装方針 • 実行時に安全性をチェックしない • Twins room内だけ • クラスロード時に済ませる • IBM Jikes RVM上に実装 • オープンソースのリサーチ用VM • Javaで実装(300KLOC) • Compile-only JIT (Baselevel,optimizing,adaptive) JSSST04@東工大
Sibling’sTIB updates VM_DynamicLinker #lazyMethodInvoker() int[] JIT stub code Class loading JIT compile システム概観 • 型表現を拡張 • TIBにRoom no.を付加 • Negligentクラスローダ • ユーザ用API • Room no.に基づくSID, ITVを算出 • TIB互換とSSP挿入 • バージョンチェック埋め込み(JIT) • TIBアップデート(伝播) SID: superclass ID display ITV: implement trits vector JTOC register JTOC(JRVM table of contents) ・static fields,methods ・all classes ・literals ・numeric,string const VM_Type type ID TIB(Object[]) Room no. field info type method info SID(extends) etc… ITV(implements) Object Room no. SID field1 Room no. ITV field2 virtual method0 TIB virtual method1 status etc… (Lockword,hashcode, gc info) JSSST04@東工大
まとめ 動作を止めずに・・・ 部分的に・・・ 高速に・・・ • Swap-lessアップデート • Negligentなクラスローダ • 安全に効率良くアップデートできるTwins room • 現在の状況 • IBM Jikes RVM 上に実装 • 性能比較実験(SpecJBB2000) JSSST04@東工大
今後の課題 • スキーマ互換 • フィールドや配列要素へのアクセス • privateフィールドのみサポート • direct field accessなのでSSPを挿入できない • 静的束縛やインライン展開されたメソッド • JITedコードをインバリデート • 型安全性の検証 JSSST04@東工大
終わり JSSST04@東工大
違う ! FAQをよく読め! ! Javaクラスローダで進化 • 動的AOP、リフレクションはどう実現される? • クラスローダを利用すれば簡単そう loader = new CustomClassLoader(…); byte[] modifiedclass = translator.compose(“Product”, “Logging”); Class c = loader.load(modifiedClass); Product p = (Product) c.newInstance(); • カスタムクラスローダを生成 • 変換器を使ってProductクラスにログ機能を付加(改変クラスのバイト列を取得) • 改変したProductクラスをカスタムクラスローダでロード 新しいバージョンのProductクラスのインスタンスを取得 JSSST04@東工大
バージョン違いのキャストを許したい Javaクラスローダは不十分 • ありがちなクラスローダへの誤解 • 二つのProductクラスは同じ名前だが異なる(別のバージョン) • 一方はシステムクラスローダで • 他方はカスタムクラスローダでロードされる • Productをインタフェースにすれば良いのでは? • 記述性、性能(indirection)、柔軟性(スキーマが固定)に問題 loader = new CustomClassLoader(…); byte[] modifiedclass = translator.compose(“Product”, “Logging”); Class c = loader.load(modifiedClass); Product p = (Product) c.newInstance(); ClassCastException JSSST04@東工大
p Segmentation fault p.getPrice() では何故バージョンバリア? • 名前空間を分離 • applet, servlet, eclipse plug-in...etc • 型詐称(type-spoofing)を防ぐ • 不正なメモリアクセスでJVMをクラッシュ (e.g. saraswat problem) loader1(http://aaa/B.jar) loader2(http://xxx/Y.jar) Product p = (Product) c.newInstance(); int price = p.getPrice(); Product getName() getPrice() Product getName() • 毎インスタンスアクセスでスキーマ(フィールドやメソッド)チェック ⇒ 型詐称されても不正なメモリアクセスを防げる • 性能を重視するJavaには受け入れられない JSSST04@東工大
現実例1:動的アスペクトウィービング • 動的AOPシステムは直感的に実装できず難しい • アスペクトを動的に合成しても、改変クラスを別バージョンとしてしかロードできない • 既存の動的AOPシステムの実装は非常に複雑で低性能 • Static code translation [Renaud01Reflection][Jason02AOSD] • Breakpoint [Popovicci02AOSD] • Just-in-time hook insertion [Sato03GPCE] • Modified JVM [Popovicci03AOSD][Bockisch04AOSD] System CL product product newInstance() Weaver incompatible JSSST04@東工大
現実例2: コンポーネントのホットデプロイ • ホットデプロイ後に旧コンポーネントのインスタンス(cache,cookie,session object)を扱えない • コンポーネント(EJB-JAR,EAR,WAR)毎にローダ割り当て • ホットデプロイ = 旧ローダ破棄 + 新ローダ生成 • 親にデリゲートして共有 ⇒ ホットデプロイできなくなる • Unified Class Loaders(JBoss) • ローダを連結、クラスをすべて共有 • ネームスペース無し System CL Servlet Servlet product product System CL App CL1 App CL2 Hot Deployment UCL1 UCL2 UCL3 EAR1 EAR2 EAR3 JSSST04@東工大
動的進化を目指した取り組み • 複数バージョンのクラスのインスタンスを利用して進化 • Negligent Class Loaders • プログラムの動的改変 • Sun JDK1.4 JPDA (JDK1.5 java.lang.instrument) • Dynamic Java Classes [Malabarba00ECOOP] • PROSE2 [Popovicci03ECOOP] • Steamloom [Bockisch04AOSD] • 新クラスのリコンパイルと旧クラスのインバリデート インスタンスアップデートやリンク再構築のオーバーヘッド、JITによる最適化を犠牲 Most of previous work JSSST04@東工大
Twins room の重複 • TIBアップデートを伝播 • A-B、B-CのTwins roomが存在する場合 • AによりBのTIBがアップデートされたならば、それにしたがってCのTIBをアップデートする • アップデートされるTIBに対しては、エントリを追加するだけなのでOK Parent CL Twins room Sibling CL Sibling CL Sibling CL Sibling CL Car Car Car Car JSSST04@東工大