パフォーマンス徹底比較 Seasar2 vs Spring

Slides:



Advertisements
Similar presentations
Web アプリをユーザー毎に カスタマイズ可能にする AOP フレームワーク
Advertisements

プログラミング 平成24年1月11日 森田 彦.
ファイルキャッシュを考慮したディスク監視のオフロード
Chapter11-4(前半) 加藤健.
最新ファイルの提供を保証する代理FTPサーバの開発
オペレーティングシステムⅡ 第11回 講師 松本 章代 VirtuaWin・・・仮想デスクトップソフト.
クラウドにおける ネストした仮想化を用いた 安全な帯域外リモート管理
3-1 MySQLについて 発表者:藤村元彦 自然言語処理研究室.
S2Container.NET, S2Dao.NET コミッタ 藤井 宏明
全体ミーティング (4/25) 村田雅之.
エンタープライズアプリケーション II 第10回 / 2006年7月23日
情報理工学部 情報システム工学科 ラシキアゼミ3年 H 岡田 貴大
DNASシステム上のアプリケーション起動シーケンスのための基盤であるdsh部分の性能評価
Lightweight Language Weekend ls-lRシェル
WagbyR6.5 Update 12 PPT版 更新情報
仮想マシンの並列処理性能に対するCPU割り当ての影響の評価
全体ミーティング (6/13) 村田雅之.
ファイルシステムキャッシュを 考慮した仮想マシン監視機構
RAD Studio 14/09/27 TEffectを使った綺麗なForm
侵入検知システム(IDS) 停止 IDS サーバへの不正アクセスが増加している
Androidソースコード公開後のJNI
ネストした仮想化を用いた VMの安全な帯域外リモート管理
サーバ構成と運用 ここから私林がサーバ構成と運用について話します.
同期的にアドバイスを活性化できる分散動的アスペクト指向システム
第20章 Flyweight ~同じものを共有して無駄をなくす~
帯域外リモート管理の継続を 実現可能なVMマイグレーション手法
ユーザ毎にカスタマイズ可能な Web アプリケーション用のフレームワークの実装
VMマイグレーションを可能にするIDSオフロード機構
アスペクト指向プログラミングを用いたIDSオフロード
MPIによる行列積計算 情報論理工学研究室 渡邉伊織 情報論理工学研究室 渡邉伊織です。
プログラム実行時情報を用いたトランザクションファンクション抽出手法
型付きアセンブリ言語を用いた安全なカーネル拡張
過負荷時の分散ソフトウェアの 性能劣化を改善する スケジューリングの提案
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
暗黙的に型付けされる構造体の Java言語への導入
理学部 情報科学科 指導教官 千葉 滋 助教授 学籍番号 03_03686 内河 綾
リモートホストの異常を検知するための GPUとの直接通信機構
ユーザ毎にカスタマイズ可能な Webアプリケーションの 効率の良い実装方法
利用関係に基づく類似度を用いたJavaコンポーネント分類ツールの作成
実行時情報に基づく OSカーネルのコンフィグ最小化
仮想メモリを用いた VMマイグレーションの高速化
Linux リテラシ 2006 第5回 SSH と SCP CIS RAT.
仮想計算機を用いたサーバ統合に おける高速なリブートリカバリ
クラウドにおけるIntel SGXを用いた VMの安全な監視機構
クラウドにおけるVM内コンテナを用いた 自動障害復旧システムの開発
未使用メモリに着目した 複数ホストにまたがる 仮想マシンの高速化
情報処理 タイマの基礎 R8C タイマの基礎.
アスペクト指向言語のための 独立性の高いパッケージシステム
Intel SGXを用いた仮想マシンの 安全な監視機構
VMMのソフトウェア若化を考慮した クラスタ性能の比較
第二回 Javaの開発環境 04A2029           古賀慎也.
ソフトウェア保守のための コードクローン情報検索ツール
ウェブアプリケーションサーバの Degradation Schemeの 制御に向けて
アクセス集中時の Webサーバの性能に対する OSの影響
仮想マシンと物理マシンを一元管理するための仮想AMT
全体ミーティング (5/23) 村田雅之.
同期処理のモジュール化を 可能にする アスペクト指向言語
仮想マシンに対する 高いサービス可用性を実現する パケットフィルタリング
コレクション・フレームワーク J2EE I (データベース論) 第6回 /
コレクション・フレームワーク データベース論 第7回.
Mondriaan Memory Protection の調査
サブゼミ第7回 実装編① オブジェクト型とキャスト.
VMリダイレクト攻撃を防ぐための 安全なリモート管理機構
卒業研究 JCSPを用いたプログラム開発  池部理奈.
ユビキタスコンピューティングの ための ハンドオーバー機能付きRMIの実装
強制パススルー機構を用いた VMの安全な帯域外リモート管理
IPmigrate:複数ホストに分割されたVMの マイグレーション手法
特定ユーザーのみが利用可能な仮想プライベート・ネットワーク
GluonJ を用いたビジネスロジックからのデータベースアクセスの分離
強制パススルー機構を用いた VMの安全な帯域外リモート管理
Presentation transcript:

パフォーマンス徹底比較 Seasar2 vs Spring 2006/04/12 株式会社電通国際情報サービス ひがやすを 株式会社アークシステム 本間 宏崇

DIコンテナの実装によるパフォーマンスの 違いを明らかにする DIコンテナが行う処理の中で、どこに時間が掛かるのかを明らかにする 目的 DIコンテナの実装によるパフォーマンスの 違いを明らかにする DIコンテナが行う処理の中で、どこに時間が掛かるのかを明らかにする

ハードウェア ソフトウェア ベンチマーク測定環境 HP ProLiant DL360 G4p CPU: Intel Xeon 3.80GHz (2 CPU) Memory: 4GB ソフトウェア OS: Red Hat Enterprise Linux AS 4 Update 3 (x86) Java: 1.5.0_06 (Sun) 高スペック機

DIコンテナ ベンチマークプログラム 測定アプリケーション Seasar 2.4 beta1 (2006/03/27) Spring 2.0 M3 (2006/03/08) ベンチマークプログラム 自作

5回実行し、最大・最小を除いた3回の平均値を採る 測定方法 VMオプション -Xmx1024M -Xms1024M -XX:PermSize=384M -XX:MaxPermSize=384M fork=true JVMのキャッシュをクリアするため 5回実行し、最大・最小を除いた3回の平均値を採る

コンテナ生成 定義からコンポーネントを組み立てる DIコンテナがやっていること XML読み込み(DOMやSAX) DI AOP リフレクション リフレクション情報を取得しキャッシュする リフレクションを使用しプロパティへアクセスする AOP バイトコード作成

それぞれの処理について、パフォーマンスを見ていきましょう まずは、XML読み込みを行っている、コンテナ生成処理からです。

コンテナ生成時の内部処理 コンテナ生成 Seasar Spring SAX リフレクション情報をキャッシュ DOM ※リフレクション処理はここでは行わない

コンテナへ入力する設定ファイル Seasar Spring <components> <component name="nullBean00000" class="xxx.NullBean00000" /> <component name="nullBean00001" class="xxx.NullBean00001" /> … <beans> <bean name="nullBean00000" class=“xxx.NullBean00000" /> <bean name="nullBean00001" class=“xxx.NullBean00001" /> …

コンテナ生成 コンテナ生成処理

Seasar ≒ Spring 理由 コンテナ生成:結果 リフレクション情報をキャッシュするぶんSeasarの方が多くの処理を行っていますが、SAXとDOMの性能差によって吸収されていると思われます。

次は、生成したコンテナからコンポーネントを取得する処理です コンポーネント取得 次は、生成したコンテナからコンポーネントを取得する処理です コンテナに登録されている全てのコンポーネントを取得するのに掛かった時間を計測しました DI・AOPは使用していません 単純に、コンテナからコンポーネントを取得するのみです

コンポーネント取得

Seasar >>(10~30倍)>> Spring コンポーネント取得:結果 Seasar >>(10~30倍)>> Spring 1000個で1400ms コンポーネントを生成するという点ではどちらも一緒のはずですが、どうして差が出るのでしょうか?

理由 コンポーネント取得 DIコンテナは、コンポーネントを生成するためにリフレクション情報を使用しています Seasarはコンテナ生成時にリフレクション情報をキャッシュしています。コンポーネント生成時にはキャッシュした情報を使用しています Springはコンポーネントを取得するときにリフレクション情報をキャッシュしています

理由 コンポーネント取得 Springはコンポーネント取得時にリフレクション処理を行っているため、遅くなります Seasarはコンテナ生成時にリフレクション処理を行っていますが、SAXとDOMの性能差によってSpringとの差が無くなっています そのため、コンポーネント取得時にSeasarの速さが際立っています

では、SeasarとSpringのリフレクション処理はどれくらい違うのでしょうか? リフレクション処理を行うクラスを直接呼び出して測定しました。 Seasar: BeanDescImpl Spring: BeanWrapperImpl

リフレクション処理 リフレクション情報をキャッシュ

Seasar >(3倍)> Spring リフレクション処理:結果 Seasar >(3倍)> Spring 1000回で1300ms 理由 Seasarはリフレクションキャッシュ処理を独自で実装しています。SpringのBeanWrapperImplはJDKのIntrospectorを使用しています。この違いが速度差となっていると思われます キャッシュ実装の違い Seasar: HashMap Spring: WeakHashMap

Seasarではコンテナ生成直後にinit処理を行うことができます init処理ではsingletonのコンポーネントを作成することができます singletonとは、コンポーネント生成は最初1度だけで、その後は最初に生成したコンポーネントを返すこと

実際の案件では、アプリケーション起動時にinit処理でsingletonのコンポーネントを生成した方が効率的です Seasarのコンテナinit処理 実際の案件では、アプリケーション起動時にinit処理でsingletonのコンポーネントを生成した方が効率的です Springにはこのような機能はありません init処理を含めた場合のコンテナ生成でのパフォーマンスを見てみましょう Seasar: コンテナ生成 + init Spring: コンテナ生成

Seasarのコンテナinit処理 コンテナ生成( + init処理)

Seasarのコンテナinit処理:結果 Seasar ≒ Spring 理由 init処理ではsingletonのオブジェクトを生成しているだけなので、それほど時間が掛かりません コンテナ作成時の速度はSeasarの方が速いため、initでのオーバーヘッドをカバーできます

では... create + initした場合での、コンポーネント取得パフォーマンスは?

create + initした後のコンポーネント取得処理

Seasar >>>>>>> (60~200倍) >>>>>>>>>>>>> Spring 結果 Seasar >>>>>>> (60~200倍) >>>>>>>>>>>>> Spring 1000個で1500ms 実際の案件ではアプリケーション初期化時にcreate + init処理を行っているので、これが現実のプロジェクトで起こる結果を反映しています ただし、コンテナから2回目に取り出すときは、SeasarもSpringもキャッシュしたオブジェクトを返すだけなので、差は付きません

今まではsingletonの場合でした。今度はprototypeの場合を見てみましょう prototypeでも1度目の取得はsingletonと同様に圧倒的な差が出ます 2度目の取得で比べてみましょう

prototype prototypeで2度目のコンポーネント取得

Seasar >(3~5倍)> Spring 理由 prototype:結果 1000個で130ms Springでは対象となるオブジェクトに加えてBeanWrapperImplを毎回作っていますが、Seasarでは対象となるオブジェクトしか作りません。これが原因の1つかもしれません。

現実的な状況を反映させるため、最初にコンテナ生成とinitを実行した上で比較しています DI (Manual) 次はDI処理について見てみましょう DIとは、あるコンポーネントが必要とする他のコンポーネントを、コンテナがセットしてあげることです(ざっくり) 現実的な状況を反映させるため、最初にコンテナ生成とinitを実行した上で比較しています コンテナへコンポーネントを2000個登録しています。2個で1組です。

コンテナ生成 (Seasarはinitを含む) DI (Manual) コンテナ生成 (Seasarはinitを含む)

前回コンテナ生成を比較した場合はほぼ一緒でしたが... DI (Manual):結果 Seasar < Spring 差は600ms 前回コンテナ生成を比較した場合はほぼ一緒でしたが...

差が大きくないのと、初期化時の処理であることを考えると、現実にはあまり問題にならないと思います DI (Manual):結果 理由 今回2000個のコンポーネントでコンテナ生成した場合は600ms差が出ています この差はリフレクションキャッシュによるものです 前回より1000個余分にキャッシュしていることが今回の600msの差につながっています Seasarでリフレクションキャッシュ1000個と2000個を作成する時間の差が400msでしたので、若干違いますがほぼその差と思われます 差が大きくないのと、初期化時の処理であることを考えると、現実にはあまり問題にならないと思います

今度は実際にユーザに影響する部分である、DIしたコンポーネントを取得する処理を見てみましょう DI (Manual) 今度は実際にユーザに影響する部分である、DIしたコンポーネントを取得する処理を見てみましょう

DI (Manual) DIしたコンポーネントを取得(1000個) Manual DI singleton

Seasar >>>>>> (100倍) >>>>>>>>>>>>>> Spring DI (Manual):結果 Seasar >>>>>> (100倍) >>>>>>>>>>>>>> Spring 1000セットで2400ms DI無しの場合と比べると... 今回は2000個から1000個取り出していますが、1000個から1000個取り出すのと速度は同じですので、そのときと比べてみましょう DI無しの場合は60倍、今回は100倍。DIすることによってさらに差が開いています。

リフレクションでのアクセスがどれくらいか見てみましょう DI (Manual):結果 理由 DIするときに、プロパティに対してリフレクションでアクセスしています リフレクションを行うクラスの性能差が一因と思われます リフレクションでのアクセスがどれくらいか見てみましょう 1プロパティへset, getして測定しました Seasar: BeanDescImpl Spring: BeanWrapperImpl

リフレクション リフレクションでのプロパティアクセス

Seasar > (4~8倍) > Spring 理由 リフレクション:結果 1000回で100ms BeanDescImplとBeanWrapperImplの差と思われます BeanWrapperImplではネストしたプロパティをサポートしており、それ関連のオーバーヘッド(文字列操作とか)が大きいと思われます

次は、prototypeで明示的にDIを指定した場合の、2度目のアクセスについてです

DIしたコンポーネントを取得(1000個) Manual DI prototype

結果 Seasar >(3倍)> Spring 1000セットで150ms DIしない場合でもprototypeでの2度目の取得は3~5倍の差だったので、DI処理のぶん更に差が出ると思いましたが、想定したほどではありませんでした

設定ファイルを少しでも少なくするために、autowireというものがあります 設定ファイルにDIを指定するpropertyタグを書かなくて良くなります autowireには幾つか種類がありますが、ここでは型によるDIを使用しています

autowire DIしたコンポーネントを取得(1000個) autowire byType singleton

Seasar >>>>>>>>>>>>>>>>>>>>>>>>>(300倍)>>>>>>>>>>> Spring autowire:結果 Seasar >>>>>>>>>>>>>>>>>>>>>>>>>(300倍)>>>>>>>>>>> Spring 1000セットで6000ms Manualでは100倍の差でしたが、Autoにすると更に3倍の差が付きました

理由 autowire:結果 autowire時にはDI対象を探すロジックが実行されます SpringではDIの度に、毎回コンテナへ登録されている全てのオブジェクトへアクセスします コンテナには2000個登録されていて、1000回DIしているので、2000 * 1000回コンポーネント定義へアクセスしています。 Seasarはコンポーネントを登録するときにクラスの型をキー情報としてハッシュテーブルへ登録しているので、DIの度に1回のアクセスで済みます つまりDIの度にListへ全件アクセスするのかHashMapへキーでアクセスするのかの差なので、差が付いて当たり前と言えるでしょう

autowireでprototypeの場合はどうでしょうか? 2回目のコンポーネント取得時

DIしたコンポーネントを取得(1000個) autowire byType prototype

Seasar >>>> (35倍) >>>>> Spring 結果 Seasar >>>> (35倍) >>>>> Spring 1000セットで2300ms 理由 singletonと同じで、DI対象を探すロジックの差でしょう singletonほどではありませんが、大きな差が出ました

AOPとは、バイトコードを操作し もともとの処理をカスタマイズするもの (ざっくり) 今回のAOPは文字列を返すだけの、非常にシンプルなものです。だからこそAOPのオーバーヘッドがわかりやすいと思います 10,000,000回メソッドを実行 SeasarはJavassist SpringはCGLIB (DynamicProxyよりも速い)

AOP AOPを仕掛けたメソッドを実行

Seasar >(3~4倍)> Spring 理由 AOP:結果 10,000,000回で2400ms Seasarは2.1まではCGLIBで2.2からはJavassistに変えて、約3倍速くなったことがあります CGLIBを使うと殆どチューニングの余地がありませんが、Javassistにはチューニングの余地があります Seasarではかなりのチューニングを行っているので、速くなっていると思われます

AOPを組み込むバイトコード操作を、weavingと呼んでいます

まずは、weavingするクラスを直接呼び出して、速度差を比較しました AOP weaving まずは、weavingするクラスを直接呼び出して、速度差を比較しました Seasar: AopProxy Spring: ProxyFactory

AOP weaving AOPのWeaving

AOPのweavingにかかる絶対時間が大きいことがわかります (1000個で8秒!) Seasar >(3倍)> Spring 1000回で8000ms 理由 JavassistとCGLIBでのバイトコードweavingの速度差と思われます AOPのweavingにかかる絶対時間が大きいことがわかります (1000個で8秒!)

次は、登録されているコンポーネントへまとめてAspectを仕掛けて、コンテナを生成してみます Seasar: AspectAutoRegister Spring: AutoProxyCreator これらを使ってみました

AOP自動登録でのコンテナ生成

Seasar >>> (15~60倍) > > > Spring 結果 Seasar >>> (15~60倍) > > > Spring 1000個で15000ms 理由 リフレクション情報のキャッシュ AOP weaving やはり、AOP weavingはDIコンテナの処理の中では重い部類に入ることがわかります

補足情報 Springは(今回使用した方法で)AOPを登録すると、コンテナ生成時にリフレクション情報をキャッシュしコンポーネントを生成するようです 1度目のコンポーネント取得時に発生していた負荷がコンテナ生成時に寄っています そのぶん、コンポーネント取得時の速度はSeasarと同じくらいに速くなっています

DIという同じ技術を実装してこれほどの差が出るのはかなり驚きです まとめ DIという同じ技術を実装してこれほどの差が出るのはかなり驚きです ある程度、原因も指摘しているので、この結果を元にSpringのチューニングに役立ててもらえれば幸いです この結果およびテストプログラムはオープンソースとして公開する予定です

本日はご静聴いただき ありがとうございました。