web-dev-qa-db-ja.com

オブジェクトキャッシュはどのように機能しますか?

私はここで決定的な答えを探しています。オブジェクトキャッシングが有効になっているとき、オプションとトランジェントはどこで生計を立てますか?

デフォルトでは、両方ともデータベースに格納されています。しかし、私は、memcacheがそれらを他の場所に格納し、APCが他のことを完全に行うといういくつかの参照を聞いたことがあります。 正確に どちらの場合でも、このデータはどこに保持されますか。

21
EAMann

WordPressは、デフォルトで「オブジェクトキャッシュ」の形式を実行しますが、その有効期間は1ページのロードのみです。

オプションは実際にこれの実に良い例です。詳細については this answer をご覧ください。サマリー:

  1. ページが始まります
  2. すべてのオプションは、単純なSELECT option_name, option_value from $wpdb->optionsステートメントでロードされます
  3. これらのオプションに対する後続のリクエスト(たとえば、get_optionへの呼び出しは、WPキャッシュAPIで保存されるため、データベースにヒットしません。

オプションは常にデータベースに「ライブ」され、常にそこに永続化されます。それが「標準的な」ソースです。ただし、オプションはオブジェクトキャッシュに読み込まれるため、オプションを要求すると、99%の確率でその要求がデータベースにヒットしない可能性があります。

トランジェントは少し異なります。

WordPressでは、キャッシュAPIをdrop-inで置き換えることができます。これは、wp-contentフォルダーに直接配置されるファイルです。独自のキャッシュドロップを作成するか、 existingplugin を使用すると、1ページのロードよりも長くオブジェクトキャッシュを保持できます。それを行うと、トランジェントが少し変わります。

set_transientwp-includes/option.php 関数を見てみましょう。

<?php
/**
 * Set/update the value of a transient.
 *
 * You do not need to serialize values. If the value needs to be serialized, then
 * it will be serialized before it is set.
 *
 * @since 2.8.0
 * @package WordPress
 * @subpackage Transient
 *
 * @uses apply_filters() Calls 'pre_set_transient_$transient' hook to allow overwriting the
 *  transient value to be stored.
 * @uses do_action() Calls 'set_transient_$transient' and 'setted_transient' hooks on success.
 *
 * @param string $transient Transient name. Expected to not be SQL-escaped.
 * @param mixed $value Transient value. Expected to not be SQL-escaped.
 * @param int $expiration Time until expiration in seconds, default 0
 * @return bool False if value was not set and true if value was set.
 */
function set_transient( $transient, $value, $expiration = 0 ) {
    global $_wp_using_ext_object_cache;

    $value = apply_filters( 'pre_set_transient_' . $transient, $value );

    if ( $_wp_using_ext_object_cache ) {
        $result = wp_cache_set( $transient, $value, 'transient', $expiration );
    } else {
        $transient_timeout = '_transient_timeout_' . $transient;
        $transient = '_transient_' . $transient;
        if ( false === get_option( $transient ) ) {
            $autoload = 'yes';
            if ( $expiration ) {
                $autoload = 'no';
                add_option( $transient_timeout, time() + $expiration, '', 'no' );
            }
            $result = add_option( $transient, $value, '', $autoload );
        } else {
            if ( $expiration )
                update_option( $transient_timeout, time() + $expiration );
            $result = update_option( $transient, $value );
        }
    }
    if ( $result ) {
        do_action( 'set_transient_' . $transient );
        do_action( 'setted_transient', $transient );
    }
    return $result;
}

うーん$_wp_using_ext_object_cache?真の場合、WordPressは、データベースの代わりにオブジェクトキャッシュを使用してトランジェントを格納します。では、どのようにしてそれをtrueに設定しますか? WPが独自のキャッシュAPIを設定する方法を探る時間です。

ほとんどすべてをwp-load.phpまたはwp-settings.phpにトレースできます。どちらもWordPressのbootstrapプロセスに不可欠です。キャッシュでは、wp-settings.phpに関連する行がいくつかあります。

// Start the WordPress object cache, or an external object cache if the drop-in is present.
wp_start_object_cache();

上から物を落としたことを覚えていますか? wp_start_object_cachewp-includes/load.phpを見てみましょう。

<?php
/**
 * Starts the WordPress object cache.
 *
 * If an object-cache.php file exists in the wp-content directory,
 * it uses that drop-in as an external object cache.
 *
 * @access private
 * @since 3.0.0
 */
function wp_start_object_cache() {
    global $_wp_using_ext_object_cache, $blog_id;

    $first_init = false;
    if ( ! function_exists( 'wp_cache_init' ) ) {
        if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
            require_once ( WP_CONTENT_DIR . '/object-cache.php' );
            $_wp_using_ext_object_cache = true;
        } else {
            require_once ( ABSPATH . WPINC . '/cache.php' );
            $_wp_using_ext_object_cache = false;
        }
        $first_init = true;
    } else if ( !$_wp_using_ext_object_cache && file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
        // Sometimes advanced-cache.php can load object-cache.php before it is loaded here.
        // This breaks the function_exists check above and can result in $_wp_using_ext_object_cache
        // being set incorrectly. Double check if an external cache exists.
        $_wp_using_ext_object_cache = true;
    }

    // If cache supports reset, reset instead of init if already initialized.
    // Reset signals to the cache that global IDs have changed and it may need to update keys
    // and cleanup caches.
    if ( ! $first_init && function_exists( 'wp_cache_switch_to_blog' ) )
        wp_cache_switch_to_blog( $blog_id );
    else
        wp_cache_init();

    if ( function_exists( 'wp_cache_add_global_groups' ) ) {
        wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache' ) );
        wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
    }
}

関数の関連行(トランジェントの格納方法を変更する$_wp_using_ext_object_cacheに関連する行)。

if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
    require_once ( WP_CONTENT_DIR . '/object-cache.php' );
    $_wp_using_ext_object_cache = true;
} else {
    require_once ( ABSPATH . WPINC . '/cache.php' );
    $_wp_using_ext_object_cache = false;
}

object-cache.phpがコンテンツディレクトリに存在する場合は含まれます。WPは、外部の永続キャッシュを使用していると想定します-$_wp_using_ext_object_cacheをtrueに設定します。

外部オブジェクトキャッシュを使用している場合、トランジェントはそれを使用します。これは、オプションとトランジェントをいつ使用するかという問題を提起します。

シンプル。データを無期限に永続化する必要がある場合は、オプションを使用します。それらは「キャッシュ」されますが、それらの正規のソースはデータベースであり、ユーザーが明示的に要求しない限り、決して消えません。

設定された期間保存する必要があるが、指定されたライフタイムを超えて持続する必要のないデータの場合は、トランジェントを使用します。内部的に、WPは外部の永続オブジェクトキャッシュを使用しようとします。そうしないと、データがオプションテーブルに移動し、有効期限が切れたときに WordPress 'psuedo-cron でガベージコレクションを取得します。

その他の懸念事項/質問:

  1. get_option?を大量に呼び出しても大丈夫ですか?関数のオーバーヘッドが発生しますが、データベースにはヒットしません。多くの場合、データベースの負荷は、選択した言語がページを生成する作業よりも、Webアプリケーションのスケーラビリティにおいて大きな懸念事項です。
  2. どのようにトランジェントとキャッシュAPIを使用することを知るのですか?データが一定期間持続すると予想される場合、トランジェントAPIを使用しますデータが持続するかどうかが重要でない場合(たとえば、データの計算/フェッチに時間がかからないが、ページの読み込みごとに複数回発生するべきではない)キャッシュAPIを使用します。
  3. すべてのオプションはページロードごとに実際にキャッシュされますか?必ずしもそうではありません。最後のオプション引数noadd_optionを呼び出すと、それらは自動ロードされません。ただし、一度フェッチすると、キャッシュに入れられ、以降の呼び出しはデータベースにヒットしません。
34
chrisguitarguy

私が知っている4種類のキャッシュがあります

  1. 些細なこと - 他のキャッシュが有効になる前に常に有効であり、効果があります。それはあなたのphp実行セッションからメモリを消費し、そしてキャッシュはphp実行が終了した後に空にされることを意味します。つまり、get_option( 'opt')を2回続けて呼び出した場合、他のキャッシュを使用しなくても、1回目と2回目にのみメモリから値が返されます。

  2. ファイル - キャッシュされた値はあなたのルートディレクトリの下のどこかのファイルに保存されます。非常に高速なディスクまたはメモリマップファイルストレージを使用しない限り、パフォーマンスの面では効果的ではないことが証明されたと思います。

  3. APC(または他のphpアクセラレータベースのキャッシュ) - キャッシュされた値はあなたのホストマシンのメモリとあなたのphpメモリ割り当ての外側に保存されます。最大の潜在的な落とし穴は、データのスコープがないことです。2つのサイトを運営している場合、それぞれがキャッシュされたもう一方のデータにアクセスしたり上書きしたりする可能性があります。

  4. Memcache - これはネットワークベースのキャッシュです。あなたはネットワーク上のどこでもキャッシングサービスを実行することができ、それはおそらくそのホストメモリに値を格納します。ロードバランシングを実行していない限り、おそらくmemcacheは必要ありません。

ところで、オブジェクトキャッシングはオプションよりはるかに多くのものをキャッシングしています、それは高レベルWP AP​​Iを使用してDBから検索されたほとんどすべてを格納します。

5
Mark Kaplun

素晴らしい質問です。

WordPressがWP_Object_Cacheクラスをどのように使用しているかという部分はまだ不足していると思うので、それを追加します。

ドキュメントから:

DEF:WordPressオブジェクトキャッシュはデータベースへの旅行を節約するために使われます。オブジェクトキャッシュは、すべてのキャッシュデータをメモリに格納し、キャッシュの内容に名前を付けて後で取得するために使用されるキーを使用して、キャッシュの内容を利用できるようにします。

これがWP_Object_Cache構造体です。

enter image description here 

注+はパブリック、 - プライベート、#保護されています。

グローバルキャッシュオブジェクトに関する一般的な統計とそこにあるものを表示するには、stats()メソッドを使用します。これが出力です。

Cache Hits: 110
Cache Misses: 98

Group: options - ( 81.03k )
Group: default - ( 0.03k )
Group: users - ( 0.41k )
Group: userlogins - ( 0.03k )
Group: useremail - ( 0.04k )
Group: userslugs - ( 0.03k )
Group: user_meta - ( 3.92k )
Group: posts - ( 1.99k )
Group: terms - ( 1.76k )
Group: post_tag_relationships - ( 0.04k )
Group: category_relationships - ( 0.03k )
Group: post_format_relationships - ( 0.02k )
Group: post_meta - ( 0.36k )

これはsingle.phpのようなテンプレートの冒頭で私が以前に得たものです。

関心のある変数はglobal $wp_object_cacheです。

プライベートのメンバ$cacheは実際のキャッシュデータを保持します。

プログラミングでは、キャッシュ構造はいたるところにあります。単純な形では、それらはキーと値のペアとして認識できます。バケット、NoDB構造体、データベースインデックス。 WordPress Object Cacheの最終目標は、可能な限り単純な構造を持つことではありませんでしたが、それでもキーと値のペアは認識できます。

キャッシュを印刷したときはsingle.phpにいたので:

print_r($wp_object_cache->cache['posts']);

単一の投稿がキャッシュされます。

    [last_changed] => 0.34169600 1481802075
    [get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075] => 0
    [2831] => WP_Post Object
        (
            [ID] => 2831
            [post_author] => 1 
            ... the cached post object goes here
        )

オブジェクトは値になり、 キャッシングキー は次のようになります。

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075

ここでは$cache_key構造体をチェックすることができます:

File: /wp-includes/post.php
4210: /**
4211:  * Retrieves a page given its path.
4212:  *
4213:  * @since 2.1.0
4214:  *
4215:  * @global wpdb $wpdb WordPress database abstraction object.
4216:  *
4217:  * @param string       $page_path Page path.
4218:  * @param string       $output    Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
4219:  *                                a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
4220:  * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
4221:  * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
4222:  */
4223: function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
4224:   global $wpdb;
4225: 
4226:   $last_changed = wp_cache_get_last_changed( 'posts' );
4227: 
4228:   $hash = md5( $page_path . serialize( $post_type ) );
4229:   $cache_key = "get_page_by_path:$hash:$last_changed";
4230:   $cached = wp_cache_get( $cache_key, 'posts' );
4231:   if ( false !== $cached ) {
4232:       // Special case: '0' is a bad `$page_path`.
4233:       if ( '0' === $cached || 0 === $cached ) {
4234:           return;
4235:       } else {
4236:           return get_post( $cached, $output );
4237:       }
4238:   }
0
prosti

APCとWPにAPCキャッシングを実装するプラグインがインストールされている場合、オプションは常にデータベースに保存されますが、トランジェントは共有メモリにのみ保存されます。 Memcacheはメモリも使用します。

オプションもメモリに格納され、可能であればそこからロードされます(そうでない場合はdbクエリが実行されます)。

0
onetrickpony