改善 PHP Web 脚本的速度

作者:Bruno Pedro

PHP Web 脚本性能下降有很多原因。瓶颈可能出现在数据库查询、网页访问,甚至慢速算法中。当性能下降时,用户会因等待结果而感到沮丧。用户减少意味着业务减少,您的网站也会变得不受欢迎。

性能损失的主要原因是糟糕的软件分析和工程设计。网站通常在没有经过彻底的性能测试的情况下被创建和发布。数据库的设计通常是为了容纳比实际更少的数据。算法的设计通常很差,而且通常没有针对速度进行优化。

当您无法重新设计整个网站以使其运行更快时,您必须通过在每次访问时提供静态页面而不是解释 PHP 来提高其性能。让我们看看实现这个目标的方法。

传统解决方案

您可以做的第一件事是预处理那些执行时间较长的 PHP 脚本或脚本部分。您可以使用 PHP shell 来完成。假设您有一个名为 index.php 的 Web 脚本,并且您想要预处理它。假设 PHP shell 被称为 phpsh,则命令行是

phpsh -q /some_dir/index.php > /some_dir/index.html

文件 index.html 现在是纯 HTML,不需要任何 PHP 处理。您可以立即将其提供给 Web 客户端。但是,如果 PHP 脚本结果随时间变化怎么办?您必须在每次结果不同时预处理脚本。解决方案是定期预处理 PHP 脚本。

定期预处理

在 Linux 中,定期执行给定进程的最简单方法称为 crontab。以下 crontab 条目说明了一个每 15 分钟执行一次的预处理

*/15 * * * * root phpsh -q /some_dir/index.php
> /some_dir/index.html

但是,选择的时间可能不足以保持信息更新。此外,某些脚本在很长一段时间内不会被访问,而其他脚本则会被持续访问,这使得使用这种技术变得毫无意义。在这种情况下,需要一种基于脚本的机制。

即时预处理

这种技术定期预处理脚本,但仅在它们被访问时才进行。它的工作方式很像 Web 代理缓存系统。我将展示实现此功能的两种方法:输出缓冲和后时间处理。

输出缓冲检查缓存文件的日期和时间,并且仅在需要时才处理脚本。处理是通过缓冲输出并将其保存在缓存文件中,然后再发送到客户端来完成的。

在 PHP 中,您可以使用 ob_start() 函数来完成此操作。此函数将打开输出缓冲并将其发送到回调函数。还有另一个函数可以将缓冲区发送回浏览器:ob_end_flush()。让我们看一个例子

<?php
// include header file
include("header.php");
?>
<?php
// sleep for 10 seconds
sleep(10);
?>

测试

<?php
// include footer file
include("footer.php");
?>
在 header.php 内部,您将找到所有缓存处理。它首先通过调用 needscache() 函数来检查脚本是否需要缓存。此函数可以根据超时或您喜欢的任何内容来检查是否需要缓存。就本文而言,检查是基于缓存超时的。

如果脚本需要缓存,则启动 ob 循环,并将脚本输出写入缓存文件。如果它不需要缓存,则从缓存文件中读取脚本输出并发送到客户端的浏览器(请参阅列表 1)。

列表 1. 从缓存文件中读取脚本输出并发送到客户端的浏览器。

footer.php 脚本只是关闭 ob 处理

<?php
ob_end_flush();
?>

您可以通过在缓存超时之前多次调用脚本来测试此技术。您会注意到,在第一次调用中,您必须等待十秒钟(这是因为脚本休眠十秒钟,用于测试目的),而在随后的调用中,输出是立即的。

但是,当缓存超时时,您将不得不等待脚本完成处理。让我们看看如何防止这种情况,并给用户一种脚本始终很快的错觉。

后视图处理还检查缓存文件的日期和时间,但是处理是在文件被服务之后完成的,从而解决了缓存超时处理负担。这是通过在脚本结束执行后缓存文件来完成的。

在 PHP 中,您可以通过使用 register_shutdown_function() 将任意函数与脚本终止事件关联来完成此操作。您唯一需要更改的文件是 header.php(请参阅列表 2)。

列表 2. 将任意函数与脚本终止事件关联

我只是添加了 doaftercache() 函数,该函数仅在脚本完成后才被调用。然后它像普通浏览器一样调用脚本并缓存它。您唯一需要等待的时间是脚本以前从未被缓存过的时候。测试一下,您就会感觉到脚本非常快。

结论

本文向您展示了 PHP 缓存机制的工作原理,并提供了一个 DIY 解决方案。如果您测试了这些示例并喜欢它们,请随时实施您自己的解决方案。但是,还有其他提高性能的方法,例如函数缓存或 PHP 脚本预编译。一些现成的解决方案可以为您提供这些功能。您应该始终为自己的需求寻找最佳解决方案并进行自己的测试。

电子邮件:bpedro@eth.pt

Bruno Pedro,ethernet lda. 的联合创始人兼经理,是一位拥有十年数据库相关应用经验的系统工程师。他是 Linux 的早期采用者,并且从那时起一直在使用开源技术。自 1995 年以来,他一直在为互联网开发应用程序。

加载 Disqus 评论