我在这里寻找一个明确的答案。启用对象缓存后,选项和瞬态在哪里结束?

默认情况下,两者都存储在数据库中。但是我听说一些参考资料称Memcache会将它们存储在其他位置,而APC将完全做其他事情。两种情况下,这些数据究竟将保留在什么地方?

评论

@toscho提到的文章现在可以在archive.org上找到:探索WordPress Cache API

#1 楼

WordPress默认情况下会执行“对象缓存”的形式,但其生存期仅为一次页面加载。

选项实际上是一个很好的例子。查看此答案以获取更多信息。摘要:


页面开始
所有选项均加载有简单的SELECT option_name, option_value from $wpdb->options语句
随后对这些选项的请求(例如,对get_option的调用从未命中数据库因为它们是用WP缓存API存储的。选项始终在数据库中“活动”并始终存在于数据库中-这就是它们的“规范”源。也就是说,选项已加载到对象缓存中因此,当您请求一个选项时,请求有99%的可能性将永远不会到达数据库。

瞬态有些不同。插件-直接放置在您的wp-content文件夹中的文件。如果您创建自己的缓存插件或使用现有插件,则可以使对象缓存的保存时间长于单个页面加载的时间。

让我们看一下set_transient中的wp-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.phpwp-settings.php,这两者都是WordPress引导过程的关键。在我们的缓存中,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_cache中的wp-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收集垃圾。

其他一些担忧/问题:



可以无数次拨打get_option吗?大概。他们招致了函数开销的调用,但是它可能不会访问数据库。与您选择的语言生成页面所做的工作相比,数据库负载通常是Web应用程序可伸缩性中更大的问题。

我如何知道使用瞬态与Cache API?如果您希望数据在设定的时间内持续存在,请使用瞬时API。如果数据是否持久无关紧要(例如,计算/获取数据不会花费很长时间,但是每次页面加载它都不会发生多次),请使用缓存API。

所有选项真的都缓存在每个页面加载上吗?不必要。如果使用最后一个可选参数add_option调用no,则不会自动加载它们。也就是说,一旦提取它们一次,它们就会进入缓存,后续调用将不会到达数据库。


评论


nitpick 1:并非所有选项都在页面开始时加载,只有那些在创建时标记为“ autoload = yes”的选项。 add_option中该参数的默认值为“是”,并且大多数插件编写者都不会理会使用“否”的区别,在那里您的陈述实际上是正确的。

–马克·卡普伦
2012年12月3日,下午5:32

即使非自动加载的选项在被提取一次之后也会被缓存。它们可能最初并未加载,但之后确实会进入对象缓存。甚至不存在的选项也会被缓存! github.com/WordPress/WordPress/blob/master/wp-includes/…但是,我添加了有关自动加载选项的注释。

–chrisguitarguy
2012年12月3日5:37



那是nitpick 2;)

–马克·卡普伦
2012年12月3日,下午5:42

感谢您的精彩文章,以及所有这些内容的总结。

–prosti
16 Dec 15'在13:54

多棒的有用答案,谢谢!

–最后
20年6月11日在8:42

#2 楼

我知道有4种缓存类型



Trivial-它始终启用并在其他任何缓存开始起作用之前起作用。它将缓存的项目存储在php数组中,这意味着它从php执行会话中消耗了内存,并且在php执行结束后清空了缓存。即,即使不使用任何其他缓存,如果连续两次调用get_option('opt'),则将仅在第一次和第二次从内存中返回该值时才进行数据库查询。
文件-缓存的值存储在根目录下某处的文件中。我认为,除非您拥有非常快速的磁盘或内存映射文件存储,否则它在性能方面是无效的。
APC(或其他基于PHP加速器的缓存)-缓存的值存储在主机的内存中和您的PHP内存分配之外。最大的潜在陷阱是没有数据作用域,如果您运行两个站点,则每个站点都可能可以访问另一个站点的缓存数据或将其覆盖。
Memcache-它是基于网络的缓存。您可以在网络上的任何地方运行缓存服务,它可能会将值存储在其主机内存中。除非您进行负载平衡,否则您可能不需要内存缓存。

BTW,对象缓存比选项缓存要多得多,它几乎可以存储使用高级WP从数据库检索到的所有内容。 API。

评论


我知道答案是相当古老的,但我还要添加出色的Redis。

–Cranio
16年4月12日在10:32

@Cranio,您是对的,但是... redis本质上是带有存储的内存缓存的变体,因此它是(NoSQL)DB。这个IMHO实际上很糟糕,好像该节点发生故障或无法更新一样,您可能会从中获取陈旧的信息。它有一个选项可以关闭类似DB的行为,但是我不确定默认情况下它是打开还是关闭。

–马克·卡普伦
16年4月12日在10:42

它是Memcached(甚至更好)的完美替代品,您还需要什么?到目前为止,我所见过的最普通的用法就是将其作为RAM键值存储(是的,除此之外,可以使数据持久化,集群正在运行并且具有队列管理功能,但是每个人都认为Redis是出色的WP的缓存选项)

–Cranio
16年4月12日在12:45

每个人都可以跳桥;),但是完全不需要增加缓存的复杂性

–马克·卡普伦
16年4月12日在13:04

那是完全没有意义的。您要RAM缓存,Redis进行RAM缓存,周期;它做的很棒。如果您不想这样做,绝对不会增加任何复杂性。所以,先生,我真的不明白你的意思。

–Cranio
16年4月13日在10:41

#3 楼

选项始终存储在数据库中,而瞬变仅在安装了APC和在WP中实现APC缓存的插件时才可能存储在共享内存中。 Memcache也会使用内存。

选项也存储在内存中,并在可能的情况下从那里加载(如果没有,则执行db查询)。

#4 楼

很好的问题。

我认为仍然缺少WordPress如何使用WP_Object_Cache类的部分,因此我将其添加。

来自文档:


DEF:WordPress对象缓存用于保存对数据库的旅行。对象缓存将所有缓存数据存储到内存中,并通过使用密钥来使缓存内容可用,该密钥用于命名和稍后检索缓存内容。这是WP_Object_Cache结构。




注意+是公共的,-私有的,#受保护的。显示有关全局缓存对象及其中内容的常规统计信息的方法。输出为:

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 )


这是我在模板stats()之类的开头就得到的内容。

请注意变量我们感兴趣的是:
single.php

私有成员global $wp_object_cache保存实际的缓存数据。


在编程中,缓存结构无处不在。以简单的形式,它们可以被识别为键值对。值区,NoDB结构,数据库索引。 WordPress对象缓存的最终目标不是拥有尽可能简单的结构,而是仍然可以识别键值对。

由于打印缓存时我在$cache中,所以我

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
        )


对象将是值,而缓存键将是be

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075


在这里,您可以检查single.php的结构:

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:   }