问题描述

我们假设有一个插件,显示 20 个相关的帖子 (每个帖子) 与一个非常复杂的查询。然后使用此查询中的数据,它构建复杂的 HTML 布局。另外,应该注意的是,该插件是公共的,可以安装在任何配置的任何服务器上。

就像是:

/* complex and large query */
$related_posts = get_posts( ... );

$html_output = '';
foreach($related_posts as $key => $item) {
     /* complex layout rendering logic (but not as slow as the previous query) */
     $html_output .= ...;
}

所以我的问题是:

  • 缓存这些数据最安全和最正确的方法是什么?

  • 应该使用 Transient API 缓存 $related_posts 数组,还是 $html_output 字符串?如果我会缓存 $html_ouput 字符串,它会达到一些 max-size 限制吗?我应该可以 gzip 它,然后保存?

  • 我应该在这里使用 Transient API 吗?

最佳解决方案

Should I use Transient API at all here?

没有。

在一个库存 WordPress 安装瞬态存储在 wp_options 表中,只有在核心升级期间才被清理。假设你有 50,000 个帖子,在选项表中有 5 万个附加行。显然,它们设置为 autoload = no,所以它不会消​​耗你所有的 memory ,但还有一个警告。

选项表中的自动加载字段没有索引,这意味着对 wp_load_alloptions()的调用将执行全表扫描。你拥有的行越多,需要的时间越长。写入选项表的次数越多,MySQL 内部缓存效率越低。

如果缓存的数据与帖子直接相关,那么最好将其存储在后期元数据中。这也将在您每次显示缓存的内容时保存一个查询,因为在 WP_Query 中的后检索期间,通常会发送缓存 (通常) 。

您的数据结构的元值可能会有所不同,如果缓存的值过时,那么您可以拥有时间戳并执行昂贵的查询,就像一个暂时的行为一样。

另一个重要的想法是记住,WordPress 瞬态可以在具有持久性对象缓存的环境中变化。这意味着如果您将缓存的数据存储在短暂的 24 小时内,绝对不保证它将在 23 小时或 12 个甚至 5 分钟内可用。许多安装的对象缓存后端是 in-memory key-value 存储,如 Redis 或 Memcached,如果没有足够的分配内存来适应较新的对象,较旧的项目将被逐出。这是元存储方法的巨大胜利。

无效也可以更聪明,即为什么在 X 小时内无效相关的帖子缓存?是因为有些内容有所改变吗?添加了一个新帖子?已分配一个新标签?根据您的 「复杂和大查询」,您可以选择仅在发生改变查询结果的事情时才使其无效。

Should I use Transient API to cache $related_posts array, or $html_output string? If I’ll cache $html_ouput string, will it reach some max-size limit? Should I maybe gzip it, before saving?

这取决于您的字符串的大小,因为这将是 PHP,MySQL 等之间的数据。您需要努力达到 MySQL 的限制,但例如 Memcached 默认的 per-object 限制只有 1 MB 。

您的 「复杂布局渲染逻辑」 实际需要多长时间?通过分析器运行它来查找。有可能是非常快速的将永远不会成为瓶颈。

如果是这样,我建议缓存帖子 ID 。不是 WP_Post 对象,因为那些将包含完整的帖子内容,而只是一个数组的帖子 ID 。然后只需使用 WP_Querypost__in,这将导致通过主键快速的 MySQL 查询。

也就是说,如果每个项目所需的数据相当简单,那么您可以只存储这三个数据,而不需要额外的 round-trip 到 MySQL 的开销,并且没有缓存非常长的 HTML 字符串的开销。

哇这是很多话,希望有所帮助。

次佳解决方案

不是所有的 WP 代码都是公共代码

如果你要发布公开的东西,那么 kovshenin 所说的一切都是完全有效的。

如果您要为自己或您的公司编写私人密码,情况会有所不同。

外部对象缓存是一个很大的好处,在任何情况下

设置外部持久对象缓存是非常推荐的,可以的时候。

所有关于 kovshenin 关于瞬态和 MySQL 的答案都是非常真实的,考虑到 WP 本身和一堆插件使用对象缓存… 然后性能提升,绝对值得 (小) 努力设置像 Redis 或 Memcached 这样的现代缓存系统。

缓存值可能不在那里:没关系

而且,是的,外部对象缓存是不可靠的。你不应该依赖于一个瞬间的事实。如果缓存不在其中,则需要确保它有效。

缓存是 notstorage,缓存是缓存。

选择使用缓存

看这个例子:

function my_get_some_value($key) {
   // by default no cache when debug and if no external object_cache
   $defUse = ! (defined('WP_DEBUG') && WP_DEBUG) && wp_using_ext_object_cache();
   // make the usage of cache filterable
   $useCache = apply_filters('my_use_cache', $defUse);
   // return cached value if any
   if ($useCache && ($cached = get_transient($key))) {
     return $cached;
   }
   // no cached value, make sure your code works with no cache
   $value = my_get_some_value_in_some_expensive_way();
   // set cache, if allowed
   $useCache and set_transient($key, $value, HOUR_IN_SECONDS);

   return $value;
}

使用这样的代码,在您的私人网站中,网站性能可以提高很多,特别是如果您有很多用户。

注意:

  • 默认情况下,调试开启时不使用缓存,因此希望在您的开发环境中。相信我,缓存可以让调试成为一个地狱

  • 默认情况下,当 WP 未设置为使用外部对象缓存时,缓存也不会被使用。这意味着与 MySQL 连接的所有问题都不存在,因为当 MySQL 使用 MySQL 时,不会出现任何瞬态问题。使用 wp_cache_*功能可能更容易一些,所以如果没有设置外部缓存,那么缓存就会在内存中发生,数据库永远都不会涉及。

  • 缓存的使用是可过滤的,可以处理您可能遇到的一些边情况

没有 Webscale 如果没有缓存

您不应该尝试解决缓存的速度问题。如果你有速度问题,那么你应该 re-think 你的代码。

但是,要在 webscale 上扩展一个网站,缓存是非常需要的。

而且很多次 (但不总是) 片段,context-aware 缓存比攻击性全页缓存更灵活和合适。

你的问题:

Should I use Transient API at all here?

这取决于。

您的代码是否耗用大量资源?如果没有,也可能不需要缓存。如上所述,不仅仅是速度的问题。如果你的代码运行速度很快,但是对于几个用户来说,它需要一堆 CPU 和内存?当你有 100 或 1000 个并发用户时会发生什么?

如果你认识缓存会是个好主意..

… 是公共代码:大概没有。您可以考虑缓存缓存,就像上面在公共代码中的示例一样,但是如果您对实现者做出这样的决定,通常会更好。

… 是私人密码:很可能是的。但即使是私人代码,选择性缓存仍然是一件好事,例如调试。

记住,无论如何,wp_cache_*功能可以让您访问缓存,而不会有数据库污染的风险。

Should I use Transient API to cache $related_posts array, or $html_output string?

这取决于很多事情。字符串有多大?你使用哪个外部缓存?如果要缓存帖子,将 ID 存储为数组可能是一个好主意,通过其 ID 来查询适当数量的帖子是相当快的。

最终注解

瞬态 API 可能是 WordPress 最好的之一。感谢您可以为任何类型的缓存系统找到的插件,它将成为可以在引擎盖下工作的大量软件的一个愚蠢的简单 API 。

在 WordPress 外部,这种使用一堆不同的缓存系统开箱即用的抽象,并且允许您从一个系统切换到另一个系统,而不用努力就很难找到。

你很少听到我说 WordPress 比其他现代的东西更好,但是当我不使用 WordPress 时,瞬态 API 是我想念的几件事之一。

当然缓存很难,不解决代码问题,而不是一个银弹,但是你需要构建一个可以工作的 high-traffic 站点。

使用 under-optimized MySQL 表进行缓存的 WordPress 想法是非常疯狂的,但是不要因为 WordPress 默认情况下使其远离高速缓存。

你只需要了解事情的运作方式,然后做出选择。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。