摘要
我有一些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),因为他们俩都不会改变 同时
问题
更新 这是我终于从缓慢的请求中得到的回报:
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
答案 0 :(得分:0)
我目前的理论是Facebook文件服务器中存在一个错误,这意味着即使已发送数据,有时连接也没有关闭,因此连接保持打开状态直到超时。如果Facebook的文件服务器没有发送(可选的)内容长度标头,则cURL无法知道有效载荷是否完整,因此挂起。
我当前的解决方案是通过首先请求没有主体的图像来“灌注”文件服务器,如下所示:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_exec($ch);
这是一个非常快速的过程,因为没有图像返回。实际上,我是在后台使用异步多重卷曲进行此操作的,因此可以继续进行其他处理。
启动文件服务器后,对文件的后续请求比以前更快,因为知道内容长度。
这有点笨拙,但是到目前为止,由于Facebook没有任何回应,我不确定该怎么做。