MODx EvoのCacheAccelerator。 動的なスニペットをキャッシュすることにより、データベースへのクエリの数を減らす

みなさんこんにちは。 私は最近、MODxのCMFと会談しました。 現在の進化バージョンを習熟。 システム全体は非常に快適で非常に柔軟ですが、よく見てみると、いくつかの欠点が見つかりました。 さらに、一部の人は私に休息を与えず、そのままにしておくことはできませんでした。

CMS / CMFの最も敏感な基準の1つであるパフォーマンスについて説明します。
一般に、パフォーマンスにはMODxにすべてのルールがあります。 彼自身は非常に有能に書かれ、最適化されています。 さらに、その柔軟性により、開発者は実装中のプロジェクトのボトルネックを管理することができます。

ただし、Dittoを使用してニュース出力を処理する方法、Jotを使用してコメントなどを処理する方法に単純にショックを受けました。 つまり、Dittoのページ全体(PHxでの作業の問題による)と、Jotスニペット自体の呼び出しの両方でキャッシュを無効にする必要があります。

実際、多数のエントリがある場合、それらは1ページに収まりません。つまり、たとえば、ニュースフィードを複数のページに分割する必要があります。 ただし、このページのキャッシュがMODxに含まれている場合、ニュースフィードの部分を切り替えると、最初にキャッシュにヒットしたコンテンツがすべて表示されます。

公式ソースは何をアドバイスしていますか?
彼らは、スニペットが複数の
キャッシュされないページ。

DittoとJotを呼び出す例を次に示します。

スニペット呼び出しページがキャッシュされない「ページ設定=>キャッシュ=>オフ」
[[Ditto?
&parents=`1`
&display=`10`
&paginate=`1`
&paginateAlwaysShowLinks=`1`
]]


スニペット呼び出しページは「ページ設定=>キャッシュ=>オン」にキャッシュされます
[!Jot?
&customfields=`name,email`
&pagination=`10`
&badwords=`*****`
&canmoderate=`Site Admins`
&captcha=`1`!]
!]


ご覧のとおり、どちらの場合もMODxによるキャッシュは実行されません。 キャッシュの欠如は、システムの速度に直接影響します。 ページが呼び出されるたびに、すべてのスニペットデータがデータベースから収集されます。

私のテストによれば、タイトル、簡単な注釈、公開日を表示する、ページあたり10エントリのDitto呼び出しページは、データベースに対して約11のクエリを作成します。 追加のフィルターを使用して、テレビのフィールドで用語を検索すると、さらに憂鬱な統計が得られます。
画像
デモ

Jot呼び出しページでも同じことが起こります。
ページごとに10個のコメントを付けてJotを呼び出し、それぞれについての標準情報
コメントと新しい投稿を追加するフォームを使用して、注文も作成します
データベースへの22-24クエリ。
画像
デモ

データベースが非常に小さい限り、これは重要ではありませんが、データベースの成長に伴い、このような数の要求により、ドキュメント数に対して応答時間が指数関数的に増加します。

少し考えてから、1つのモジュール、1つのスニペット、およびサードパーティライブラリで構成されるCacheAcceleratorを作成しました。

Cache Acceleratorは、任意のスニペット(DittoおよびJotだけでなく)の出力をキャッシュすることにより、システムの速度を上げ、データベースへのクエリの数を減らします。

テストによると、上記のDittoを使用したページへの繰り返しリクエストは、データベースへの呼び出し回数を11から3(!)に減らし、Jotを使用したページへの呼び出しを22から1(!)に減らすという形で結果をもたらします。
画像画像

この製品は、MODxエンジンへの統合のハック方法を使用しません。 これは完全に独立したコードブロックです。 インストールと使用が非常に簡単です。

インストール:

まず、ページからfileCacheをダウンロードします。
http://neo22s.com/filecache/

いずれかの直接リンク:
http://lab.neo22s.com/fileCache/fileCache.zip

ディレクトリ/アセット/プラグイン/ cacheacceleratorを作成します
cacheacceleratorディレクトリで、キャッシュディレクトリを作成します(/ assets / plugins / cacheaccelerator / cache)
作成された両方のディレクトリにchmod 777をインストールします

次に、ダウンロードしたアーカイブから、fileCache.phpをディレクトリ/ assets / plugins / cacheacceleratorにコピーします

その後、MODxマネージャーで、[ 要素 ]-> [ 制御要素] -> [ スニペット] -> [ 新しいスニペット ]をクリックします。 CacheAcceleratorという新しいスニペットを作成します。
画像

画像

画像

画像

スニペットの内容をそこにコピーします。

CacheAcceleratorスニペット:

<?php
// . Ditto
if(!function_exists(cacheFieldsCompare)) {
function cacheFieldsCompare ($param1, $param2, $param3){
/*
1 or !=
2 or =
3 or <
4 or >
5 or <=
6 or >=
7
8
*/
switch($param3){
case 1:
return $param1 != $param2;
break;
case 2:
return $param1 == $param2;
break;
case 3:
return $param1 < $param2;
break;
case 4:
return $param1 > $param2;
break;
case 5:
return $param1 <= $param2;
break;
case 6:
return $param1 >= $param2;
break;
case 7:
return stristr($param1, $param2);
break;
case 8:
return !stristr($param1, $param2);
}
}
}

$nocache = isset($nocache)? $nocache : 0; //
$url = $_SERVER["REQUEST_URI"]; // ,
$path_to_cacheengine=$modx->config['base_path']."assets/plugins/cacheaccelerator/"; // CacheAccelerator
$path_to_cache=$modx->config['base_path']."assets/plugins/cacheaccelerator/cache/"; // ( )
require_once ($path_to_cacheengine."fileCache.php"); // fileCache
$cache = fileCache::GetInstance(84600*7,$path_to_cache);// fileCache

//
if((int)$clearCache){
if($logMessages) echo("Clearing cache...");
$cache->deleteCache(0);
return;
}

// , ( , )
$noCacheGroups = isset($noCacheGroups) ? $noCacheGroups : "";
$nocache = intval($modx->isMemberOfWebGroup(explode("||",$nocacheGroups)) || $modx->checkSession()) ? 2 : $nocache;
if($nocache == 2){
if($logMessages) echo("No caching for this web group.");
}

/* -, . , */
if(isset($dropCacheField)){
$fieldsArray = explode("||", $dropCacheField);
foreach ($fieldsArray as $field){
$field1 = explode(";", $field);
if($field1[1] && $field[2]){
if(empty($field1[0])){
foreach ($_POST as $key => $postField){
if(cacheFieldsCompare($postField, $field1[1], $field1[2])){
$nocache = 1;
continue;
}
}
foreach ($_GET as $key => $getField){
if(cacheFieldsCompare($getField, $field1[1], $field1[2])){
$nocache = 1;
continue;
}
}
} else {
if(!empty($_POST[$field1[0]])){
if(cacheFieldsCompare($_POST[$field1[0]], $field1[1], $field1[2])){
$nocache = 1;
continue;
}
}
if(!empty($_GET[$field1[0]])){
if(cacheFieldsCompare($_GET[$field1[0]], $field1[1], $field1[2])){
$nocache = 1;
continue;
}

}
}
} else {
if(!empty($_POST[$field1[0]]) || !empty($_GET[$field1[0]]))
$nocache = 1;
}
}

//
if($nocache == 1){
if($logMessages) echo(" Clearing cache... ");
$cache->deleteCache(0);
}
}

//
if($nocache == 0){
$cached = $cache->cache($cacheId.$url);
if(isset($cached)){
if($logMessages) echo(" Cache hit! ");
$modx->placeholders = $cached['placeholders']; //
return $cached['content']; //
}
}

$output = $modx->runSnippet($snippetToCache, $modx->event->params); //

//
if($nocache == 0){
if($logMessages) echo("Storing to cache...");
$cache->cache($cacheId.$url,array('placeholders' => $modx->placeholders, 'content' => $output));
}
// MODx
return($output);
?>


作成したスニペットを保存します。 次に、[ プラグイン ]タブに移動します。
プラグインの作成 ] クリックします
画像

画像

CacheAcceleratorClearという名前を付けます。 プラグインの内容をコピーします。

CacheAcceleratorClearプラグイン:

$path_to_cacheengine=$modx->config['base_path']."assets/plugins/cacheaccelerator/"; // CacheAccelerator
$path_to_cache=$modx->config['base_path']."assets/plugins/cacheaccelerator/cache/"; // ( , CacheAccelerator)
require_once ($path_to_cacheengine."fileCache.php");// fileCache
$cache = fileCache::GetInstance(84600*7,$path_to_cache);// fileCache
$cache->deleteCache(0);//
return;


注意! プラグインの内容をコピーしたら、[ システムイベント ]タブに移動します。このタブで、[ キャッシュサービスイベント]セクションの[OnCacheUpdate]イベントをオフにします。
[ 保存]ボタンをクリックしてください。
画像
画像
以上で、CacheAcceleratorのインストールは完了です。

このプラグインは1つの機能を実行します。 MODxがキャッシュをフラッシュするとき、CacheAcceleratorキャッシュもフラッシュします

CacheAcceleratorを使用します:

CacheAcceleratorは、どのスニペットにも絶対に使用できます。 出力をキャッシュします。
それまでは、DittoとJotの呼び出しの例での使用を検討します。

Ditto呼び出しは次のようになります。
[[CacheAccelerator?
&snippetToCache=`Ditto`
&cacheId=`News`
&parents=`1`
&display=`10`
&paginate=`1`
&paginateAlwaysShowLinks=`1`
]]


Ditto自体を呼び出す代わりに、CacheAcceleratorスニペットが呼び出され、キャッシュされたスニペットの名前(この場合はDitto)がsnippetToCacheパラメーターで指定されます。
次はcacheIdパラメーターです。 ページに複数のキャッシュされたスニペットがある場合、キャッシュされたコンテンツを分離するように設計されています。 たとえば、左側のメニュー、最新のニュース、ニュースフィード自体。 キャッシュされたコンテンツがバインドされる任意の値を含めることができます。
Dittoが二重角括弧[[]]で呼び出された場合、この呼び出しもそれらに含まれている必要があることに注意してください。

Jot呼び出しの例:
[!CacheAccelerator?
&snippetToCache=`Jot`
&cacheId=`Comments`
&dropCacheField=`JotForm||post;true;2||;publish;2||;unpublish;2||;delete;2||;edit;2`
&noCacheGroups=`Site Admins`
&customfields=`name,email`
&pagination=`10`
&badwords=`*****`
&canmoderate=`Site Admins`
&captcha=`1`
!]


キャッシュされたスニペット自体もsnippetToCacheパラメーターで指定され、cacheIdではページ上のキャッシュされたコンテンツの識別子で指定されます。
dropCacheFieldとnoCacheGroupsの2つのパラメーターがあります。 それらについてさらに詳しく説明します。

事実は、MODxマネージャーから追加されるニュースブロックとは異なり、各ニュースを追加した後にキャッシュがクリアされるJotコメントフィードでは、サイトにアクセスしたユーザーはコメントを追加できます。 同時に、このコメントを彼と他のユーザーの両方に表示するには、CacheAcceleratorキャッシュをクリアする必要があります。 このアクションは、Jotだけでなく、出力をキャッシュする他の多くのスニペットにも必要な場合がありますが、ユーザーのアクション後にキャッシュを更新する可能性も提供します。
これらの目的のために、dropCacheFieldパラメーターも機能します。
||で区切られた条件のリストが含まれています これらの条件のいずれかがトリガーされると、CacheAcceleratorキャッシュがクリアされます。

条件はフィールド名です。
GETまたはPOSTリクエストでどちらが検出されると、キャッシュが更新されます。

これは、比較のかもしれません。
セミコロンがリストされます。
;;_
フィールド名自体が空として示されている場合、すべての既存のフィールドが比較されます。

以下に例を示します。
&dropCacheField=`JotForm||post;true;2||;delete;2`

ここに示されています:

偶然に、キャッシュはクリアされます。

Jotで新しいメッセージを投稿すると、JotFormフィールドを含むフォームが送信されます。 したがって、コメントを投稿した後、キャッシュはクリアされ、情報は関連したままになります。 このページへの最初の要求の後、キャッシュが再び作成され、後続の呼び出しがキャッシュから提供されます。

noCacheGroupsパラメーターには、||で区切られたリストが含まれます。リストには、データがキャッシュから返されないWebユーザーのグループが含まれ、スニペットは呼び出しごとに実行されます。 たとえば、モデレーターの場合、出力フォームはコントロールボタンによって異なり、そのようなリクエストがキャッシュに入ると、他のログインユーザーにも、リクエストに関係のない要素を持つフォームが表示されます。
また、デフォルトでは、MODxマネージャーで許可されているユーザーのキャッシュ処理は行われません。 また、あなたが資料を編集しているユーザーが管理パネルのメンバーである場合、この問題は自然に消えます。

以下を呼び出すことで、どこからでもCacheAcceleratorキャッシュをクリアすることもできます。
チャンクから:
[!CacheAccelerator? &clearCache=`1`!]

スニペットから:
$modx->runSnippet("CacheAccelerator", array("clearCache" => 1))

キャッシュ可能なスニペットで定義されたプレースホルダーもキャッシュから呼び出されたときにキャッシュおよび登録されます。

例:
[[CacheAccelerator?&snippetToCache=`Ditto`&cacheId=`News`]]
[+start+] - [+stop+] [+total+] <br>
[+previous+] [+pages+] [+next+]<br>


パラメータリスト:
snippetToCache-キャッシングのスニペット名。たとえば、 `Ditto`。
cacheId-ページ上のキャッシュされたスニペットの識別子。たとえば、「News」
dropCacheField-フィールドとそれらの条件のリスト。これにより、キャッシュがリセットされます(例: `JotForm || post; true; 2`)
noCacheGroups-キャッシュ処理が実行されないグループのリスト。たとえば、「admins || moderators」
clearCache-値が1の場合、キャッシュは強制的にクリアされます。
logMessages-スニペットのコンテンツの前の値が1の場合、キャッシュへのアクセスに関するシステムメッセージなどが表示されます。

条件のリスト:
1 !=等しくない
2 =等しい
3 <より小さい
4 >以上
5 <=より小さいか等しい
6 > =以上
7含む
8が含まれてい

このサイトでCacheAcceleratorの完成版をダウンロードできます。

決して完成品のふりをして、その作業にエラーがないことはありません。 これは最初のアルファ版であり、このようなマニュアルを作成した経験はほとんどありません。
欠点やエラーの開発と解消にご協力いただければ幸いです。

UPD


新しいパラメータは、スニペット:
noCacheRoles-キャッシュ処理が実行されないマネージャーロールのリスト
たとえば、「管理者||編集者」

checkURL-異なるURLに個別のキャッシュを作成します(1 | 0)。 これは、デフォルトで有効になって。 インクルードは、ページナビゲーションスニペ​​ットに役立ちます。

また、プラグインの新しいパラメーター:
only_manual-キャッシュの手動リセットのみを許可します。

Andchirの改訂に感謝します。

新しいバージョンは、ここまたはここ からダウンロードできます。

Source: https://habr.com/ru/post/J113719/


All Articles