延迟,直到超时PHP多卷曲请求

时间:2019-02-01 17:50:21

标签: php curl php-5.4 curl-multi

摘要

我有一些PHP 5.4代码,可以使用多卷曲并行获取一批Facebook / Instagram照片。这段代码已经使用了多年,据我所知,没有任何变化。

我将多个curl请求添加到“ multi”请求中。每个curl请求都会得到一个CURLOPT_TIMEOUT。我看到的问题是,突然之间,我的一些请求直到达到此超时(无论我设置了什么超时)都没有完成。

代码

我这样做(简化):

do {
    while (CURLM_CALL_MULTI_PERFORM === curl_multi_exec($mh, $running));

    // Wait for activity on any curl-connection (optional, reduces CPU)
    curl_multi_select($mh);

    // a request was just completed -- find out which one
    while($done = curl_multi_info_read($mh))
    {
        $completedCurlRequest = $done['handle'];

        //save the file
        do_some_work(completedCurlRequest);

        curl_multi_remove_handle($mh, $completedCurlRequest);
    }
} while ($running);

我使用此脚本运行大约40个并行请求的批处理,以获取一些图像(从Facebook)。它们中的大多数大约需要500毫秒才能完成。但是,一些请求在到达之前会“挂起”(直到CURLOPT_TIMEOUT为止。)

基本上,curl_multi_select步骤会占用整个超时时间。或者,如果我删除了curl_multi_select行,则外循环旋转(正在消耗CPU)直到超时。

注意事项

  • 超时没有关系-如果我将超时设置为30s, 他们在30秒后到达,如果我将超时设置为1秒,它们就会到达 1秒后!

  • 这是一个真正的突然变化,与任何代码都不相关 发行-直到2019年1月30日为止一切正常,但在 31日突然停止工作。

  • 这不容易重现,因为它只影响图像一次。如果我 对我已经获取的一批图像重复此操作,效果很好 下次。

  • 它同时影响Facebook和Instagram图片,所以我认为这个问题 必须与我的代码或服务器(而不是Facebook或 Instagram),因为他们俩都不会改变 同时

问题

  1. 我在使用多卷曲程序时可能做错了什么吗? (但如果是这样,有什么变化?)
  2. Facebook和Instagram是否更改了可能导致此问题的任何内容?
  3. 我的服务器上的某些内容可能已更改以触发此操作吗?
  4. 我该如何调试呢?

更新 这是我终于从缓慢的请求中得到的回报:

INFO

"content_type": "image/jpeg",
"http_code": 200,
"header_size": 377,
"request_size": 180,
"total_time": 15.001012,    //<----- Total time == CURLOPT_TIMEOUT
"namelookup_time": 0.007149,
"connect_time": 0.12018,
"pretransfer_time": 0.441911,
"size_download": 40714,
"speed_download": 2714,
"download_content_length": -1,   //<------Not set

HEADER

HTTP/2 200 
content-type: image/jpeg
x-haystack-needlechecksum: 3529661797
timing-allow-origin: *
access-control-allow-origin: *
cache-control: max-age=1209600, no-transform
date: Mon, 04 Feb 2019 14:04:17 GMT
access-control-expose-headers: X-FB-CEC-Video-Limit

它缺少content-length头,但似乎总是的情况下的第一次一个文件被取出。 50个并行请求中只有1个或2个比较慢,但是所有请求都缺少其内容长度标头。

如果我再次读取相同的文件,这是更快的,我确实看到内容长度被设定此时

INFO

"download_content_length": 52721,

HEADER

content-length: 52721           

1 个答案:

答案 0 :(得分:0)

我目前的理论是Facebook文件服务器中存在一个错误,这意味着即使已发送数据,有时连接也没有关闭,因此连接保持打开状态直到超时。如果Facebook的文件服务器没有发送(可选的)内容长度标头,则cURL无法知道有效载荷是否完整,因此挂起。

我当前的解决方案是通过首先请求没有主体的图像来“灌注”文件服务器,如下所示:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_exec($ch);

这是一个非常快速的过程,因为没有图像返回。实际上,我是在后台使用异步多重卷曲进行此操作的,因此可以继续进行其他处理。

启动文件服务器后,对文件的后续请求比以前更快,因为知道内容长度。

这有点笨拙,但是到目前为止,由于Facebook没有任何回应,我不确定该怎么做。