Upload
katanyan
View
990
Download
3
Embed Size (px)
Citation preview
• キャッシュの概要
• WordPressに備わっているキャッシュの仕組みの紹介
• WordPress Object Cache https://codex.wordpress.org/Class_Reference/WP_Object_Cache
• Transients API https://wpdocs.osdn.jp/Transients_API
• ※ WordPress コアのコードを例示している箇所はすべてバージョン 4.4.2 からの引用
• キャッシュ機構はデータを要求する側と応答する側の間に立ち、応答結果のコピーを保存
• 要求に応じて、該当するコピーがあればコピーを返す(キャッシュヒット)
• コピーが無ければ応答側にデータを要求してその応答結果を返す(キャッシュミス)
• 本来、キャッシュの存在は意識されないもの (キャッシュの有無にかかわらず、システムは同じように動作することが求められる。キャッシュの仕組みを使う側からはその存在は意識されないが、実はそこにあり、こっそりデータが保存されるイメージ。だから「隠し場所」)
HTTPリクエスト 解析
PHP MySQL PHPHTTPレスポンス
出力
キャッシュなし
※上記のイメージは、以下のページの「動的なサイトがリクエストを受け取って処理する仕組み」の画像の一部抜粋を元に作成 http://takahashifumiki.com/web/programing/2426/
HTTPリクエスト 解析
PHP MySQL PHPHTTPレスポンス
出力
キャッシュなし
HTTPリクエスト 解析
PHP MySQL PHPHTTPレスポンス
出力
出力キャッシュ (ページキャッシュ)
※上記のイメージは、以下のページの「動的なサイトがリクエストを受け取って処理する仕組み」の画像の一部抜粋を元に作成 http://takahashifumiki.com/web/programing/2426/
HTTPリクエスト 解析
PHP MySQL PHPHTTPレスポンス
出力
キャッシュなし
HTTPリクエスト 解析
PHP MySQL PHPHTTPレスポンス
出力
出力キャッシュ (ページキャッシュ)
キャッシュヒットすれば この部分の処理が省略される
※上記のイメージは、以下のページの「動的なサイトがリクエストを受け取って処理する仕組み」の画像の一部抜粋を元に作成 http://takahashifumiki.com/web/programing/2426/
HTTPリクエスト 解析
PHP MySQL PHPHTTPレスポンス
出力
キャッシュなし
HTTPリクエスト 解析
PHP MySQL PHPHTTPレスポンス
出力
出力キャッシュ (ページキャッシュ)
HTTPリクエスト 解析
PHP MySQL PHPHTTPレスポンス
出力
データキャッシュ (MySQLの応答結果をキャッシュするケース)
キャッシュヒットすれば この部分の処理が省略される
※上記のイメージは、以下のページの「動的なサイトがリクエストを受け取って処理する仕組み」の画像の一部抜粋を元に作成 http://takahashifumiki.com/web/programing/2426/
• クライアントサイド
• HTTPキャッシュ/プロキシキャッシュ
• サーバーサイド
• アプリケーション
• 出力キャッシュ/データキャッシュ
• ミドルウェア
• リバースプロキシキャッシュ/バイトコードキャッシュ/DBキャッシュ
• OS
• ディスクキャッシュ
画像出典:WordPressキャッシュ系プラグインの比較とサイトに適した選び方 http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/comparison-and-selection-of-wordpress-cache-plugin/
ほんとうは怖いWP Super Cacheの話 http://takahashifumiki.com/web/programing/2426/
※WP Super Cache がよくないということではありません
• クライアントサイド
• HTTPキャッシュ/プロキシキャッシュ
• サーバーサイド
• アプリケーション
• 出力キャッシュ/データキャッシュ
• ミドルウェア
• リバースプロキシキャッシュ/バイトコードキャッシュ/DBキャッシュ
• OS
• ディスクキャッシュ
PHP実行プロセス DB
プログラム
投稿データを要求
Object Cache
キャッシュデータ
PHP実行プロセス
プロセス終了により 無くなる
投稿データを要求キャッシュミス
DBからデータを取得
APCu などPHP実行プロセス DB
投稿データを要求
Object Cacheプログラム
PHP実行プロセス
投稿データを要求
キャッシュミスDBからデータを取得
投稿データを要求 キャッシュデータ
キャッシュデータ
• WP_Object_Cache クラスで実装
• インスタンス変数にデータを保持
• プログラムから使用するときは WP_Object_Cache に直接アクセスせず wp_cache_* 関数を使う
• 関数の一覧と基本的な使い方を Codex で確認してみましょう
get_post( 1 );
get_post( 1 );
get_post( 1 );
get_post( 1 );
get_post( 1 );
get_post( 1 );
get_post( 1 );
get_post( 1 );
get_post( 1 );
get_post( 1 );
get_post 関数より抜粋
function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) { if ( empty( $post ) && isset( $GLOBALS['post'] ) ) $post = $GLOBALS['post'];
if ( $post instanceof WP_Post ) { $_post = $post; } elseif ( is_object( $post ) ) { if ( empty( $post->filter ) ) { $_post = sanitize_post( $post, 'raw' );
$_post = new WP_Post( $_post ); } elseif ( 'raw' == $post->filter ) { $_post = new WP_Post( $post ); } else { $_post = WP_Post::get_instance( $post->ID );
} } else { $_post = WP_Post::get_instance( $post ); }
get_post 関数より抜粋
function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) { if ( empty( $post ) && isset( $GLOBALS['post'] ) ) $post = $GLOBALS['post'];
if ( $post instanceof WP_Post ) { $_post = $post; } elseif ( is_object( $post ) ) { if ( empty( $post->filter ) ) { $_post = sanitize_post( $post, 'raw' );
$_post = new WP_Post( $_post ); } elseif ( 'raw' == $post->filter ) { $_post = new WP_Post( $post ); } else { $_post = WP_Post::get_instance( $post->ID );
} } else { $_post = WP_Post::get_instance( $post ); }
public static function get_instance( $post_id ) { global $wpdb;
$post_id = (int) $post_id; if ( ! $post_id ) return false;
$_post = wp_cache_get( $post_id, 'posts' );
if ( ! $_post ) { $_post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d LIMIT 1", $post_id ) );
if ( ! $_post ) return false;
$_post = sanitize_post( $_post, 'raw' ); wp_cache_add( $_post->ID, $_post, 'posts' ); } elseif ( empty( $_post->filter ) ) { $_post = sanitize_post( $_post, 'raw' ); }
return new WP_Post( $_post ); }
WP_Post クラスより抜粋
public static function get_instance( $post_id ) { global $wpdb;
$post_id = (int) $post_id; if ( ! $post_id ) return false;
$_post = wp_cache_get( $post_id, 'posts' );
if ( ! $_post ) { $_post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d LIMIT 1", $post_id ) );
if ( ! $_post ) return false;
$_post = sanitize_post( $_post, 'raw' ); wp_cache_add( $_post->ID, $_post, 'posts' ); } elseif ( empty( $_post->filter ) ) { $_post = sanitize_post( $_post, 'raw' ); }
return new WP_Post( $_post ); }
WP_Post クラスより抜粋
wp_insert_post 関数より整形して抜粋
if ( empty( $data['post_name'] ) && !in_array( $data[‘post_status'], array( 'draft', 'pending', 'auto-draft' ) ) ) {
$data['post_name'] = wp_unique_post_slug(
sanitize_title( $data['post_title'], $post_ID ), $post_ID, $data[‘post_status'], $post_type, $post_parent
);
$wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ),
$where );
clean_post_cache( $post_ID ); }
if ( empty( $data['post_name'] ) && !in_array( $data[‘post_status'], array( 'draft', 'pending', 'auto-draft' ) ) ) {
$data['post_name'] = wp_unique_post_slug(
sanitize_title( $data['post_title'], $post_ID ), $post_ID, $data[‘post_status'], $post_type, $post_parent
);
$wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ),
$where );
clean_post_cache( $post_ID ); }
wp_insert_post 関数より整形して抜粋
wp_cache_delete( $post->ID, 'posts' );
wp_cache_delete( $post->ID, 'post_meta' );
clean_object_term_cache( $post->ID, $post->post_type );
wp_cache_delete( 'wp_get_archives', 'general' );
do_action( 'clean_post_cache', $post->ID, $post );
if ( 'page' == $post->post_type ) { wp_cache_delete( 'all_page_ids', 'posts' );
do_action( 'clean_page_cache', $post->ID ); }
wp_cache_set( 'last_changed', microtime(), 'posts' );
clean_post_cache 関数より抜粋
• ちなみに、get_posts / WP_Query は・・・
• 取得した投稿リストの各投稿オブジェクトがキャッシュされる
• cache_results パラメータで投稿オブジェクトをキャッシュするかどうかを指定可能
• 投稿リストそのものはキャッシュされない
function get_books( $args = array() ) { $defaults = array( 'post_type' => 'book' ); $args = wp_parse_args( $args, $defaults );
$cache_key = md5( 'books_' . serialize( $args ) );
$books = wp_cache_get( $cache_key, 'books' ); if ( $books === false ) { $books = get_posts( $args ); wp_cache_set( $cache_key, $books, 'books', 60 * MINUTE_IN_SECONDS ); }
return $books; }
カスタム投稿のリストをキャッシュするユーザー定義関数のサンプル
function get_books( $args = array() ) { $defaults = array( 'post_type' => 'book' ); $args = wp_parse_args( $args, $defaults );
$cache_key = md5( 'books_' . serialize( $args ) );
$books = wp_cache_get( $cache_key, 'books' ); if ( $books === false ) { $books = get_posts( $args ); wp_cache_set( $cache_key, $books, 'books', 60 * MINUTE_IN_SECONDS ); }
return $books; }
カスタム投稿のリストをキャッシュするユーザー定義関数のサンプル
get_option( 'hoge' );
get_option( 'hoge' );
get_option( 'hoge' );
get_option( 'hoge' );
get_option( 'hoge' );
get_option( 'hoge' );
get_option( 'hoge' );
get_option( 'hoge' );
get_option( 'hoge' );
get_option( 'hoge' );
• オートロード対象のオプションはコアの初期化処理で一括してロードされ、オブジェクトキャッシュに保存される
• wp-settings.php
• wp_not_installed
• is_blog_installed
• wp_load_alloptions
• オートロード対象ではないオプションも、一度�get_option で取得するとキャッシュされる
• オプション関係のキャッシュ ( [キャッシュグループ].[キャッシュID] )
• options.alloptions�… オートロードされたオプションのリスト
• options.notoptions�… 存在しないオプションのリスト
• options.[オプション名] �… オートロード対象外の個別のオプション
wp_start_object_cache 関数より抜粋 wp-settings.php でこの関数が呼ばれオブジェクトキャッシュが初期化される
$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' ); if ( function_exists( 'wp_cache_init' ) ) wp_using_ext_object_cache( true ); } $first_init = true;
} elseif ( ! wp_using_ext_object_cache() && file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) { wp_using_ext_object_cache( true ); }
if ( ! wp_using_ext_object_cache() ) require_once ( ABSPATH . WPINC . '/cache.php' );
wp_start_object_cache 関数より抜粋 wp-settings.php でこの関数が呼ばれオブジェクトキャッシュが初期化される
$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' ); if ( function_exists( 'wp_cache_init' ) ) wp_using_ext_object_cache( true ); } $first_init = true;
} elseif ( ! wp_using_ext_object_cache() && file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) { wp_using_ext_object_cache( true ); }
if ( ! wp_using_ext_object_cache() ) require_once ( ABSPATH . WPINC . '/cache.php' );
• wp-content の下に object-cache.php という名前でファイルを配置
• object-cache.php 内で wp_cache_* 関数を定義する
• wp_cache_* 関数の引数でキャッシュの有効期限を指定可能 ( 有効期限が使用されるかどうかはドロップインの実装による )
PHP実行プロセス DB
プログラム
外部サイトから データを取得
Transients API
有効期限
Options API
set_transient
データ
データを保存 add_option
PHP実行プロセス DB
プログラム
外部サイトから データを取得
Transients API
有効期限
Options API
set_transient
データ
データを保存 add_option
データを要求
データ
有効期限
PHP実行プロセス DB
プログラム
外部サイトから データを取得
Transients API
有効期限
Options API
set_transient
データ
データを保存 add_option
データを要求 get_transient
データ
有効期限
PHP実行プロセス DB
プログラム
外部サイトから データを取得
Transients API
有効期限
Options API
set_transient
データ
データを保存 add_option
データを要求 get_transient get_option
データ
有効期限
PHP実行プロセス DB
プログラム
外部サイトから データを取得
Transients API
有効期限
Options API
set_transient
データ
データを保存 add_option
データを要求 get_transient get_option
データ
有効期限
PHP実行プロセス DB
プログラム
外部サイトから データを取得
Transients API
有効期限
Options API
set_transient
データ
データを保存 add_option
データを要求 get_transient get_option
データ
有効期限
PHP実行プロセス DB
プログラム
外部サイトから データを取得
Transients API
有効期限
Options API
set_transient
データ
データを保存 add_option
データを要求 get_transient get_option
データ
有効期限
PHP実行プロセス DB
プログラム Transients API Options API
get_transient
データ
データを要求 get_option
delete_option 有効期限
有効期限 (期限切れ)
データ
• 「永続的かつ時限的なキャッシュ」 ( Codex より)
• リクエスト( ≒ PHP実行プロセス ) をまたいでデータの再利用が可能
• データに有効期限を設定可能
• データはデータベース ( wp_options テーブル ) に保存
• Codex を見てみましょう
• set_transient
• add_option でデータと有効期限を保存
• get_transient
• 有効期限が過ぎていたら delete_option でデータを削除
• 有効期限がまだ来ていなければ、get_option でデータを取得
• ※有効期限が過ぎていても、次の get_transient が呼ばれるまでデータは残り続けるということ
• フラグメントキャッシュ
• ページ断片の再利用。フッターやサイドバーの HTML をキャッシュして複数のリクエストに対して使い回す
• 重い処理、外部のWebサービス / サイトとの連携を伴う処理
• WordPress コア / プラグイン / テーマ の更新チェック
• SNS の API 利用制限を回避するなど
• フラッシュメッセージ
• 「設定を更新しました」など、1回限りのメッセージをリクエストをまたいで表示
$url = $http_url = 'http://api.wordpress.org/core/version-check/1.7/?' . http_build_query( $query, null, '&' );
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) $url = set_url_scheme( $url, 'https' );
(中略)
$response = wp_remote_post( $url, $options );
(中略)
$updates = new stdClass(); $updates->updates = $offers; $updates->last_checked = time(); $updates->version_checked = $wp_version;
if ( isset( $body['translations'] ) ) $updates->translations = $body['translations'];
set_site_transient( 'update_core', $updates );
wp_version_check 関数より抜粋
$url = $http_url = 'http://api.wordpress.org/core/version-check/1.7/?' . http_build_query( $query, null, '&' );
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) $url = set_url_scheme( $url, 'https' );
(中略)
$response = wp_remote_post( $url, $options );
(中略)
$updates = new stdClass(); $updates->updates = $offers; $updates->last_checked = time(); $updates->version_checked = $wp_version;
if ( isset( $body['translations'] ) ) $updates->translations = $body['translations'];
set_site_transient( 'update_core', $updates );
wp_version_check 関数より抜粋
$current = get_site_transient( 'update_core' );
(中略)
// Wait 60 seconds between multiple version check requests $timeout = 60; $time_not_changed =
isset( $current->last_checked ) && $timeout > ( time() - $current->last_checked );
if ( ! $force_check && $time_not_changed ) { return; }
wp_version_check 関数より抜粋
$current = get_site_transient( 'update_core' );
(中略)
// Wait 60 seconds between multiple version check requests $timeout = 60; $time_not_changed =
isset( $current->last_checked ) && $timeout > ( time() - $current->last_checked );
if ( ! $force_check && $time_not_changed ) { return; }
wp_version_check 関数より抜粋
• Object Cache がドロップインで拡張されている場合、トランジェントデータの保存先として Object Cache が使われる
• トランジェントデータの読み書きは wp_cache_* 関数に委譲
• プラグイン開発等で Transients API を使う際には、トランジェントデータがデータベース以外に保存されるケースも考慮しておく
• WordPress に備わっているキャッシュの仕組みとして Object Cache と Transients API がある
• Object Cache は単に PHP の変数でデータを管理。手軽で高速だが、リクエストをまたいでデータを再利用することはできない�( ドロップインで拡張すれば可能になる )
• Transients はサイトオプションの仕組みをうまく使うことで有効期限つきの永続キャッシュを実現。リクエストをまたいでデータを再利用できる
Special Thanks to• 高橋文樹.com
http://takahashifumiki.com
• ゆっくりと…http://tokkono.cute.coocan.jp