PowerCMS™
[ブログ] PowerCMS 6 でのアップデートまとめ を追加しました。
[新着情報] 多要素認証設定画面の QR コードが表示されない問題への対策ファイル を追加しました。
[新着情報] PowerCMSクラウド 月額費用の価格改定に関する追加情報を公開します を追加しました。
[よくあるご質問] サポートサイトへ登録しているアカウントの情報を変更することはできますか? を追加しました。

PowerCMS ブログ

ホーム > PowerCMS ブログ > テンプレート作成Tips > DynamicMTML(ダイナミックパブリッシング) で動的インクルードを使うと Smartyのコン…

2016年01月21日

DynamicMTML(ダイナミックパブリッシング) で動的インクルードを使うと Smartyのコンパイルキャッシュの効果が限定的になる

最近 PowerCMS や MTのダイナミックパブリッシングで大きなモジュールをインクルードすると思うようなスピードが出ないケースに遭遇しました。調査にあたっては SpeedMeterプラグインを利用しました。

モジュール インクルードサンプル の中では以下のように前後半を分けて、どの部分が時間を要しているのかを調査しようとしました。

インクルード元

<mt:SpeedMeter name="モジュール全体">
<mt:Include module="インクルードサンプル">
</mt:SpeedMeter>

モジュール内

<mt:SpeedMeter name="モジュール前半">
# 大量のMTMLを含むテンプレートのコード
</mt:SpeedMeter>
<mt:SpeedMeter name="モジュール後半">
# 大量のMTMLを含むテンプレートのコード
</mt:SpeedMeter>

こうしてテンプレートのビルドブロックごとのビルド時間を計測していったのですが、不思議な数値が出たのです。

  • 'モジュール全体'をビルドしました。処理時間: 2.50459890365601
  • 'モジュール後半'をビルドしました。処理時間: 0.00037813186645508
  • 'モジュール前半'をビルドしました。処理時間: 0.19418096542358

前後半をあわせて0.2秒にも満たないのにテンプレート全体では2.5秒もかかっています。大きなテンプレートをSQLでロードするのに時間がかかっているのかと疑い、ファイルインクルードにしましたが速くなったのは誤差程度。

そこで、mt:Includeのコードを確認しました。

mt/php/lib/function.mtinclude.php

ob_start();
$ctx->_eval('?>' . $_var_compiled);
$_contents = ob_get_contents();
ob_end_clean();

ここでピンと来たのですが、MTのダイナミックパブリッシング(DynamicMTMLも基本は同じ)では、以下の順で処理が行なわれます。

  1. .htaccessによってリクエストが .mtview.php に渡される
  2. DynamicMTML では addons/DynamicMTML.pack/php/dynamicmtml.run.php 経由で、MTでは直接 php/mt.php が処理を担う
  3. プラグインの初期化や設定情報等を初期化(一部DBへのアクセス有り)
  4. mt_fileinfoレコードを検索し、必要なオブジェクトをデータベースから取得し、ページのコンテキストをセット
  5. テンプレートをロードし、MTMLを取得する
  6. MTViewer.php がテンプレートをビルドする

class MTViewer(MTViewer.php)は PHPのテンプレートエンジン Smartyの拡張クラスで、prefilter.mt_to_smarty.php の中の smarty_prefilter_mt_to_smarty 関数がテンプレートの処理の冒頭に呼ばれます。この処理は MTML(MTタグ)を正規表現によってパースし、Smartyのコンパイル形式に変換し、その後ページの処理が行なわれます。

$this->load_filter('pre', 'mt_to_smarty');

Smarty のコンパイル処理は PHP のネイティブコードを生成し、各ウェブサイト/ブログ以下の templates_c/ ディレクトリにコンパイル済みの状態で保存されます。一度作成してしまえば、その後はコンパイルされた PHP スクリプトが実行され、テンプレートに更新があった時のみ再コンパイルされます。

templates_c ディレクトリに保存されたコンパイルキャッシュ

動的MTInclude ではコンパイル結果はキャッシュされない

このケースの 2.X秒はこのコンパイル処理だったのでした。数千行ある巨大なMTタグを含むモジュールを MTIncludeしていたので、その部分が毎回コンパイルされていたというわけです。

対策はモジュールを静的インクルードすること

対策はモジュールを静的インクルードすることです。以下は改修前のコンパイルキャッシュです。MTInclude タグのみがキャッシュされています。

改修前のコンパイルキャッシュ

モジュールの中を以下のように変更します。

<mt:Unless regex_replace="/^\s*\n/gm","" trim="1">
    <mt:DynamicMTML>
        # モジュールの中身
    </mt:DynamicMTML>
</mt:Unless>

インクルード元のテンプレートの下記の部分を変更します。

    <mt:DynamicMTML>
        <mt:Include module="インクルードサンプル">
    </mt:DynamicMTML>

これを、静的インクルードにします。

    <mt:Include module="インクルードサンプル">

これで、MTInclude タグの中身が展開された上でキャッシュされました。

改修後のコンパイルキャッシュ

これでページの表示速度が大きく改善しました。複雑で巨大なMTタグを含むテンプレートモジュールをダイナミックでインクルードしている時には意識すると良いと思います。但し、コンパイルキャッシュのサイズが 1MBを超えるなど、巨大になってしまうと今度はまた逆に速度低下の要因となります。

テンプレートをコンパクトにしつつ、コンパイルキャッシュの恩恵をうけるために 静的インクルードを使う、というのが今回のポイントでした。


カテゴリー
DynamicMTML
テンプレート作成Tips
トラブルシューティング

Recent Entries