【问题标题】:Persistent/keepalive HTTP with the PHP Curl library?使用 PHP Curl 库的持久/保持活动 HTTP?
【发布时间】:2010-11-01 15:45:25
【问题描述】:

我正在使用一个简单的 PHP 库通过 HTTP 将文档添加到 SOLR 索引。

目前涉及3台服务器:

  1. 运行索引作业的 PHP 框
  2. 保存被索引数据的数据库框
  3. solr 盒子。

在 80 个文档/秒(100 万个文档中)时,我注意到 PHP 和 solr 盒上的网络接口的中断率异常高(2000/秒;此外,图表几乎相同——当 PHP 盒上的中断率达到峰值时,Solr 盒上的中断率也会达到峰值),但数据库盒上的中断率要低得多(300/秒)。我想这仅仅是因为我打开并重用了与数据库服务器的单个连接,但由于 Solr 客户端库的编写方式,每个 Solr 请求当前都通过 cURL 打开一个新的 HTTP 连接。

所以,我的问题是:

  1. 可以使用 cURL 来打开 keepalive 会话吗?
  2. 如何重用连接? -- 是否像重用 cURL 句柄资源一样简单?
  3. 是否需要设置任何特殊的 cURL 选项? (例如强制 HTTP 1.1?)
  4. cURL keepalive 连接是否存在任何问题?该脚本一次运行数小时;我可以使用单一连接,还是需要定期重新连接?

【问题讨论】:

  • 好吧,我在解析整个站点时使用了它,其中包含许多需要身份验证并始终保持会话的页面。使用初始句柄资源,您可以继续执行命令以获取页面并与客户端保持相同的会话和连接。使用命令行,这已经持续了大约 20 分钟(对于我们所有的数据要求 - 因此可以持续更长时间),无需重新连接。但是我不确定这是否是您要问的,因此这是评论而不是答案:)
  • 另请注意,根据您正在执行的操作和连接的服务器,您通常需要设置一些选项。所有这些都在这里有详细记录:uk3.php.net/manual/en/function.curl-setopt.php
  • 这部分常见问题解答是相关的,虽然不是很详细:curl.haxx.se/docs/faq.html#Can_I_perform_multiple_requests
  • 我遇到了一个问题:在通过单个 curl 句柄发出大约 100,000 个请求后,我的脚本达到了 512 兆的内存使用量;在我开始重用连接之前,它从未超过 60 MB。我现在每 1000 个请求重新连接一次(这可能比必要的频率更高,但很少会导致连接开销应该非常小)
  • 还有: CURLOPT_MAXCONNECTS - 允许的最大持久连接数。当达到限制时,CURLOPT_CLOSEPOLICY 用于确定要关闭哪个连接。

标签: php http curl libcurl keep-alive


【解决方案1】:

如果您不关心请求的响应,您可以异步执行它们,但您会冒着使 SOLR 索引过载的风险。不过我对此表示怀疑,SOLR 非常快。

Asynchronous PHP calls?

【讨论】:

  • 这当然很有趣,但它根本没有解决连接重用问题。事实上,这只会使我的连接开销问题变得更糟。
【解决方案2】:

cURL PHP 文档 (curl_setopt) 说:

CURLOPT_FORBID_REUSE - TRUE 强制 显式关闭的连接 当它完成处理时,以及 不会被汇集以供重复使用。

所以:

  1. 是的,实际上它应该默认重用连接,只要您重用 cURL 句柄。
  2. 默认情况下,cURL 自己处理持久连接;如果您需要一些特殊的标头,请检查 CURLOPT_HTTPHEADER
  3. 服务器可能会发送一个保持活动超时(默认 Apache 安装,它是 15 秒或 100 个请求,以先到者为准) - 但当这种情况发生时,cURL 只会打开另一个连接。

【讨论】:

  • 太棒了!我非常接近发布我的第一个 stackoverflow 问题。这个解决方案适用于我们的中间件,前提是我们添加了请求标头“连接:关闭”。
【解决方案3】:
  1. 在您访问的服务器上必须启用保活,并且最大保活请求应该是合理的。如果是 Apache,请参阅apache docs

  2. 您必须重复使用相同的 cURL 上下文。

  3. 在配置 cURL 上下文时,在 header 中启用 keep-alive with timeout:

    curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array(
        'Connection: Keep-Alive',
        'Keep-Alive: 300'
    ));
    

【讨论】:

  • 弗兰克,我刚刚重新测试了我的代码,它看起来默认是打开的。不过,明确设置它并没有什么坏处。
  • @OlegBarshay 你知道我们是否需要删除curl_close($curlHandle); 以保持连接。 ?
  • @zeflex 是的,你必须删除它,如果你调用curl_close 连接将被关闭
  • 如果服务器断开连接,curl_exec 是否会创建一个新连接并再次设置句柄,即使保持活动仍处于活动状态?
【解决方案4】:

Curl 默认发送 keep-alive 头,但是:

  1. 使用不带任何参数的curl_init() 创建上下文。
  2. 将上下文存储在可以继续存在的范围内(不是本地变量)
  3. 使用CURLOPT_URL 选项将url 传递给上下文
  4. 使用curl_exec()执行请求
  5. 不要关闭与curl_close()的连接

非常基本的例子:

function get($url) {
    global $context;
    curl_setopt($context, CURLOPT_URL, $url);
    return curl_exec($context);
}

$context = curl_init();
//multiple calls to get() here
curl_close($context);

【讨论】:

  • 您还需要在第二次调用之前设置cookie,例如:curl_setopt($context, CURLOPT_COOKIE, 'name=value'); 例如我的请求是curl_setopt($context, CURLOPT_COOKIE, 'PHPSESSID=bl392rgi8q664l7faat33hfta4');
猜你喜欢
  • 2011-02-03
  • 2014-01-04
  • 2012-12-24
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 2012-03-09
相关资源
最近更新 更多