我应该使用Transient API来存储HTML字符串还是对象?


18

假设有一个插件可以显示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字符串,它将达到最大大小限制吗?保存之前,我应该gzip压缩吗?
  • 我应该在这里全部使用Transient API吗?

Answers:


18

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

没有。

在普通的WordPress安装中,瞬态存储在wp_options表中,并且仅在核心升级期间清除。假设您有50,000个帖子,那么选项表中还有50,000行。显然,它们已设置为autoload = no,因此不会消耗您的所有内存,但是还有另一个警告。

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

如果缓存的数据与帖子直接相关,则最好将其存储在帖子元中。每次需要显示缓存的内容时,这还将为您节省查询,因为(通常)在WP_Query的帖子检索期间准备发布元缓存。

元值的数据结构可能会有所不同,如果缓存的值已过时,则可以设置时间戳并执行昂贵的查询,就像瞬态行为一样。

需要牢记的另一重要思想是,在具有持久对象缓存的环境中,WordPress瞬态可能易变。这意味着,如果您将缓存的数据临时存储24小时,则绝对不能保证它会在23小时甚至12分钟甚至5分钟后可用。许多安装的对象缓存后端是内存中的键值存储(例如Redis或Memcached),如果分配的内存不足以容纳较新的对象,则将驱逐较旧的对象。对于元存储方法而言,这是一个巨大的胜利。

失效也可以变得更聪明,即为什么要在X小时内使相关的帖子缓存失效?是否因为某些内容已更改?新增了一个帖子?是否分配了新标签?根据您的“复杂而庞大的查询”,您可以选择仅在发生某些会改变查询结果的情况时才使它无效。

是否应该使用Transient API缓存$ related_posts数组或$ html_output字符串?如果我将缓存$ html_ouput字符串,它将达到最大大小限制吗?保存之前,我应该gzip压缩吗?

它很大程度上取决于字符串的大小,因为这是要在PHP,MySQL等之间流动的数据。您将需要非常努力地达到MySQL的极限,但是例如,Memcached默认的每个对象的极限是仅1 mb。

您的“复杂布局渲染逻辑”实际需要多长时间?通过探查器运行它以找出答案。很有可能,它永远不会成为瓶颈。

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

就是说,如果每个项目所需的数据非常简单,也许是标题,缩略图URL和永久链接,那么您只需存储这三个数据即可,而无需额外往返MySQL,也无需缓存超长HTML字符串。

哇,这句话很多,希望对您有所帮助。


12

并非所有WP代码都是公共代码

如果您要公开发布某些内容,那么科夫舍宁说的所有话都是完全正确的。

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

无论如何,外部对象缓存都是一个很大的好处

如果可以的话,强烈建议您设置外部持久对象缓存。

kovshenin的答案中关于瞬态和MySQL的所有内容都是非常正确的,考虑到WP本身和一堆插件都使用了对象缓存...那么您获得的性能提升,绝对值得(少量)设置像Redis或Memcached这样的现代缓存系统。

缓存的值可能不存在:很好

此外,是的,外部对象缓存可靠。您永远不应依赖瞬态存在的事实。您需要确保如果缓存不在应有的位置,则它可以正常工作。

缓存不是存储,缓存是缓存。

选择性使用缓存

请参阅以下示例:

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时,您不会使用任何瞬态。一个可能更简单的选择是使用wp_cache_*functions,因此,如果未设置外部缓存,则该缓存发生在内存中,并且永远不会涉及数据库。
  • 缓存的用法是可过滤的,以处理您可能遇到的一些极端情况

如果没有缓存则没有Webscale

您不应该尝试解决高速缓存的速度问题。如果遇到速度问题,则应重新考虑代码。

但是要以webscale扩展网站,非常需要缓存。

在很多时候(但并非总是)碎片化的情况下,上下文感知缓存比主动式全页缓存更具灵活性和适用性。

你的问题:

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

这要看情况

您的代码是否消耗大量资源?如果没有,也许不需要缓存。如前所述,不仅仅是速度问题。如果您的代码运行速度很快,但需要几个用户使用大量CPU和内存...当您有100个或1000个并发用户时会发生什么?

如果您意识到缓存将是一个好主意。

...是公共代码:可能不是。您可以考虑选择性地缓存,就像上面的示例中的公共代码一样,但是如果您将这样的决定留给实现者,通常会更好。

...是私人密码:很可能是。但是即使对于私有代码,选择性地缓存仍然是一件好事,例如用于调试。

记住,无论如何,这些wp_cache_*函数可以使您访问缓存,而不会污染数据库。

是否应该使用Transient API缓存$ related_posts数组或$ html_output字符串?

这取决于很多事情。弦多大?您正在使用哪个外部缓存?如果您要缓存帖子,将ID存储为数组可能是个好主意,通过它们的ID查询相当数量的帖子非常快。

最后说明

瞬态API可能是WordPress最好的东西之一。多亏了可以在任何类型的缓存系统中找到的插件,它成为许多可以在后台运行的软件的愚蠢的简单API。

在WordPress之外,很难找到这样的抽象,它可以与一堆不同的缓存系统一起使用,并且可以毫不费力地从一个系统切换到另一个系统。

您很少听到我说WordPress比其他现代功能要好,但是当我不使用WordPress时,瞬态API就是我错过的少数几个功能之一。

当然,缓存很困难,不能解决代码问题,不是灵丹妙药,但是您需要构建一个高流量站点才能正常工作。

WordPress的想法是使用未充分优化的MySQL表进行缓存,这是非常疯狂的,但是最好不要因为WordPress默认情况下这样做而使自己远离缓存。

您只需要了解事物的工作原理,然后做出选择即可。


2

前面的答案已经强调了强制性的“ 它取决于 ”,我完全同意。

但是,我根据我“如何”添加一个建议,这将在您上面描述的场景中最好地完成。

在那种情况下,我不会使用Transients,而应该使用Post Meta,因为后者具有一个优点:Control

由于需要按每个帖子缓存数据,因此要缓存的数据量取决于发布的数量,并且会随着时间的推移而增长。一旦超过一定数量的帖子,您可能会达到对象缓存允许使用的内存限制,并且它将在过期之前开始从内存中擦除先前缓存的数据。这可能会导致一种情况,您有大量的访问者涌入,每个访问者将在每个页面请求后触发“过于复杂的SQL”,并且您的站点将陷入瘫痪。

如果将数据缓存在Post Meta中,则不仅可以控制其存储和检索方式,还可以精确地控制其更新方式。您将为此添加一个cron作业,该作业仅在很少或没有流量访问站点的时间段运行。因此,网站的真正用户永远不会遇到“慢查询”,您甚至可以预先加载它,以便在第一个访问者访问时就已经完成了工作。

请记住,所有缓存都是一个折衷方案!这就是为什么通常的答案是“取决于情况”的原因。以及为什么没有“圣杯”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.