【CakePHP】「CakePHPカンファレンス東京」に参加します

▼Event Entry::CakePHPカンファレンス東京
http://events.php.gr.jp/events/show/55

参加いたします!

危なかった…昨日はすっかり忘れていました。
でも120人くらいで頭打ちのようなので、まだ申込間に合いますよ(といっても、1時間はもたないと思いますが)。

ちなみに、LTも一応申し込みました。
採用されるといいな。
ネタは…ウチで扱ってるのは2つくらいしかないので、簡単に想像つくと思います(^^;。

Cakeとは全然関係ないのですが、今日はiPhone開発関連のアクセスがものすごいです。
どうやら「もとまかのiPhone・iPod touch戯れ日記」さんに捕捉されたもようです。
どうもありがとうございます。

【CakePHP】App::importが遅い件(続編)

App::import関連でさらに調査してみたのですが、私の方で重大なミスをしていました。

とりあえず、歴代RCx版での比較をしてみましたので先に紹介します。

【共通設定】
・app/controllers/mypages_controller.phpとして、var $uses=array(),var function index(){}のみを設定したコントローラを作成。
・app/view/mypages/index.ctpとしてブランクファイルを作成。
・app/view/layouts/default.ctpとして、標準のdefault.ctpをベースにContent-type,title,content_for_layout以外の動的要素を取り除いたレイアウトファイルを作成。
・debug=0に設定
・上記設定を行ったあと、トップページにアクセスして動作確認。
・導入後、apacheサービスをrestart。
・ ab -n 1000 -c 100 http://hoge.com/mypages でベンチマーク実行。

【bootstrap.phpの変更】
各バージョンについて、bootstrap.php中のDispatcherの呼び出し部分を次のように変更。

RC1/RC2
App::import(‘Core’, array(‘Session’, ‘Security’, ‘String’, ‘Dispatcher’));
↓↓↓
App::import(‘Core’, array(‘Session’, ‘Security’, ‘String’));
App::import(‘Core’, ‘Dispatcher’, true, array(), ‘/path/to/cake/dispatcher.php’);

RC3
App::import(‘Core’, array(‘Dispatcher’));
↓↓↓
App::import(‘Core’, ‘Dispatcher’, true, array(), ‘/path/to/cake/dispatcher.php’);

【結果(3回中の平均)】
RC1
ノーマル:25.52req/sec
改造  :26.50req/sec

RC2
ノーマル:67.09req/sec
改造  :65.20req/sec

RC3
ノーマル:73.00req/sec
改造  :73.00req/sec

つまり結論から申しますと「debug=0での実行では、改造してもそれほど差がない」というわけです。
前回の記事では、debug=2のままで実行してしまい、それが原因で差がついたようです(逆に言えば、debug=2の時は改造した方が速い)。これについては、上記テストのあと、(RC3版のみですが)debug=2に修正して実行したところ、前回の記事とほぼ同じ結果が得られました。

もう少し冷静に検証すればこのようなミスはなかったので、申し訳ないです。

ただ、これで終わりというわけではなく、App::import周りのチューンナップは今後も必要と思われます。
当方でも引き続き調査しますので、何か発見がありましたらまた紹介させていただきます。

【CakePHP】App::importが遅い件の調査

最近CakePHPフォーラムの方で、App::importが遅い、という話題がありました。
この件について、結構いい加減なレスを付けてしまったのですが、自分でも結構切実なため、ちょっと調査してみることにしました。

手っ取り早くpearのBenchmarkを入れ、configure.php内のメソッドに全て適用して走らせたところ、一番重いのは、App::import内で呼び出しているApp::__findのようです。具体的な数値はさらしても全く参考にならないので割愛しますが、当方の遅いサーバで、トータルの処理時間が他のメソッドが0.001s以下の処理であるのに対し、App::importやApp::__findは0.1s単位の話になっています。

フォーラムで指摘のあったものとして、「ディレクトリ検索のリストの一番最後にcakeディレクトリがある」というのがあり、確かに見つからなかった場合に最悪今まで調べたcake内のほかのディレクトリを再チェックしかねません。こうなる可能性があるもので、必ずファイルが存在しているものはbasics.php、bootstrap.php、dispatcher.phpの3つです。

ソースを調べたところ、案の定というのか、bootstrap.php内で「dispatcher.php」がApp::importで呼ばれているではありませんか! ほかのファイルについてはrequireで直接呼ばれているようなので問題なさそうですが、dispatcherがなぜApp::importで呼ばれているのか理解できません。

本来はrequire(_once)で片付けるのが一番高速なのですが、どこか別の場所でdispatcherを呼んでいる場所があるらしく、このままだと_loadedリストに書かれないため2度読みの可能性があります。そこで、App::importでファイルを直接指定することで2度読みOKの状況を作ることにして、変更してみました。

【/path/to/cake/bootstrap.php】

App::import(‘Core’, array(‘Dispatcher’));
↓↓↓
App::import(‘Core’, ‘Dispatcher’, true, array(), ‘/path/to/cake/dispatcher.php’);

ブランクページを表示するだけの「/mypages/index」を作り、早速abしてみました。
100アクセス中、改造前は45req/sくらいでしたが、65req/secくらいに跳ね上がりました!

結論として、bootstrap.phpのdispatcher.php呼び出しが諸悪の根源とみて良いと思います。
また、基本的に場所の分かり切っているクラスの読み込みはファイルパスの直接指定に直すことで高速化できると思います。例えばrouter.php, controller.php等も必ず読み込まれるファイルですから、直接指定で問題ないと思います(ただ、比較的早い段階で見つかるので、それほど高速になるかは分からないです)。できればこういったファイルについてはrequireで問題ないような作りになっていると…(^^;

【追記】
全く書かれていなかったので補足しますと、テストを行ったのはRC3版です。
RC1やRC2で同様の改造を行う場合は、App::importに列挙されているSession、Security、Stringの3点を分解してから行う必要があります。

【追記その2】
さらに調査した結果が こちら にあります。
合わせてお読みください。

【CakePHP】外部プログラムでコンポーネントを共有したい場合

たまたま仕事でメールフォームを設置しなければならなくなって、お手軽にQdmailなんかを拝借させてもらったのですが(感謝です)。その際になかなか素晴らしいアイデアを発見しました。

Qdmailはコンポーネントでも素のクラスとしても使うことが出来るのですが、その仕組みが面白くて、Cakeかどうかの判定で「CAKE」もしくは「CAKE_CORE_INCLUDE_PATH」がdefinedされているか調べ、ある場合はObjectをextendした空のクラスを、そうでない場合はなにもextendしていない空のクラスを定義し、実体の方はこの空のクラスをextendしていました。種明かしされれば「なぁ~んだ!」ですが、頭の固い私にはそのアイデアは出てこなかったです(^^;。

ちょうど、「連想くん」のハイブリッド化を検討していて、コンポーネントをそのまま使いたいと思っていたので、このやり方を早速採用してみたいと思います。

ちなみに、Cakeでない場合に「空のObjectクラスを定義してextendする」の方が手順が少ないですが、ほかのシステムでObjectが出てきたらアウトだから、こういう実装方法になっているんでしょうね。公開用のプログラムならアウトですが、自分で分かっていてやるのならこれでもアリですね。

【CakePHP】CakePHP1.2.0.7692出ました! が…

早速出てますね、新バージョンが!

というわけで、早速アップデートしてみました。
おそらくRC3導入してレポートするのは最速かも(笑)。

基本的に、従来RC2から必要なものを移動してくるだけで大丈夫そうです。
Tplcutterも丸ごとコピーしてからコンバートをかけ、そのまま表示できました。
連想くんのRC3化の所要時間2分程度(笑)。

問題点としては…
今回パフォーマンス改善があった、ということで期待してしまったのですが、実際は大して変わりませんでした。連想くんのトップページ(素のHTMLを表示するだけ)のabはRC2が26req/secであったのに対し、RC3は28req/secと、あまり変化無し。初期化部分はあまり改善されていないようです。大変に残念。

どのくらいソースが変わっているかは分からないのですが、viewについては見ておきました。render部分に若干手が入っていて、処理が簡略化されているようでした。ですが、基本処理は全く変わっていないので、おそらく現バージョンのSmartyViewで問題なく動くと思います。新バージョンを出すかどうかは現在悩んでいます。SmartyViewに関しては別途ご連絡したいと思います。

結論として、新規で作成するのは別として、アップデートの手間はそれほどかからないと思いますので、RC3にすること自体は問題ないかもしれません。ただ、パフォーマンス目当てで導入することについては、それほどでもないんじゃないか? という感じですね。モデル等使うとそれなりの改善があるかもしれませんけど、とりあえず初期化部分は相変わらず重い印象です。

【追記】
重いと言われていた?configure.phpを少し見てみました。
まず、uses()はrequireに置き換えられていました。
また、App::getInstance()でインスタンスを取得していた部分は直接呼び出す形式に。
その他、いくつか簡略化されている処理が見られました。
しかし、処理の流れそのものは変わっていませんので、「劇的な」は難しそうでした。
まだまだ気持ち程度ですかね。

【CakePHP】ハイブリッド運用の考察

昨晩から引き続きになりますが、Cake使用でのパフォーマンス改善の究極として「Cakeを使わないでCakeで作ったページを開けないものか?」というものがあります。

トップページなど、ぶっちゃけ処理が不要で表示のみのページは、直接テンプレートをインクルードして表示すればいいわけで、こうするだけでパフォーマンスが30倍は上がります。

実は、webroot直下にfuga.phpを置くことで、普通に「http://hoge.com/fuga.php」を開くことが出来ます。これは、mod_rewriteで、ファイルが存在している場合にはそのまま実行するように記述されているからです。
ところが、ホーム(/)や、「http://hoge.com/fuga」のような形式でアクセスしたい場合、mod_rewriteの設定をしてもうまくいかないようです。fuga.phpそのものは呼び出すことが出来るのですが、その中に記述されているcssやらjsファイルが取得できなくなってしまうのです。
回避する方法はちゃんとあるのかもしれませんが、とりあえずお手軽ということで、index.phpはそのまま読み込んで、指定URLで割り込んでしまうという形式を使うことにします。

まず、ファイルを読み込むためのピュアPHPファイルを用意します。
例えばindex_direct.phpとします。
次のように記述すると、レイアウトに配置されたビューテンプレートを表示できるようになります。

【index_direct.php】
<?php
    ob_start();
    include_once('../views/fuga/index.ctp');
    $content_for_layout =ob_get_clean();
    include_once('../views/layouts/fuga.ctp');
?>

index_direct.phpの置き場所は、webrootでもいいのですが、不要にアクセスされるのも良くないので、vendorsとかに入れておいた方が良いかもしれません。
そしてこのファイルを、index.phpの先頭で呼び出します。

【index.php】
※先頭に次の文を挿入

if($_GET['url'] == ''){  //ホームの場合はブランク
    include_once('./index_direct.php');
    return;
}

if文で、ダイレクトで表示させたいパスの場合分けをします。
GETパラメータを取得したい場合は、preg_match等で必要な部分を抜き出します。POSTは普通にとれると思います。

これで、とりあえずビューテンプレートそのものは表示できます。
問題点は、ヘルパーを使っている場合です。ヘルパーのインスタンスは一切定義されていませんから、エラーになります。また、当然ながらDBのアクセスなど、今までCakeにやってもらっていたものは自前で行わなければなりません。

上記問題さえ克服できれば、ピュアPHPで表示するのと大差ない速さで表示できるようになるので、これはこれで使えるかもしれません。処理の全くない素のページは、基本htmlやformのヘルパーを普通のHTMLの記述に戻す程度で処理を通すことが出来ると思います。

気持ちよくないのは、webroot内のindex.phpを中途半端に書き換える点ですね。
app内であることが救いですけど。
ちなみにapp/config/bootstrap.phpでカスタムな記述をするような慣習がありますが、ここに書いてしまうと基礎的なCakeシステムが読み込まれてたあとでの実行になってしまいますので、試してはいませんがパフォーマンスが食われてしまうのではないかと思います。

以上、裏技的なTipsでした。
こういった逆行する技術無しにCakeのパフォーマンスが上がるといいですね。

【CakePHP】Cakeのパフォーマンス問題を目の当たりにした!

今週は、サーバのメンテナンスがてら、ApacheやPHPのバージョンを上げたりいろいろしているのですが、その課程でCakeのパフォーマンス問題を目の当たりにしました。

当方のサーバは大変に非力で、セレロンな512MBメモリのサーバです(一応専用ですが)。abで調査してみると、某連想くんなサイトは20リクエスト/秒出ません(涙)。
どんなに非力でも100位は出るだろうと思っていたのですが…とんでもなかったです。Apacheのmpmも相当いじりましたが、サーバを硬直させないようにするのに精一杯といった感じです。

というわけで、「連想くん」を本サービスとして稼働させるには、いくつかの対策をたてなければならないです。

【対策案】
1:100倍は速いサーバに載せ替える(赤どころではない)
2:ビューキャッシュを用いる
3:そもそもCakeをやめる

正直、1は現実的でないです。懐が大変に厳しくて…
誰か恵んでください(^^;;;。

2については、サイト構成の改良が必要になりそうです。当方の作り方として、フォームのバリデーションを呼び出し元に置いて、OKなら目的ページへリダイレクトしているので、キャッシュを効かせるとバリデーションとリダイレクトがされなくなってしまいます。なので、キャッシュの効かない別ページで処理をさせるといった手法が必要になりそうです。ただ、アクセス数の多いトップページなどはこのやり方が有効ですが、トータルではあまり解決になっていないかも。

ということは、真面目に3を考えなければならないかもしれません。
正直「連想くん」はそれほど複雑ではなく、ぶっちゃけCakeなしで出来てしまうものなので、3は問題のないレベルです。しかし、現時点で企画が進行している次のサービスについては、フレームワークがあることで大変に開発が簡素化できる内容であり、3を非常に考えにくい…

最近Cakeのフォーラムでも話題が上がっているのですが、ディスパッチャあたりの処理が大変に重いとのことで、ソースを眺めてみると、確かにその片鱗が伺えます。なんというか、同じ関数を何度も呼びに行っていたりとか、たかだかパスを作るのに凄い複雑な処理を走らせているとか。結構無駄がありそうです。

1.2になって、いろいろと仕様が増えているのですが、正直過剰になってきているような気がします。例えばimportとかも、require_onceで済むような内容についても構わずものすごい処理が走ります。

ここに来て、いろいろドキュメントを残したり、ツールを作ったりしていて言うのもなんですが、なんでもCake 、というのはどうかと思い始めてきました。
公開用のサービスは、やはりパフォーマンスを考えてピュアPHP、というのも選択肢の一つに入れておいた方が良さそうです。
管理ツールなどは、リクエスト数など気にしなくても大丈夫ですし、特にアソシエーションが管理機能の実現にマッチしていると思いますから、Cakeは結構有効だと思います。

公開サービス向けの、Cakeまで大げさでない、簡素なフレームワークがあると良いですね。
Cake側でパフォーマンスチューニングしてくれると一番良いんですけど…

なんかCakeを悪者のように書いてしまっていますが、これはSynfonyを使ってもZendFrameworkを使っても同じような問題に直面するはずです(使っていないので何とも言えないですけど)。フレームワークは一般的に、作りやすくする反面パフォーマンスを犠牲にしますからね。

話は大きく変わって「連想くん」ですが、新しいバージョンになり、連想単語の入力が不要になりました。自分で言うのもアレですが、使い方次第でなかなか面白いサービスだと思います。連想単語をさらに連想検索できるので、さかのぼっていくと良い暇つぶしが出来ます(笑)。
DBのデータの持ち方を変える必要が出てきたので、そこを修正しなければならないのですが、DB関連を外したものをまず公開してしまおうかとも。今日明日中にアップデートしてみます。

【Tplcutter】Tplcutter0.2.0公開いたします

新バージョンのTplcutter バージョン0.2.0を公開いたします。

先日指摘しましたelement関連の不具合の修正と、新機能である「ピース」機能の実装をいたしました。

「ピース」機能を簡単に説明いたしますと、エレメントは「繰り返し流用したい部分をあらかじめファイルに書き出しておき、それを呼び出す」機能であるのに対し、「繰り返し流用したい部分をあらかじめメモリに蓄積しておき、加工時に指定の場所にコピーする」機能を提供します。こうすることで、実際の表示の際に余分な処理を抑えることが出来、展開速度の向上を見込むことが出来ます。

なお、ピースは同一アプリケーション内であれば、テンプレート内のどの場所に記述しても有効に働きます。つまり、指定した領域のあるテンプレートファイルと異なったテンプレートファイル内でも呼び出すことが出来ます。

使用例はサンプルファイル内にありますので、そちらをご覧いただけますと幸いです。

とりあえず使えるツールになったっぽいので、よほどのバグがない限り、しばらくバージョンアップは控えることにします。まだいくつかやりたい機能はありますが、それは現在構築している新企画サイトの作成が終わってからにしたいと思います。

*************************************************
    テンプレート加工ツール「Tplcutter」簡易説明書
    Copyright (C) 2008 ECWorks ( http://ecw.seesaa.net/ )
*************************************************
 設置方法など詳細につきましては、アーカイブ内のドキュメントをお読みください。

————————————————–
■はじめに
————————————————–

 現在主流になりつつある、フレームワークを用いたWEBアプリ開発では、HTMLファイルやPHPファイルを直接表示する手法は少なくなり、Viewシステムを介してテンプレートファイルを読み込み、それを加工した後に表示する手法が一般的となりました。
 ところが、テンプレートファイルは通常外部から見えない領域に格納されるため、デザイン編集作業の際にテンプレートファイル内に記述する画像など表示物等のリンクが実際のリンクと異なってしまうため、編集が困難になるという問題が発生します。

 そこで、デザイン時では普通のHTMLを編集するような感覚でデータを作成し、それらテンプレートとその他ファイルを適切な位置に配置できるようなツールが実現できないかと考え、本ツール「Tplcutter」を開発しました。
 デザイナー側から見ますと、サイト制作ツール等で編集可能なディレクトリ構造のまま作業し、それをそのままプログラマー側に受け渡せます。また、テンプレートは読み込んで加工したものを別のディレクトリに作成し、その他表示物はコピーしますので現在稼働しているサイトのデザインを崩すことなく直接編集することも可能です。
 そして、最大のメリットとしては、コマンド一発で全てのテンプレートを更新することにあります。デザイナーによって制作されたテンプレートを適用するためには、これらファイルを加工したり、異なるディレクトリに配置したりする必要がありました。デザインが変更されるたびにこの作業を行わなければならないため、無駄な手間が発生します。本ツールはこれら作業を自動化しますので、時間の節約や更新間違い等による不具合の発生を極力防ぐことが出来ます。
 本ツールは、もともとCakePHPフレームワークにて利用できるように開発したのですが、SmartyやSynfony等、ほかのフレームワーク・テンプレートシステムでも利用できるように、PHPコマンドラインでも利用できるよう拡張いたしました。ini形式ファイルにて細かな設定が出来ますので、幅広いシステムで使用することができます。

————————————————–
■動作環境
————————————————–

 本ツールは、CakePHP1.2.xのCakeコンソール、もしくはPHP4/5のコマンドラインで使用することが出来ます。

 CakePHPにてテンプレートを利用する場合は、Cakeコンソールで使用することで、ほぼ無設定でCakePHP向けのテンプレート加工をします。
 同様に、PHPのコマンドラインから利用する場合は、ほぼ無設定でPHP向けのテンプレート加工をします。

 どちらの方法でも、ini形式ファイルにて設定することで、異なるテンプレートシステム向けの加工をすることも可能です。

————————————————–
■ご利用条件
————————————————–

 本ツール一式は使用もしくは再配布について、無料でご利用いただけます。
 本ツールおよびアーカイブ内に含まれる全ての著作物に対する権利はECWorksが保有しており、GNU一般公衆利用許諾契約に基づいて配布しております。再配布・改変等は契約の範囲内で自由に行うことが出来ます。詳しくは、添付のGNU一般公衆利用許諾契約書をお読みください。
 なお、本ツールは一般的な利用において動作を確認しておりますが、ご利用の環境や状況、設定もしくはプログラム上の不具合等により期待と異なる動作をする場合が考えられます。本ツールの利用に対する効果は無保証であり、あらゆる不利益や損害等について、当方は一切の責任をいたしかねますので、ご了承いただきますようお願い申し上げます。

▼ダウンロードはこちら
tplcutter-0.2.0.zip

【SmartyView】SmartyView1.2.0.7296 For CakePHP1.2

 CakePHP1.2用SmartyViewの最新版を公開いたします。

 このViewを利用することで、SmartyテンプレートをCakePHPで利用することが出来ます。
 ご利用には別途Smartyテンプレートシステムを用意する必要があります。

 Bakeryにも1.2用SmartyViewが紹介されているのですが、CakePHP1.2.0.6311betaあたりから仕様の合わない部分や不具合等がいくつかありましたので、作り直して公開しております。基本的に、アーカイブを解凍していただき、そのままのディレクトリ構造をcakeシステムに適用していただければ動作すると思いますので、導入は簡単です。是非ご利用ください。

 詳しくは、アーカイブ中のreadmeをお読みください。

※RC1版と比べ、コードはだいたい同じなのですが、ヘルパーの呼び出し方法が違う等若干異なっています(view.phpのアップデート由来です)。RC1で本バージョンを使用した場合も、おそらく動作はするとは思いますが、どのような挙動をするかまでは良く分かりませんので、一応無保証でお願いします。

ダウンロードはこちら

▼CakePHP1.2.0.7296 RC2向け
smartyview-1.2.0.7296.zip

CakePHP1.2RC1/beta版のSmartyViewは こちら で紹介しています。

第3回CakePHP勉強会に行けなくなりました…

仕事の都合で、勉強会に行けなくなりました。
ライブ中継もするみたいですが、それも観ることが出来ません。 
非常に残念です。
つーか、参加申し込みにもれてしまった人に申し訳なかったです。

とりあえず、後で上がるだろうレポや資料で我慢します。