【问题标题】:PHP generating pages, but not returning them to the user right awayPHP 生成页面,但不立即将它们返回给用户
【发布时间】:2011-09-03 14:47:32
【问题描述】:

我目前正在测试我正在组装的服务器设置的负载能力。 apache2 服务器上安装了 PHP 5.X,它连接到单独机器上的主数据库,然后连接到 2 个从服务器中的 1 个进行读取。

如果我自己调用它,我的测试页需要 0.2 秒才能生成。我在另一台服务器上创建了一个 php 脚本,它同时创建了 65 个对测试页面的调用。测试页面在整个页面中进行微时间基准测试,让我知道每个部分需要多长时间。正如预期的那样 - 至少对我来说,如果有人对此有意见或建议,请随时发表评论 - 页面的 SQL 部分需要很短的时间来处理它收到的前几个请求,然后降级,因为其余的查询堆积起来,必须等待。我认为这可能是磁盘 IO 问题,但在固态驱动器上测试时发生了同样的行为。

我的问题是大约 65 个页面中的大约 30 个已创建,并按我的预期由我的测试脚本加载。例如,我的基准测试说页面是在 3 秒内创建的,而我的测试脚本说它在 3.1 秒内收到了完整的页面。差别不大。问题是对于其他请求,我的基准测试表明页面在 3 秒内加载,但测试脚本直到 6 秒才完整接收到页面。从 apache 服务器生成的页面到发送回请求它的测试脚本之间有整整 3 秒的时间。为了确保测试脚本没有问题,我尝试在本地浏览器运行时加载页面,并通过 Chrome 中的时间线窗口确认了相同的延迟。

我已经为 Apache 尝试了各种配置,但似乎找不到导致此延迟的原因。我最近的尝试如下。该机器是具有 2Ghz 内存的四核 AMD 2.8Ghz。任何有关配置的帮助或其他有关操作的建议将不胜感激。 -- 抱歉问了这么长的问题。

我应该提到,我在脚本运行时监控了资源,CPU 达到了最大 9% 的负载,并且始终至少有 1 gig 的可用内存。

我还会提到,当我查询的只是一个静态 HTML 页面时,也会发生相同类型的事情。第一对需要 .X 秒,然后慢慢增加到 3 秒。

LockFile ${APACHE_LOCK_DIR}/accept.lock
PidFile ${APACHE_PID_FILE}
超时 120
最大客户数 150
保持活动状态
保活超时 4
MaxKeepAliveRequests 150

标头始终附加 x-frame-options sameorigin

    启动服务器 50
    MinSpareServers 25
    MaxSpareServers 50
    最大客户数 150
    MaxRequestsPerChild 0


用户 ${APACHE_RUN_USER}
组 ${APACHE_RUN_GROUP}
AccessFileName .httpdoverride

    命令允许,拒绝
DefaultType 文本/纯文本
主机名查找关闭
错误日志 ${APACHE_LOG_DIR}/error.log
日志级别警告
包括 mods-enabled/*.load
包括 mods-enabled/*.conf
包括 httpd.conf
包括 ports.conf

LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" 组合
LogFormat "%h %l %u %t \"%r\" %>s %O" 常见
LogFormat "%{Referer}i -> %U" 引用
LogFormat "%{User-agent}i" 代理
包括 conf.d/
包括启用站点/
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps



    SecRuleEngine 开启
    SecRequestBodyAccess 开启
    SecResponseBodyAccess 关闭
    SecUploadKeepFiles Off
    SecDebugLog /var/log/apache2/modsec_debug.log
    SecDebugLogLevel 0
    SecAuditEngine RelevantOnly
    SecAuditLogRelevantStatus ^5
    SecAuditLogParts ABIFHZ
    SecAuditLogType 串行
    SecAuditLog /var/log/apache2/modsec_audit.log
    SecRequestBodyLimit 131072000
    SecRequestBodyInMemoryLimit 131072
    SecResponseBodyLimit 524288000
        服务器令牌已满
        SecServerSignature "Microsoft-IIS/5.0"

更新: 似乎很多回应都集中在 SQL 是罪魁祸首这一事实上。所以我在这里声明相同的行为发生在静态 HTML 页面上。下面列出了基准测试的结果。

并发级别:10 测试时间:5.453 秒 完成请求:1000 失败的请求:899 (连接:0,接收:0,长度:899,例外:0) 写入错误:0 总传输量:290877 字节 传输的 HTML:55877 字节 每秒请求数:183.38 [#/sec](平均) 每个请求的时间:54.531 [ms](平均) 每个请求的时间:5.453 [ms](平均值,所有并发请求) 传输速率:收到 52.09 [Kbytes/sec] 连接时间(毫秒) 最小值平均值[+/-sd] 中值最大值 连接:0 21 250.7 0 3005 处理:16 33 17.8 27 138 等待:16 33 17.8 27 138 总计:16 54 253.0 27 3078 特定时间内服务的请求百分比(毫秒) 50% 27 66% 36 75% 42 80% 46 90% 58 95% 71 98% 90 99% 130 100% 3078(最长请求)

我还要声明,我通过使用 PHP 和 microtime() 确定延迟是在页面生成之前发生的。我通过生成页面和我的测试脚本接收它之间的时间差来确定这一点。差异是一致的,这意味着从生成页面到我的测试页面收到它的时间量是相同的,无论整个请求花费了多长时间。

感谢所有回复的人。都是好点,我不能说他们中的任何一个都解决了这个问题。

【问题讨论】:

  • 尝试更高的 StartServers 和 MinSpareServers。以我的经验,当流量突然爆发时,apache 可能需要一段时间才能启动额外的线程。在更宏大的计划中,通过快速反向代理 (nginx) 进行代理以更快地响应连接并更快地释放 apache 线程。更好的是,使用 squid/varnish 缓存页面,这样您就不会浪费资源数百次生成完全相同的内容。
  • 啊,刚刚注意到关于数据库的一点。 1) 尽可能避免写入 2) 确定哪些查询正在减慢 3) 缓存以完全避免数据库访问。我会做一些基准测试——记录每个查询的查询时间,并生成所有运行查询的列表,在请求期间从最慢到最快排序。
  • 好问题,只是属于不同的网站。
  • @AJ - 为什么它不属于这个网站?
  • @Frank: 1) 我正在做的唯一写入是基于内存的表。 2) 它实际上是在每页上运行 10 次完全相同的查询。从表 LIMIT 1000 中选择 *; 3)我增加了数据库服务器上的缓存,但由于某种原因它不想缓存它。在 apache 方面,1)我尝试通过反向代理并直接连接到机器,结果相同。 2)我可以缓存页面,但生产环境不会经常提供具有完全相同内容的页面,因此测试不会模拟实际使用情况。我会在一分钟内发布更高值的结果。

标签: php apache


【解决方案1】:

在下车之前加载的页面确切数量是多少?您提到您正在从单个外部脚本创建 65 个同时请求。您没有启用像 limitipconn 这样的模块,它会在来自单个 IP 的 N 个连接之后限制事情吗?是否总是正好 30 个(或其他)连接然后延迟?

【讨论】:

  • 在下降之前总是一个随机数量。如果我缩减同时请求,有时它会在 3 秒之前加载 1000 个页面。
【解决方案2】:

还有许多其他因素,但我真的猜想您正在使用 30M 左右快速生成 30-40 个进程,并杀死您的机器有限内存,然后继续生成新进程并进行交换,减慢一切都结束了。

使用 2G 内存,MaxClients 为 150,MaxRequestsPerChild 为 0,即使您的数据库不在同一台物理服务器上,服务器资源也可能会被淹没。

基本上,对于 Web 服务器性能,您永远都不想交换。运行您的测试,然后立即使用以下命令检查 Web 服务器上的内存:

free -m

这将为您提供以 MB 为单位的内存使用量和交换使用量。理想情况下,您应该看到交换 0 或接近 0。如果不是 zilch 或交换使用率非常低,问题只是内存耗尽,您的服务器正在抖动,因此浪费 CPU 导致响应时间变慢。

您需要确定一些数字,但首先执行“top”并在 top 运行时按 Shift-M 以按内存排序。下次您运行测试并找到关于每个 httpd 进程报告了多少 %MEM 的大致数字。它会有所不同,因此最好使用较高的作为最坏情况界限的指导。我在同一台服务器上有一个 wordpress、一个 drupal 和一个客户站点,它从一开始就为每个 http 进程分配 20M,并最终随着时间向上增长——如果每个都超过 100M 的话。

举个例子,如果我有 2G 和 linux、核心服务和 mysql 使用 800M,我会保持对内存的期望,我想假设 Apache 的可用内存低于 1G .有了这个,如果我的 apache 进程平均使用 20M 的高端,我只能有 50 个 MaxClients。这是一个非常不保守的数字,在现实生活中,为了安全起见,我会将 Max 降至 40 左右。不要试图压缩内存...如果您提供的流量足以同时拥有 40 个连接,那么在启动 Max 服务器之前先花 100 美元购买 4G。就是其中之一,一旦你越过界限,一切都会从马桶上掉下来,所以要安全地控制在你的记忆力范围内!

另外,对于 php,我喜欢将 MaxRequestsPerChild 保持在 100 左右...您不是受 CPU 限制的网页服务,因此不必担心会节省几毫秒以生成新的子进程。将其设置为 0 意味着无限的请求,除非客户端总数超过 MaxSpareServers,否则它们永远不会被杀死。这通常是 A 非常糟糕的事情 php 使用 apache 工作者,因为它们只会继续增长直到出现问题(比如必须硬重启服务器,因为您无法登录导致 apache 用完所有内存和ssh 不能在没有超时的情况下工作)。

祝你好运!

【讨论】:

  • 我认为它没有进入交换,我正在监视使用情况。我现在已经获得了 4 GB 的 RAM,所以当我有时间查看结果是否不同时,我会重复测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
  • 2014-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多