レベル: 中級 小野 圭二 (ono@net8.co.jp), 代表取締役, (株)ネットエイト
2007年 11月 30日 日本では意外と知られていないオープンソースのRIA/Ajax開発プラットフォームであるOpenLaszloについて、“システム開発”の視点からその導入方法について紹介する連載です。今回は、パフォーマンスに気をつけたLZXコーディングを行う前に、アプリケーションのパフォーマンスの勘所と切り分け方について解説します。
1.OpenLaszloアプリケーションにおけるパフォーマンスとは
まず最初に、“パフォーマンス”について定義しておきましょう。ITシステムには、OS~アプリケーションの間に様々なモジュールが存在します。ことに現在のWebシステムにおいては非常に多彩なモジュールが連携しあいながら動いていますので、“パフォーマンス調整”と言ったときにどこが調整対象なのか、しばしば立ちすくんでしまうことがあります。
OpenLaszloにおいてはMVCモデルが完全に分離されるため、通常のWebシステムにおける調整よりは切り分けがきれいになります。しかしながらこれも、“一点の疑念もなく”切り分けられるのはSOLOモードでの話しになります。これがPROXYモードになりますと、やはりTomcat等のサーブレットコンテナとの連携がありますので通常のWebシステムのパフォーマンス調整の考え方に近くなります。この場合の参考資料は多数存在しますのでそちらを調べてもらうこととして、ここではSOLOモードに絞ってOpenLaszloアプリケーションのパフォーマンス調整について解説します。とは言いましても、実際のコード記述の注意点は次回の記事とさせていただいて、今回はパフォーマンス調整の前に、チェックポイントとチェック方法について解説します。
OpenLaszloはFlash Player上で稼動するアプリケーションと、DHTMLとして稼動するアプリケーションの二つをコンパイルアウトできます。とは言いましてもDHTML版はバージョン4.1で完全サポート予定ですので、それまではベータ仕様です。そのためここで解説するのはFlash版を取り上げます。
Flash版はご存知の通り、Flash Player上で稼動します。そのため、Flash Playerの特徴を抑えておくとパフォーマンス調整に役立ちます。OpenLaszloにからむFlash Playerの大きな特徴として以下の3点があります。
- Flash Playerはシングルスレッドモデルである
- スクリプト実行時に、15秒ルールがある
- メモリ管理はFlash Player任せである
これらについて、以降で詳しく見ていきましょう。
2.シングルスレッドモデル
Flash Playerはシングルスレッドモデルです。そしてLZXは順次実行型のプログラム言語です。
リスト2.1 サンプル1
<canvas>
<dataset name=”d1” src=”proc1” request=”true”/>
<dataset name=”d2” src=”proc2” request=”true”/>
<datapointer xpath=”d1:/**”>
<handler name=”ondata”>
<!-- d1データセットを受け取って行う処理 -->
</handler>
</datapointer>
<datapointer xpath=”d2:/**”>
<handler name=”ondata”>
<!-- d2データセットを受け取って行う処理 -->
</handler>
</datapointer>
<simplelayout/>
<text datapath=”d1:/***”/>
<text datapath=”d2:/***”/>
</canvas> |
リスト2.1を簡単に解説しますと、“<dataset>”の“d1”,“d2”はrequest=“true”属性によってアプリケーション実行時に自動的に実行されます。“src”属性の指定によってサーバサイドプログラムを呼び出したり、サーバサイドにあるXMLファイルを読み込んだりします。そして読み込み具合を“<datapointer>”でチェックしします。この部分で、エラー処理したり、タイムアウト処理したりできます。このサンプルではうまく読み込めた前提だけで“ondata”ハンドラしか記述していませんがサンプルですので気にしないで下さい。そして最後のところで“ondata”されたデータを“<text>”に設定しています。ブラウザ(Flash Player)を通して表示されるのは最後の“<text>”だけです。
さて、シングルスレッドモデルでは同時に一つの処理しか実行しません。そして順次実行型のプログラムは、ソースに記述された順番に実行されます。つまり、リスト2.1ではクライアントにこのプログラムが読み込まれて、<canvas>のインスタンスが生成された次には、“d1のdataset” → “d2のdataset”→ “d1のdatapointer”→ “d2のdatapointer”→ “d1のtext” → “d2のtext”の順で実行されます。
お気づきでしょうか、“パフォーマンス”のTipsがここにあります。
例えば、コンボボックス設定のための<dataset>が沢山あったとします。そのうちのどれかがサーバエラーを起こす可能性があるとします。
リスト 2.2 とりあえずデータを全部読み込む方法
<dataset name=”d1” src=”proc1” request=”true”/>
<dataset name=”d2” src=”proc2” request=”true”/>
<dataset name=”d3” src=”proc3” request=”true”/>
<dataset name=”d4” src=”proc4” request=”true”/> |
リスト 2.3 サーバサイドエラーを想定した方法
<dataset name=”d1” src=”proc1” request=”true”/>
<dataset name=”d2” src=”proc2”/>
<dataset name=”d3” src=”proc3”/>
<dataset name=”d4” src=”proc4”/>
<datapointer xpath=”d1:/**”>
<handler name=”ondata”>
<!-- d1データセットを受け取って行う処理 -->
<!-- d2データセットを呼び出す -->
var d = canvas.datasets.d2;
d.doRequest();
</handler>
</datapointer>
<datapointer xpath=”d2:/**”>
<handler name=”ondata”>
<!-- d2データセットを受け取って行う処理 -->
<!-- d3データセットを呼び出す -->
var d = canvas.datasets.d3;
d.doRequest();
</handler>
</datapointer>
<datapointer xpath=”d3:/**”>
<handler name=”ondata”>
<!-- d3データセットを受け取って行う処理 -->
<!-- d4データセットを呼び出す -->
var d = canvas.datasets.d4;
d.doRequest();
</handler>
</datapointer> |
コードは長くなってしまいますが、リスト2.3の方が結果的にパフォーマンスが良くなるのはおわかりでしょう。つまり、リスト2.2ではどこか一つの<dataset>がエラーを起こしても、アプリケーションは処理を止めることなくどんどん進んでいきます。そして<datapointer>での判定で初めてエラー処理が行われます。リスト2.3ではエラーを起こした<dataset>で処理を止めることができます。
※このサンプルでは、“proc*”はjspの様なサーバサイドプログラムです。
OpenLaszloではMVCが完全に分離されていますので、サーバサイドでエラーが起こってもサーバサイドからクライアント処理を止めることができません。そのため、クライアントサイドで独自に止めるような仕組みをとっておかないと、ずーっと走り続けてから、最後の最後にエラー、ということになります。意外と見落としがちですが、パフォーマンス調整とはこうゆうところの制御から始まります。
3.15秒ルール
Flashコンテンツが組み込まれているWebコンテンツや、既にOpenLaszloをお試しいただいている方々には、“ムービー内のスクリプトが原因で。。。。”ダイアログボックスをご覧になったことがあるでしょう。Flash Playerはスクリプト処理が15秒滞っているとこのアラートダイアログを表示します。この”スクリプト処理”はインスタンス生成と大きく関係しています。インスタンスとはLZXコンポーネントを指すことになるのですが、早い話画面表示が15秒間とまってしまうとアラートが出てしまうのです。
”15秒間止まってしまう”原因はどこにあるのでしょうか? <dataset>によるサーバプログラム呼び出しによるスループット/レスポンスの遅延はもちろん考えられます。もちろんOpenLaszloアプリケーションの問題も考えられます。この切り分けをまずしなければなりません。この問題は大きく以下で切り分けれます。
- サーバプログラムとの通信遅延
- LZXコンポーネントのインスタンス生成遅延
- LZXコンポーネントへのデータバインド遅延
これらを切り分けるに、デバックウィンドウを起動すると便利です。
リスト 3.1 ボトルネックの切り分け
<canvas debug="true">
<script>
var t = new Date();
var beginTime = t.getTime();
var tmpTime;
</script>
<dataset name="d1" src="proc1" request="true"/>
<datapointer xpath="d1:/**">
<handler name="ondata">
</handler>
</datapointer>
<text datapath="d1:/**">
<handler name="oninit">
var t = new Date();
tmpTime = t.getTime();
Debug.write( "インスタンス生成: " + ( tmpTime - beginTime ) + " ms" );
</handler>
<handler name="ondata">
var t = new Date();
Debug.write( "データバインド: " + ( t.getTime() - tmpTime ) + " ms" );
</handler>
</text>
</canvas> |
リスト3.1によって、遅延のボトルネックがどこにあるのかわかります。
即ち、“<text>”のインスタンス生成にかかる時間と、同じくデータバインドの時間の各デバックデータから判断できます。このデータからボトルネックを判断して調整することになります。OpenLaszloの調整項目は“インスタンス”と”データバインド”の部分になります。特に”インスタンス”を調整するのはよく効きます。実際の調整方法は次回で解説します。
4.メモリ管理
さて、OpenLaszloアプリケーションを運用する上で一番厄介なのはFlash Playerのメモリ管理の問題です。Flash Playerのガルベージコレクションは任意のタイミングで動くためコントロールできません。いや、任意に動かないことが多々あります。そのため、LZXコンポーネントをプログラマはデストロイしたつもりでも、メモリ上にはしっかり残っています。Flash Playerのメモリ管理は「Alex’s Flex Closet: Garbage Collection and Memory Leaks」に詳しく説明されています。
一応“いつか”はガルベージしてくれるはずですので、コンポーネントをデストロイするのは意味があるのですが、過剰に(普通に)期待しては裏切られます。
それではどうしたらいいのでしょう?
OpenLaszloにはコンポーネントのメモリリークをチェックするコマンドが用意されています。詳細は下記URLにあります。
内容を解説しますと、OpenLaszloアプリケーションをデバックモードで走らせておいて、そのバックグラウンドでコンポーネントのメモリリーク状況を調べるものになります。
<canvas debug=“true”>又は、URLにdebug=trueの引数を付けて(ex. http://foo/lps-***/**/**.lzx?debug=true)アプリケーションを起動するとデバックウィンドウを表示させます。このデバックウィンドウのEVAL欄でリターンキーを押します。すると“lzx>”という表示がデバックウィンドウに現れます。この状態で以降、EVAL欄入力されるコマンドが実行されます。これはとても便利な機能です。
さてこのEVAL欄に以下のコマンドを入力していきます。
(1)__LzDebug.markObjects()
(2)__LzDebug.findNewObjects()
(3)__LzDebug.whyAlive()
(1)でアプリケーション内にその時点で存在しているオブジェクトリストを取得します。そして任意のタイミングで(2)を実行すると、その時点のオブジェクトリストを取得します。そしてまた任意のタイミングで(3)を実行するとまたその時点のオブジェクトリストが取得されるのですが、この(3)を実行したときに、デストロイしたり使わなくなっているために本来ガルベージ対象であるはずのオブジェクト、つまりメモリリークとなっているものをリストアップしてくれるのです。
(3)実行時に.toString()を付けて、__LzDebug.whyAlive().toString()を実行するとより詳しいデータを取得することができます。残念ながらFlash Playerのメモリ管理に完全な解決策は今のところありませんが、これらのツールを使うことで、コーディングをブラッシュアップすることができます。ちょっと難しいですが、お試し下さい。
参考文献 学ぶために
製品や技術を入手するために
著者について  | 
|  | 長くインターネットシステム開発に従事して来てWebアプリケーションの操作性に疑問を持ち続けていたところでOpenLaszloに出会う。現在、日本でOpenLaszloの普及を推進中。次々と出現するフレームワークに辟易し、OpenLaszloのマルチランタイム性こそプログラマを救うと考えている。いづれWebは全てAjax/RIAになると確信している。Laszlo Systems社でトレーニングを受けた最初の日本人エンジニアでもある。 |
記事の評価
|