找出 WordPress 为什么变慢

wp profile 是帮助快速定位 WordPress 慢在哪里的 WP-CLI 命令。它很容易部署到已有 WP-CLI 的服务器,并可与 Xdebug、New Relic 配合使用。通过它可以迅速了解执行时间、查询数量、缓存命中与未命中比例等关键指标,为进一步调试指明方向。

安装

如果尚未安装 wp profile 包,先执行:

$ wp package install wp-cli/profile-command

第一步:分析 WordPress 的加载过程

遇到一个从未接触过、运行缓慢的 WordPress 站点时,可以运行 wp profile stage,查看加载过程各阶段的指标。加入 --url=<url> 参数,可以按特定 URL 模拟请求。

$ wp profile stage --url=runcommand.io
+------------+---------+------------+-------------+-------------+------------+--------------+-----------+------------+--------------+---------------+
| stage      | time    | query_time | query_count | cache_ratio | cache_hits | cache_misses | hook_time | hook_count | request_time | request_count |
+------------+---------+------------+-------------+-------------+------------+--------------+-----------+------------+--------------+---------------+
| bootstrap  | 0.7597s | 0.0052s    | 14          | 93.21%      | 357        | 26           | 0.3328s   | 2717       | 0s           | 0             |
| main_query | 0.0131s | 0.0004s    | 3           | 94.29%      | 33         | 2            | 0.0065s   | 78         | 0s           | 0             |
| template   | 0.7041s | 0.0192s    | 147         | 92.16%      | 2350       | 200          | 0.6982s   | 6130       | 0s           | 0             |
+------------+---------+------------+-------------+-------------+------------+--------------+-----------+------------+--------------+---------------+
| total (3)  | 1.477s  | 0.0248s    | 164         | 93.22%      | 2740       | 228          | 1.0375s   | 8925       | 0s           | 0             |
+------------+---------+------------+-------------+-------------+------------+--------------+-----------+------------+--------------+---------------+

WordPress 处理浏览器请求时,本质上是在执行一个较长的 PHP 脚本。wp profile stage 将它分成三个阶段:

  • bootstrap:WordPress 初始化自身,加载插件和主主题,并触发 init 钩子。
  • main_query:WordPress 将请求(例如 /2016/10/21/moms-birthday/)转换成主要的 WP_Query。
  • template:WordPress 根据主查询确定应渲染哪个主题模板,并执行渲染。

第二步:深入某个阶段

上面的例子中,bootstrap 看起来有些慢,可以继续细查。运行 wp profile stage bootstrap,进入这一阶段的更细粒度分析模式。--spotlight 会过滤接近零的结果。

$ wp profile stage bootstrap --url=runcommand.io --spotlight
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| hook                     | callback_count | time    | query_time | query_count | cache_ratio | cache_hits | cache_misses | request_time | request_count |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| muplugins_loaded:before  |                | 0.1644s | 0.0017s    | 1           | 40%         | 2          | 3            | 0s           | 0             |
| muplugins_loaded         | 2              | 0.0005s | 0s         | 0           | 50%         | 1          | 1            | 0s           | 0             |
| plugins_loaded:before    |                | 0.1771s | 0.0008s    | 6           | 77.63%      | 59         | 17           | 0s           | 0             |
| plugins_loaded           | 14             | 0.0887s | 0s         | 0           | 100%        | 104        | 0            | 0s           | 0             |
| after_setup_theme:before |                | 0.043s  | 0s         | 0           | 100%        | 26         | 0            | 0s           | 0             |
| init                     | 82             | 0.1569s | 0.0018s    | 7           | 96.88%      | 155        | 5            | 0s           | 0             |
| wp_loaded:after          |                | 0.027s  | 0s         | 0           |             | 0          | 0            | 0s           | 0             |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| total (7)                | 98             | 0.6575s | 0.0043s    | 14          | 77.42%      | 347        | 26           | 0s           | 0             |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+

wp profile 根据主要动作进一步划分各阶段。bootstrap 阶段的主要动作包括 muplugins_loaded、plugins_loaded 和 init。还能看到 plugins_loaded:before、wp_loaded:after 等中间动作,它们对应实际 WordPress 钩子之前或之后的脚本执行,可以看作“伪钩子”。

第三步:分析具体钩子

找到需要检查的钩子后,运行 wp profile hook <hook>。加入 --fields=<fields> 参数可以只输出指定字段。

$ wp profile hook plugins_loaded --url=runcommand.io --fields=callback,time,location
+------------------------------------------------------------+---------+-----------------------------------------------------------------+
| callback                                                   | time    | location                                                        |
+------------------------------------------------------------+---------+-----------------------------------------------------------------+
| wp_maybe_load_widgets()                                    | 0.0046s | wp-includes/functions.php:3501                                  |
| wp_maybe_load_embeds()                                     | 0.0003s | wp-includes/embed.php:162                                       |
| VaultPress_Hotfixes->protect_jetpack_402_from_oembed_xss() | 0s      | vaultpress/class.vaultpress-hotfixes.php:124                    |
| _wp_customize_include()                                    | 0s      | wp-includes/theme.php:2052                                      |
| EasyRecipePlus->pluginsLoaded()                            | 0.0013s | easyrecipeplus/lib/EasyRecipePlus.php:125                       |
| Gamajo\GenesisHeaderNav\genesis_header_nav_i18n()          | 0.0007s | genesis-header-nav/genesis-header-nav.php:61                    |
| DS_Public_Post_Preview::init()                             | 0.0001s | public-post-preview/public-post-preview.php:52                  |
| wpseo_load_textdomain()                                    | 0.0004s | wordpress-seo-premium/wp-seo-main.php:222                       |
| load_yoast_notifications()                                 | 0.0016s | wordpress-seo-premium/wp-seo-main.php:381                       |
| wpseo_init()                                               | 0.0329s | wordpress-seo-premium/wp-seo-main.php:240                       |
| wpseo_premium_init()                                       | 0.0019s | wordpress-seo-premium/wp-seo-premium.php:79                     |
| wpseo_frontend_init()                                      | 0.0007s | wordpress-seo-premium/wp-seo-main.php:274                       |
| Black_Studio_TinyMCE_Plugin->load_compatibility()          | 0.0016s | black-studio-tinymce-widget/black-studio-tinymce-widget.php:206 |
| Jetpack::load_modules()                                    | 0.0564s | jetpack/class.jetpack.php:1672                                  |
+------------------------------------------------------------+---------+-----------------------------------------------------------------+
| total (14)                                                 | 0.1026s |                                                                 |
+------------------------------------------------------------+---------+-----------------------------------------------------------------+

在这个例子中,可以发现 wpseo_init() 和 Jetpack::load_modules() 合计为每次页面加载贡献了约 100 毫秒的耗时。

有了 wp profile,找出 WordPress 变慢的原因就更容易了。


来源:WP-CLI 手册《Figure out why WordPress is slow》,WP-CLI Development Group 与手册贡献者。本文为中文翻译,保留全部原始命令与示例输出。所有结果均为原文示例,未在本次准备中运行;其中软件路径、行号和耗时对应原案例,不能视作当前版本的实测结果。命令行模拟请求也不包含完整浏览器渲染时间。安装命令会增加 WP-CLI 包;样例 runcommand.io 是原文域名,不是已验证的测试目标。

本文依据 wp-cli/handbook 文章源码,按仓库 MIT 许可证使用:

The MIT License (MIT)

Copyright (C) 2012-2022 WP-CLI Development Group (https://github.com/wp-cli/handbook/contributors)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容