PHP中的长运行时脚本导致NGINX服务器变得非常繁忙

时间:2012-08-05 14:02:05

标签: nginx php

我会尝试对此非常具体 - 这并不容易,所以请尽量遵循。

我们有一个在NGINX上使用PHP运行的脚本 - PHP-fpm FastCGI。 此脚本从尝试访问它的用户获取信息,并在实时上运行某些算法。它不能是在后台运行的预定进程。 有时,甚至需要加载5-12秒之间的页面 - 而确定。 通常,我们从用户收集数据并向第三方服务器发出多个传出请求,收集数据,分析数据并为用户返回响应。

问题是, 有很多很多用户运行此脚本,服务器非常繁忙 - 因为它们都是服务器上的活动连接,等待响应。 我们有2台服务器在1负载均衡器下运行,这还不够。 有时,服务器一次有超过1,500个活动连接。您可以想象这些服务器在该时间范围内的响应方式。

我正在寻找解决方案。 我们可以为LB添加越来越多的服务器,但这是唯一的解决方案,这听起来很荒谬。 我们跑过那个脚本并将其优化到最大程度,我可以向你保证 - 对于该脚本的长时间运行没有真正的解决方案,因为它依赖于第三方服务器需要时间来回应我们的实时流量。

是否有一个你能想到的解决方案,保持这个脚本不变 - 但不知何故,为了降低这些活动连接对整个服务器功能的影响? 有时,他们只是停下来回应。

非常感谢您的阅读!

3 个答案:

答案 0 :(得分:3)

3个月的问题,我知道,但我无法帮助它思考:

  1. 如果您确定所有对第三方服务器的请求的网络总和加上PHP脚本中相应的响应处理低于硬件的限制。

  2. 然后,您的PHP脚本可能会无效地忙于循环,直到所有响应都从第三方服务器返回

  3. 如果我正在处理这样的问题,我会这样做:

    1. 停止使用自定义外部C ++ curl,因为PHP脚本正在忙着等待它。

    2. Google,了解PHP的curl-multi实现的非繁忙循环使用

    3. 希望这是有道理的。

答案 1 :(得分:1)

我的建议是为请求设置有限的超时,为每个第三方请求使用异步请求

例如,对于您的页面,您必须显示5个第三方请求的结果。这意味着,您在内部脚本中调用cURLfile_get_contents 5次,但脚本会因第三方的每次超时而冻结。一步步。这意味着,如果对于每个请求,您必须等待10秒才能得到响应 - 您将总共有50秒 User calls the script -> script wait to end -> server is loaded for 50 seconds

现在,如果对第三方的每个请求都将异步发送 - 它会将脚本的加载时间减少到最大请求延迟。因此,您将拥有一些较小的脚本,这些脚本的寿命会缩短 - 并且会降低服务器的负载 User calls the script -> script is loaded -> requests are sent -> there are no scripts that are waiting for the response and consuming resources of your server

愿AJAX和你在一起! ;)

答案 2 :(得分:0)

这是一个非常老的问题,但是由于我有一个类似的问题,所以我可以分享我的解决方案。长时间运行的脚本会影响系统的各个部分,并导致web服务器(处于活动连接状态),php-fpm和mysql / other数据库的压力。这些往往会导致一系列影响,例如其他请求开始失败。

首先确保服务器上已安装netdata(https://github.com/netdata/netdata)。如果您正在运行许多实例,则可能会发现具有Grafana / Prometheus设置也是值得的。

接下来,确保它可以看到PHP FPM进程Mysql和Nginx。 Netdata显示了很多东西,但是对于这个问题,我的关键指标是:

  • 连接(mysql_local.connections)-是充满连接的数据库
  • PHP-FPM活动连接(phpfpm_local.connections)-PHP无法跟上
  • PHP-FPM请求持续时间(phpfpm_local.request_duration)-处理时间到了吗?
  • 磁盘使用时间(disk_util.sda)-显示磁盘是否无法保持(100%=负载不足)
  • 用户打开文件(users.files)

请确保您有足够的文件句柄(https://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/),并且磁盘未完全占用。这两个都将阻止您使工作正常进行,因此请在麻烦的服务器上将它们增大。

下一步检查Nginx在nginx.conf中是否有足够的资源:

worker_processes auto;
worker_rlimit_nofile 30000;

events {
    worker_connections 768;
}

这将使您有时间找出问题所在。

接下来查看php-fpm(/etc/php/7.2/fpm/pool.d/www.conf):

  • 将pm.max_spare_servers设置为较高的值,例如100
  • 设置pm.max_requests = 500-以防万一您的脚本无法正确释放自身。

然后观看。我的问题是每个请求都会阻止传入连接。对同一脚本的更多请求将阻止更多连接。机器可以正常运行,但是执行卷曲命中或慢速SQL语句的单个慢速脚本将在整个持续时间内保持该连接,因此30秒=减少了处理传入请求的php进程。最终,您击中500,然后用尽。如果您可以增加FPM进程的数量,以使慢速脚本请求的频率与其运行的秒数相匹配。因此,如果脚本花费2秒并每秒被命中2次,则您将需要不断增加4个fpm worker线程来执行任何操作。

如果可以的话,就停在那儿-额外的努力可能不值得。如果仍然有问题,请在包装盒上创建第二个php-fpm实例,并将对慢速脚本的所有请求发送到该新实例。这样,在运行时间过多的情况下,您可以离散地使那些请求失败。这将使您有能力执行两项重要操作:

  • 控制用于慢速脚本的资源量
  • 意味着所有其他脚本都不会受到慢速脚本的阻塞,并且(假设操作系统限制足够高)也不会受到资源限制的影响。

希望能帮助有人在负载下挣扎的生活!