我目前有一台 Apache2 服务器,它运行mpm-prefork
在mod_php
OpenVZ VPS 上,具有 512M 实际 RAM / 1024M 突发 RAM(无交换)。运行一些测试后,我发现 Apache 获得的最大进程大小为 23M,因此我将其设置MaxClients
为 25(23M x 25 = 575 MB,对我来说没问题)。我决定在我的服务器上运行一些负载测试,结果让我感到困惑。
我正在ab
我的台式机上请求来自 wordpress 博客的主页。
当我ab
使用 24 个并发连接运行时,一切似乎都很好。当然,CPU 上升,可用 RAM 下降,结果是每个请求的响应时间约为 2-3 秒。
但是如果我ab
使用 25 个并发连接(我的服务器限制),Apache 会在几秒钟后挂起。它开始处理请求,然后停止响应,CPU 回到 100% 空闲状态并ab
超时。Apache 日志显示它已达到MaxClients
。
当这种情况发生时,Apache 会将自身锁定在 25 个正在运行的进程上(如果我检查服务器状态,它们都处于“W”状态),并且只有在设置之后,TimeOut
进程才会开始死亡,服务器才会再次开始响应(在我的情况下,它设置为 45)。
我的问题是:这是预期的行为吗?为什么 Apache 在达到 时就死机了MaxClients
?如果它可以在 24 个连接下工作,那么在 25 个连接下难道不应该工作吗?只是可能需要更多时间来响应每个请求并将其余请求排队?
对我来说,这听起来有点奇怪,任何一个孩子ab
只需设置与服务器的并发连接就可以独自杀死一个网络服务器MaxClients
。
答案1
哈!我终于自己找到了问题所在。这更多地与编程有关,而不是与服务器管理有关,但我还是决定把答案放在这里,因为通过谷歌搜索,我发现我不是唯一一个遇到这种问题的人(而且由于 Apache 挂起,第一个猜测是服务器有问题)。
问题不在于 Apache,而在于我的 Wordpress。更具体地说是我的主题。我使用的主题名为 Lightworld,它支持将图像添加到博客标题。为了实现这一点,它使用 PHP 的函数检查图像大小getimagesize()
。由于此函数正在打开另一个与服务器的 http 连接以获取图像,因此来自的每个请求都ab
在 PHP 内部创建另一个请求。由于我使用了所有可用的服务器插槽,这些 PHP 请求被放入队列中,但 Apache 永远无法访问它们,因为它的所有进程都被锁定,原始请求正在等待插槽来完成 PHP 内部请求。
基本上,PHP 使我的服务器陷入死锁状态,并且只有在这些连接等待其“子”请求超时后,Apache 才会开始正常工作。
从我的主题中删除此功能后,现在我可以ab
在我的服务器上运行任意数量的并发连接,并且 Apache 会按预期对它们进行排队。
答案2
这里发生的情况是,您有 25 个线程可以接受连接,并且您正在发送 26 个并发请求。最后一个请求位于套接字队列中,具体取决于您的积压大小。
第二个问题是,无论您运行什么都需要 2-3 秒,响应的时间都足够长,25 个并发连接会减慢它的速度。sleep(1) 可能会起作用,但是,当您从 mysql 执行文件锁定或表锁定时,每个并行请求可能都在等待先前完成,直到达到 45 秒超时。
对于加载了 mod_php 和任何模块的 apache 进程来说,23mb 听起来很小,因此,我怀疑您可能会看到这些 apache 进程在应用程序运行时占用更多的内存。您无法真正用 MaxClients 和内存进行数学运算...它会有点接近,但您永远不知道。
www-data 1495 0.1 0.9 56288 19996 ? S 15:48 0:01 /usr/sbin/apache2 -k start
www-data 1500 0.0 0.5 49684 12436 ? D 15:48 0:00 /usr/sbin/apache2 -k start
有一台机器,56M 和 49M 进程。
另一台机器:
www-data 7767 0.1 0.1 213732 14840 ? S 14:55 0:08 /usr/sbin/apache2 -k start
www-data 8020 0.2 0.1 212424 13660 ? S 14:57 0:08 /usr/sbin/apache2 -k start
另一台机器:
www-data 28509 0.8 0.1 161720 10068 ? S 14:39 0:43 /usr/sbin/apache2 -k start
www-data 28511 0.8 0.1 161932 10344 ? S 14:39 0:43 /usr/sbin/apache2 -k start
因此,内存使用在很大程度上取决于任务、加载了哪些模块等等。对于最后两个,我相信我们已经禁用了 pdo 和 pdo_mysql,因为该应用程序不使用它们。
真正的问题是,您正在做什么,这需要 3 秒钟?在当今世界,这已经是一段漫长的时间,并且被视为“阻塞”应用程序。Apache 通常不会死机,但会将这些线程留在积压队列中,直到它可以为它们提供服务或等待的请求超时。我相信您的应用程序可能会导致 Apache 超时。在仅包含 phpinfo(); 的页面上尝试一下,看看结果是否相同。