Drupal 8 的动态页面缓存
Drupal 8 现在有了动态页面缓存。Page Cache 模块只对匿名用户生效,而 Dynamic Page Cache 模块则更进一步的为所有用户提供服务。
4 月 8 日起,Drupal 8 缺省开启了页面缓存。刚好五个月以后也就是 9 月 8 日,Dynamic Page Cache 模块也加入了 Drupal 8,同样的也是缺省开启。
动态页面缓存是什么?
Page Cache 模块缓存的是完全渲染之后的 HTML 响应内容
他假设每个响应只有一种,这个假设只对匿名用户有效。相对于 Drupal 7,8 的创新是加入了 Cache Tags(缓存标记),这就使得在使用页面缓存的时候,依然能够及时更新页面,不再呈现过期内容。
Dynamic Page Cache 模块缓存大部分渲染之后的 HTML 相应内容
现在不再认为只有一种响应了:这里要感谢 cache contexts,他能够获取到页面各个部分的变体。在渲染过程中,自动占位会识别页面中的一部分不可缓存的内容,替换为占位符。这些占位符只在最后一刻进行渲染。动态页面缓存模块会在这些占位符被替换之前进行缓存。
所以,概念上来说:Page Cache –> Dynamic Page Cache
Key | Value | |
---|---|---|
Page Cache | URL |
最终响应 缓存标记 |
Dynamic Page Cache | URL cache contexts |
部分响应 占位符 缓存标记 |
上表对比展示了二者的优劣:Page Cache 包含了最终响应,所以相对较快;而 Dynamic Page Cache 只包含了部分响应,但是因为这部分内容是没有经过个性化的,所以适用于各种用户。
换句话说,动态页面缓存做的事情比较多,但是适用于更多场景。
Benchmark
在开启页面缓存之后,Drupal 8 对匿名用户能够在常数时间内返回响应。
有了动态页面缓存之后,Drupal 8 的响应时间就是在之前的时间上再加上渲染占位符的时间。这意味着,页面的绝大部分能够在固定时间里完成(跟内容多少无关)。最后的占位符渲染环节是最需要进行优化的,当然,最好没有这部分(可以延伸阅读一下 BigPipe 相关内容)。
在我的机器上(ab -c1 -n 1000
, PHP 5.5.11,Intel Core i7 2.8 GHz 笔记本电脑,15 个带有一条留言的 Node,其中 10 个列在首页上):
- 没有动态页面缓存
- 首页:61.3 毫秒/请求(每秒 16 个请求)
- node/1:92.3 毫秒/请求(每秒 10.8 个请求)
- 动态缓存开启
- 首页:38.3 毫秒/请求(每秒 26 个请求)
- node/1:73.8 毫秒/请求(每秒 13.5 个请求)
分析
首页只有一个占位符(message),这使得首页是一个最低相应时间的指标:我的机器上大概 38 毫秒。
- 大约 38 毫秒用于 bootstrap,路由,路由权限检查,从动态页面缓存中获取缓存内容。
- 跟 node/1 比较:渲染占位符用掉了超过 35.5 毫秒的时间。这说明此处的渲染成本非常高——留言 Form。
可以看到,动态页面缓存在开发期间也很有用,他暴露了无法缓存或者难于渲染的页面部分。
在实际服务器上,十倍不止
上面的测试只是一个并发,还可以参考Rasmus Lerdorf 的相关测试
多赢
各种规模的站点都会受益:
- 企业级站点得到了更高的可塑性,以及针对认证用户的反向代理/CDN方面能力的提升。
- 小站点能够为认证用户提供更多更快的并发访问能力。
所以我的工作由 Acquia 赞助,但是大家都能从中获益。
有人发表疑问, Drupal 8 会不会太复杂了,是不是已经不在意站点搭建者,而只考虑企业应用了之类的、我认为这就是个很好的反例 —— 缺省激活的页面缓存优于大多数的 Drupal 7 站点。
我们的确在缓存标记上增加了复杂性,不过这只对开发者产生了影响,而且提供了完善的文档。最重要的是,站点建设者不需要关心这些了,Drupal 8 开始不再需要手工清除缓存了!
Drupal 很像乐高积木。直到 Drupal 8,如果你试用了太多的模块,站点会变慢,缓存的设置复杂到令人望而却步。现在这些组成部分必须自己声明缓存的元数据,这样 Drupal 就可以把大部分“加速”工作自动完成了。
小站点(包括共享主机)
小站点能够处理更多的认证用户产生的并发访问,更快的生成页面。
无需任何配置。
无需任何搜索。
企业站点(以及企业级托管)
企业站点有了更多调节的能力:如果倾向于利用足够的存储空间,而不是渲染占位符的话(空间换时间),那么只要覆盖缺省的自动占位符条件即可。
这也是第一次我们有机会利用CDN为认证用户提供响应内容。
开发者
在缓存元数据(缓存标记,上下文和最大周期)之外,可以针对主机环境,性能和缓存方面做深入细致的调整。而之前,必须分析和调试一大坨代码,来判断为什么有些缓存没有在合适的时候过期。
原因是,现在的整个过程被标准化了,我们可以使用更好的工具——甚至可以自动的检测类似问题:不合适的缓存上下文,过低的缓存生命周期,过于频繁的缓存失效。
最后,这一切使得 Drupal 8 成为最快的 Drupal
Drupal 8 的动态页面缓存 vs Drupal 7 的 Authcache
动态页面缓存在 Drupal 7 中最相近内容应该就是 Authcache 模块了。在 Drupal 7 中使用 Authcache 也能获得非常好的性能,但是这需要大量的工作:所有的代码(第三方的和自行实现的)必须进行分析,以保证所有的输出过程中所有需要进行缓存验证的部分都对应到账号。所有的因素必须都传递给 Authcache,来进行缓存键的计算。“关键属性”的概念和 Drupal 8 的缓存上下文类似。然而,这个过程很容易漏掉一些因素。这是因为站点的所有者要负责识别所有的验证,这里包含所有的模块和页面。缺省情况下,Authcache 假设用站点的 base URL 和用户的角色来进行区分。所以除非你的站点非常简单(可能连多语言都不支持),否则就要进行很多的研究来用好 Authcache。
(例如目前还在运行 Drupal 7 的 Drupal.org,几个月前推出了针对评论的渲染缓存功能。他的工作方式很像 Authcache:必须指定引起缓存校验的因素。有个因素(时区)被忽略了,结果导致了奇怪的输出结果。强如 Durpal.org 的团队,也发生了这种错误,我们如何能够寄希望于其他团队呢?)
Drupal 8 中的动态页面缓存建立在缓存元数据概念之上。不需要自定义钩子,也无需用户参与。缓存行为现在是模块的责任,有理由相信,模块作者更知道模块的功能,因此也无需再次进行代码分析。动态缓存还支持缓存标记,所以跟 Drupal 7 的 Authcache 不同,动态页面缓存能够及时进行更新。
在 Drupal 8.0.0 中,动态页面缓存在 bootstrap、路由、路由访问控制之后执行。而因为 Authcache 做了一些简单假设,他能够在完全执行完 bootstrap 之前执行,这样无疑是更快的。我们也正在一个 issue (#2541284) 中提出这个问题,这一问题如果得以解决,能够得到巨大的性能提升,我们会在 Drupal 8 未来的某个版本中发布出来。
最后因为 Drupal 8 中缺省就启用了动态页面缓存,所以他直接为所有的开发者和所有的站点产生巨大的影响。建议所有的 Drupal 开发者在代码中定制合适的缓存上下文。这样 Drupal 8 的模块就会被为数众多的网站所考验,遗失的缓存元数据也就可以迅速修正。所有用户一起来完成这一任务,而不是像 Authcache 用户那样单打独斗。