Nginx + PHP:在取消请求时停止进程

eKr*_*nak 17 php nginx long-polling

我有Nginx 1.4.4和PHP 5.5.6.我正在进行长轮询请求.问题是,如果我取消通过Ajax发送的HTTP请求,请求仍在处理(它们不会停止).我在文件末尾用PHP mail()函数测试了它,而邮件仍然没有停止文件).

我很担心,因为我认为它可能导致服务器崩溃,因为未关闭的请求负载很高.是的,我试过ignore_user_abort(false);但没有变化.有可能我应该在Nginx中改变一些东西吗?

  location ~ \.php$ {    
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;  
  }
Run Code Online (Sandbox Code Playgroud)

Dan*_*ack 12

坏消息是你几乎肯定无法解决你想要解决的问题.客户端在接收请求之前关闭连接时发送的FastCGI信号是FCGI_ABORT_REQUEST

当HTTP客户端关闭其传输连接而FastCGI请求代表该客户端运行时,Web服务器将中止FastCGI请求.情况似乎不太可能; 大多数FastCGI请求的响应时间都很短,如果客户端速度很慢,Web服务器会提供输出缓冲.但FastCGI应用程序可能会延迟与另一个系统通信或执行服务器推送.

不幸的是,看起来原始的fast-cgi实现PHP-FPM都不支持FCGI_ABORT_REQUEST信号,因此不能被中断.

好消息是有更好的方法来解决这个问题.基本上你应该永远不会有需要很长时间才能处理的请求.相反,如果请求需要很长时间才能处理,您应该:

  • 将其推送到需要处理的任务队列.
  • 将"任务ID"返回给客户端.
  • 让客户定期轮询以查看该"任务"是否已完成以及何时完成显示结果.

除了这3个基本内容之外 - 如果您担心在客户端不再对请求结果感兴趣时浪费系统资源,您应该添加:

  • 如果客户端仍在询问结果,则将任务分解为小部分工作,并仅将任务从一个工作"状态"移动到下一个工作状态.

您没有说明您的长期运行任务是什么 - 让我们假装从另一台服务器下载大图像文件,操纵该图像,然后将其存储在S3中.所以这项任务的状态如下:

TASK_STATE_QUEUED
TASK_STATE_DOWNLOADING //Moves to next state when finished download
TASK_STATE_DOWNLOADED
TASK_STATE_PROCESSING  //Moves to next state when processing finished
TASK_STATE_PROCESSED
TASK_STATE_UPLOADING_TO_S3 //Moves to next state when uploaded
TASK_STATE_FINISHED
Run Code Online (Sandbox Code Playgroud)

因此,当客户端发送初始请求时,它会返回一个taskID,然后当它查询该任务的状态时,:

  • 服务器报告该任务仍在处理中

要么

  • 如果它处于以下状态之一,则客户端请求会将其提升到下一个状态.

TASK_STATE_QUEUED => TASK_STATE_DOWNLOADING
TASK_STATE_DOWNLOADED => TASK_STATE_PROCESSING
TASK_STATE_PROCESSED => TASK_STATE_UPLOADING_TO_S3
Run Code Online (Sandbox Code Playgroud)

因此,只有客户感兴趣的请求才会继续处理.

顺便说一下,我强烈建议使用一些设计用于保存任务队列(例如Rabbitmq,RedisGearman)的队列,而不仅仅是使用MySQL或任何数据库.基本上,SQL在组成队列方面并不是那么好,你最好从一开始就使用适当的技术,而不是使用错误的技术来启动,然后在数据库成为紧急情况时不得不在紧急情况下将其交换掉当它试图进行数百次插入时,每秒更新只是为了管理任务.

作为一个附带好处,通过将长时间运行的过程分解为任务,它变得非常容易:

  1. 查看处理时间的花费在哪里.
  2. 查看并检测处理时间的波动(例如,如果CPUS达到100%利用率,则图像调整大小将突然花费更长时间).
  3. 在缓慢的步骤中投入更多资源.
  4. 您可以向客户端提供状态更新消息,这样他们就可以看到任务中的进度,从而提供更好的用户体验,而不是只是坐在那里"无所事事".