【发布时间】:2014-05-15 17:39:05
【问题描述】:
我们的团队正在开发 WordPress 插件,并在几个独立的服务器上提供托管实例。我们的 WordPress 安装由 Git 管理,所有服务器都部署了相同的源和 WordPress 设置,只有域和数据库中的实际数据有所不同。对于每次安装,MySql 都在同一台主机上运行。 WordPress 仅在每台服务器上运行。
但是,在 Windows Server 2008 RC2 上部署此设置后,我们注意到与我们的其他服务器相比存在巨大的性能差异:页面生成时间从 avg.使用 PHP 生成的页面需要 400 毫秒到 4000-5000 毫秒。仅 Apache 提供的静态资源,速度与 linux 差不多。
所以我们采取了一些措施来缩小问题范围:
- 确保没有运行防病毒软件或其他 Windows 域的东西干扰
- 收集分析数据以识别脚本执行期间的时间杀手
- 测试不同的服务器和硬件设置
- 仔细检查 Apache 和 PHP 配置是否存在明显的配置错误
经过一些分析后,我们很快注意到正则表达式的计算在我们的 Windows 机器上非常慢。评估 10.000 个正则表达式 (preg_match) 在 Linux 上大约需要 90 毫秒,在 Windows 上大约需要 3000 毫秒。
下面提供了分析、系统测试和配置详细信息。 我们不想优化这个脚本(我们知道该怎么做)。我们希望让脚本在 Windows 上的运行速度与在 Linux 上大致相同(假设 opcache/...的设置相同)。也无需优化脚本的内存占用。
更新:一段时间后,系统似乎内存不足,触发内存不足异常和随机分配。有关更多详细信息,请参见下文。重启 Apache/PHP 暂时解决了这个问题。
追踪到_get_browser 是:
File (called from)
require wp-blog-header.php (index.php:17)
wp (wp-blog-header.php:14)
WP->main (functions.php:808)
php::do_action_ref_array (class-wp.php:616)
php::call_user_func_array (wp-includes/plugin:507)
wp_slimstat::slimtrack (php::internal (507))
wp_slimstat::_get_browser (wp-slimstat.php:385)
更新 2:出于某种我不记得的原因,我们又将 PHP 作为服务器上的 Apache 模块激活(同样会导致性能不佳)。但是今天它们运行得非常快(~1sec/request)。添加 Opcache 可以将其降低到 ~400ms/req。 Apache/PHP/Windows 保持不变。
1) 分析结果
分析是在所有机器上使用 XDebug 完成的。通常我们只收集了一些运行 - 这些足以揭示大部分时间(50%+)花费的位置:WordPress 插件 wp-slimstats 的方法 [get_browser][1]:
protected static function _get_browser(){
// Load cache
@include_once(plugin_dir_path( __FILE__ ).'databases/browscap.php');
// browscap.php contains $slimstat_patterns and $slimstat_browsers
$browser = array('browser' => 'Default Browser', 'version' => '1', 'platform' => 'unknown', 'css_version' => 1, 'type' => 1);
if (empty($slimstat_patterns) || !is_array($slimstat_patterns)) return $browser;
$user_agent = isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:'';
$search = array();
foreach ($slimstat_patterns as $key => $pattern){
if (preg_match($pattern . 'i', $user_agent)){
$search = $value = $search + $slimstat_browsers[$key];
while (array_key_exists(3, $value) && $value[3]) {
$value = $slimstat_browsers[$value[3]];
$search += $value;
}
break;
}
}
// Lots of other lines to relevant to the profiling results
}
这个函数类似于 PHP 的get_browser 检测浏览器的功能和操作系统。大部分脚本执行时间都花在这个foreach 循环中,评估所有那些preg_match(每个页面请求大约8000 - 10000)。这在 Linux 上大约需要 90 毫秒,在 Windows 上大约需要 3000 毫秒。所有测试设置的结果都相同(图片显示了两次执行的数据):
当然,加载两个巨大的数组需要一些时间。也评估正则表达式。但我们预计它们在 Linux 和 Windows 上花费的时间大致相同。这是 linux vm 上的分析结果(仅限一页请求)。区别很明显:
另一个时间杀手实际上是 WordPress 使用的对象缓存:
function get( $key, $group = 'default', $force = false, &$found = null ) {
if ( empty( $group ) )
$group = 'default';
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
$key = $this->blog_prefix . $key;
if ( $this->_exists( $key, $group ) ) {
$found = true;
$this->cache_hits += 1;
if ( is_object($this->cache[$group][$key]) )
return clone $this->cache[$group][$key];
else
return $this->cache[$group][$key];
}
$found = false;
$this->cache_misses += 1;
return false;
}
时间花在这个函数本身上(3 个脚本执行):
在 Linux 上:
最后一个真正的大杀手是翻译。从记忆中加载的每个翻译在 WordPress 中需要 0.2 毫秒到 4 毫秒:
在 Linux 上:
2) 测试系统
为了确保虚拟化或 Apache 确实会影响这一点,我们在几个设置上对此进行了测试。所有设置都禁用了 Antivir:
- Linux Debian、Apache 2 和 PHP 在最新的稳定版本上。这对于在他们的虚拟机中运行的开发人员来说和在登台/实时服务器上是一样的。作为所需性能的参考系统。在我们的办公室或某些托管服务(共享空间)中运行。 Windows 系统的内存在 4GB 到 8GB 之间,内存使用率一直低于 50%。虚拟化永远不会同时运行 Windows 和 Apache。
- Life-Servers,在 T-Systems(托管虚拟化服务器)上运行,在 VMWare Player 上
- 赢得 2008 R2。 Apache 2.2.25 + PHP 5.4.26 NTS,VC9 作为 fastcgi 模块
- 赢得 2008 R2。 Apache 2.2.25 + PHP 5.5.1 NTS,VC11 作为 fastcgi 模块
- 赢得 2008 R2。 Apache 2.2.25 + PHP 5.5.1 NTS,VC11 作为 apache 模块
- Win 2008 R2,Apache 2.2.25 + PHP 5.5.11 TS,VC11 作为 apache 模块(这是我在更新 2 中提到的快速模块)
- 在本地机器上,主机:OpenSuse,虚拟化:VMWare 播放器,与@T-Systems 相同。为了避免他们的基础设施影响我们:
- 赢得 2008 R2。 Apache 2.2.25 + PHP 5.4.26 NTS,VC9 作为 fastcgi 模块
- 赢得 2008 R2。 IIS7 + PHP 5.4.26 NTS,VC9 作为 fastcgi 模块(带和不带 wincache)
- Win 2012. IIS * + PHP 5.5.10 NTS,VC11 作为 fastcgi 模块(带和不带 wincache)
- 在没有虚拟化的本地机器上
- 赢得 2008 R2。 Apache 2.2.25 + PHP 5.4.26 NTS,VC9 作为 fastcgi 模块
上述分析结果在不同系统上是相同的(约 10% 的推导)。 Windows 总是比 Linux 慢的一个重要因素。
使用全新安装的 WordPress 和 Slimstats 产生了大约同样的结果。重写代码在这里不是一个选项。
更新:与此同时,我们发现了另外两个 Windows 系统(Windows 2008 R2、VM 和 Phys),它们的完整堆栈运行得非常快。相同的配置。
更新 2:在 Life-Servers 上将 PHP 作为 apache 模块运行比 fastcgi 方法稍快:低至约 2 秒,减少 50%。
内存不足
一段时间后,我们的 Live-Server 完全停止工作,触发这些内存不足异常:
PHP Fatal error: Out of memory (allocated 4456448) (tried to allocate 136 bytes)
PHP Fatal error: Out of memory (allocated 8650752) (tried to allocate 45 bytes)
PHP Fatal error: Out of memory (allocated 6815744) (tried to allocate 24 bytes)
这发生在随机脚本位置。显然 Zend 内存管理器不能分配更多的内存,尽管脚本可以这样做。在事件发生时,服务器有大约 50% 的可用 RAM (2GB+)。所以服务器实际上并没有用完内存。重启 Apache/PHP 暂时解决了这个问题。
不确定此问题是否与此处的性能问题有关。然而,由于这两个问题似乎都与内存有关,因此将其包含在此处。特别是我们将尝试重现提供良好性能的 Windows 测试的设置。
3) Apache & PHP 配置
... 可能没有任何常见的陷阱。输出缓冲已启用(默认),多字节覆盖已禁用,...如果有任何选项感兴趣,我们将很乐意提供它们。
httpd.exe -V的输出
Server version: Apache/2.4.7 (Win32)
Apache Lounge VC10 Server built: Nov 26 2013 15:46:56
Server's Module Magic Number: 20120211:27
Server loaded: APR 1.5.0, APR-UTIL 1.5.3
Compiled using: APR 1.5.0, APR-UTIL 1.5.3
Architecture: 32-bit
Server MPM: WinNT
threaded: yes (fixed thread count)
forked: no
Server compiled with....
-D APR_HAS_SENDFILE
-D APR_HAS_MMAP
-D APR_HAVE_IPV6 (IPv4-mapped addresses disabled)
-D APR_HAS_OTHER_CHILD
-D AP_HAVE_RELIABLE_PIPED_LOGS
-D DYNAMIC_MODULE_LIMIT=256
-D HTTPD_ROOT="/apache"
-D SUEXEC_BIN="/apache/bin/suexec"
-D DEFAULT_PIDLOG="logs/httpd.pid"
-D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
-D DEFAULT_ERRORLOG="logs/error.log"
-D AP_TYPES_CONFIG_FILE="conf/mime.types"
-D SERVER_CONFIG_FILE="conf/httpd.conf"
mpm_winnt_module 配置:
<IfModule mpm_winnt_module>
ThreadsPerChild 150
ThreadStackSize 8388608
MaxConnectionsPerChild 0
</IfModule>
php.ini 摘录:
realpath_cache_size = 12M
pcre.recursion_limit = 100000
4) 目前怀疑的原因
旧假设:
所有三个示例都严重依赖大数组和字符串操作。那某种似乎是普通工厂。由于实现在 Linux 上运行良好,我们怀疑这是 Windows 上的内存问题。鉴于在精确定位的位置没有数据库交互,我们不怀疑数据库或服务器 PHP 集成是问题所在。不知何故,PHP 的内存交互似乎很慢。 也许有人干扰了 Windows 上的内存,导致访问速度显着变慢?
旧假设 2:
由于相同的堆栈在其他 Windows 机器上运行良好,我们假设问题出在 Windows 配置中。
新假设 3:
实际上我没有假设。为什么 PHP 会像 fastcgi 那样运行比 apache 模块慢得多>
关于如何验证这一点或在这里找到真正问题的任何想法?非常欢迎任何有关解决此问题的帮助或指导。
【问题讨论】:
-
您是否在同一硬件上运行两者?
-
@hek2mgl : apache 和 mysql?是的。考虑到当前的内存/CPU 消耗和所花费时间的位置,这应该不会造成问题。
-
不,我是说windows和linux
-
我的意思是:它们有可比性吗?
-
@halfer:IIS 是一个完美的选择。但是,我们在 IIS 上也有同样糟糕的性能(参见 2)测试系统)。
标签: php linux windows wordpress performance