WordPressページキャッシング

画像



最近、このトピックに関する多くの投稿がHabréに掲載されていますが、本質的には「Varnish / W3 Total Cacheをインストールし、「Hello world page」に100万のリクエストを保持しています」と呼ぶことができます。 この記事は、すべてがどのように機能するかを知り、ページキャッシング用の独自のプラグインを作成したいオタクを対象にしています。



なんで?



既存の機能のバイクを作成する前に各開発者に生じる標準的な質問。 実際、既製のプラグインは数多くあり、その多くは非常に高品質ですが、それらは主に静的なブログ向けに設計されていることを理解する必要があります。 標準のWordPressサイトがない場合はどうすればよいですか?



さあ始めましょう



WordPressが提供するツールは何ですか?



誰もが知っているように、このCMSはプラグインを使用してその機能を簡単に拡張できますが、いくつかのタイプのプラグインがあることを誰もが知っているわけではありません。





advanced-cache.php



このプラグインが機能を開始するには、それをwp-contentディレクトリに配置し、 wp-config.phpに次の行を追加する必要があります。
define('WP_CACHE', true);
      
      





WordPressコードを見ると、このスクリプトがプラットフォームの読み込みの初期段階で読み込まれていることがわかります。

 // wp-settings.php:63 // For an advanced caching plugin to use. Uses a static drop-in because you would only want one. if ( WP_CACHE ) WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' );
      
      





また、カーネルをロードした後、CMSはwp_cache_postload()関数を呼び出そうとしますが、それについては後で詳しく説明します。

 // wp-settings.php:226 if ( WP_CACHE && function_exists( 'wp_cache_postload' ) ) wp_cache_postload();
      
      







保管



キャッシュを保存するには、キャッシュからコンテンツを返す速度がその速度に直接依存するため、高速ストレージを使用するのが最適です。 MySqlまたはファイルシステムの使用はお勧めしませんが、Memcached、Redis、またはRAMを使用する他のストレージはそれをはるかに上手く行います。



私は個人的にRedisが好きです。使用するのが非常に簡単で、読み取り/書き込み速度が優れており、素晴らしいボーナスとしてデータのコピーをハードドライブに保存するため、サーバーの再起動時に情報を失うことはありません。

 $redis = new Redis(); //    $redis->connect( 'localhost' ); //   $value   $key   $timeout $redis->set( $key, $value, $timeout ); //     $key $redis->get( $key ); //     $key $redis->del( $key );
      
      





もちろん、これはメソッドの完全なリストではなく、APIのリスト全体を公式Webサイトで調べることができますが、ほとんどのタスクではこれで十分です。



サイトがポンピングされたオブジェクトキャッシュ( object-cache.php )を使用している場合、そのAPIを使用するのは理にかなっています:

 wp_cache_set( $key, $value, $group, $timeout ); wp_cache_get( $key, $group ); wp_cache_delete( $key, $group );
      
      







最も単純なページキャッシング



読者を不必要な構成と混同せず、キャッシュ自体のロジックに焦点を合わせないように、コードは意図的に簡素化され、多くのチェックが削除されました。 advanced-cache.phpファイルで、次のように記述します。

 //      ,     , //          wp_start_object_cache(); //   //    URL  $key = 'host:' . md5( $_SERVER['HTTP_HOST'] ) . ':uri:' . md5( $_SERVER['REQUEST_URI'] ); //       if( $data = wp_cache_get( $key, 'advanced-cache' ) ) { //   ,      $html = $data['html']; die($html); } //   ,   //        if( ! is_admin() ) { //    ob_start( function( $html ) use( $key ) { $data = [ 'html' => $html, 'created' => current_time('mysql'), 'execute_time' => timer_stop(), ]; //         10  wp_cache_set($key, $data, 'advanced-cache', MINUTE_IN_SECONDS * 10); return $html; }); }
      
      







以上で、最も簡単な作業ページキャッシュが得られました。次に、各セクションをさらに詳しく見てみましょう。



キー作成
 $key = 'host:' . md5( $_SERVER['HTTP_HOST'] ) . ':uri:' . md5( $_SERVER['REQUEST_URI'] );
      
      



この場合、キーはページのURLです。 $ _SERVERグローバル変数とハッシュを使用するのは良い習慣ではありませんが、簡単な例では問題ありません。 正規表現で使用すると便利なため、文字列の区切りセクションを「host:」と「uri:」として追加することをお勧めします。 たとえば、特定のホストのすべてのキーを取得します。
 $keys = $redis->keys( 'host:' . md5( 'site.com' ) . ':*' );
      
      





キャッシュからの問題

 //       if( $data = wp_cache_get( $key, 'advanced-cache' ) ) { //   ,      $html = $data['html']; die($html); }
      
      



ここではすべてが簡単です。キャッシュが既に作成されている場合は、ユーザーにキャッシュを発行して実行を完了します。



キャッシュに保存

PHP関数ob_startは、バッファーへの後続の出力をすべてインターセプトし、スクリプトの最後で処理できるようにします。 簡単に言えば、すべてのサイトコンテンツを$ html変数で取得します。
 ob_start( function( $html ) { // $html - HTML    return $html; }
      
      





次に、データをキャッシュに保存します。
 $data = [ 'html' => $html, 'created' => current_time('mysql'), 'execute_time' => timer_stop(), ]; wp_cache_set($key, $data, 'advanced-cache', MINUTE_IN_SECONDS * 10);
      
      





HTMLだけでなく、キャッシュ作成時間などのその他の有用な情報も保存することは理にかなっています。 少なくともContent-Typeの HTTPヘッダーを保存し、キャッシュから発行されたときに送信することを強くお勧めします。



改善



上記の例では、 is_admin()関数を使用して管理パネルのキャッシュを除外しましたが、この方法は2つの理由であまり実用的ではありません。



単純なサイトの最適なソリューションは、ログインユーザー(管理者)にキャッシュをまったく使用しないことです。 カーネルが完全にロードされる前にadvanced-cache.phpが実行されるため、 is_user_logged_in()関数を使用できませんが、Cookieが認証されているかどうかを判断できます(ご存知のとおり、WordPressはセッションを使用しません)。

 //   cookie wordpress_logged_in_* $is_logged = count( preg_grep( '/wordpress_logged_in_/', array_keys( $_COOKIE ) ) ) > 0; //       if( ! $is_logged ) { ob_start( function( $html ) use( $key ) { // .... return $html; }); }
      
      







タスクを複雑にします



私たちのサイトが異なる地域や国のユーザーに異なるコンテンツを提供しているとしましょう。 この場合、キャッシュキーはページURLだけでなく、リージョンでもある必要があります。
 $region = get_regeon_by_client_ip( $_SERVER['REMOTE_ADDR'] ); $key = 'host:' . md5( $_SERVER['HTTP_HOST'] ) . ':uri:' . md5( $_SERVER['REQUEST_URI'] ) . ':region:' . md5( $region );
      
      





この原則によれば、パラメーターに応じて、ユーザーグループごとに異なるキャッシュを作成できます。



wp_cache_postload()



この関数はカーネルをロードした後に呼び出され、場合によっては使用するのにも便利です。

経験から、このオプションははるかに安定して動作すると言います。
 function wp_cache_postload() { add_action( 'wp', function () { ob_start( function( $html ) { // ... return $html; }); }, 0); }
      
      





wp_cache_postload()の呼び出し時に、add_action関数は既に存在し、使用できます。



キャッシュキーを生成するために、Cookie、IP、および初期化段階で利用可能なその他のリソースから取得できないデータが必要な場合があります。 たとえば、ユーザーごとに個別のキャッシュを生成する必要があります(これは理にかなっています)。
 function wp_cache_postload() { $key = 'host:' . md5( $_SERVER['HTTP_HOST'] ) . ':uri:' . md5( $_SERVER['REQUEST_URI'] ) . ':user:' . get_current_user_id(); if( $data = wp_cache_get( $key, 'advanced-cache' ) ) { $html = $data['html']; die($html); } add_action( 'wp', function () { ob_start( function( $html ) { // ... return $html; }); }, 0); }
      
      





この例でわかるように、すべてのロジックはwp_cache_postloadの本体に配置され、 get_current_user_id()を含むすべてのプラットフォーム関数がここですでに利用可能です。 このオプションは前のものより少し遅いですが、ページキャッシュを微調整する無限の可能性があります。



忘れてはならないもの



  1. プロジェクトで使用する場合、これらの例は非常に単純化されています。キャッシングの条件を追加するのに面倒くさくないでください。

    • リクエストのみ取得
    • ページにエラーがない場合のみ
    • Cookieが設定されていない場合のみ
    • ステータス200または301の場合のみ
  2. キャッシュの有効性は、その寿命に依存します。 $タイムアウトを増やすときは、データを変更するときにキャッシュの無効化を考慮するために問題を取ります。
  3. WP Cronは、後でadvanced-cache.phpを開始しますが、高いキャッシュヒットでは機能しない可能性があります。




おわりに



独自のページキャッシュを作成するのに難しいことはありません。 もちろん、これは典型的なサイトには意味がありませんが、モンスターをスポーンした場合、この資料は役に立つはずです。



All Articles