如何在GET / PHP5中限制每秒对服务器的连接数量?

时间:2011-03-27 02:26:45

标签: php api get

给定下面的脚本,该脚本以另一种语言提取单词并与服务器建立连接。

  

但是,有很多单独的字符串实体,其中一些返回为空值。 StackOverflow的研究员@Pekka正确评估了Google的局限性:定时结果。

问:如何以速度为代价,如何使连接更加强大/可靠?
Q2。如何逐步限制每秒与服务器建立的连接数量?

只要返回的值正确,我愿意牺牲速度,即使它会导致120秒的延迟。现在一切都在0.5秒内开始并完成,翻译中存在各种差距。几乎像荷兰奶酪(带孔),我想要奶酪没有孔,即使这意味着更长的等待时间。

正如你所看到的那样,我自己将脚本置于睡眠状态1/4秒的解决方案不能称为优雅...如何从这里开始?

    $url='http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=' . rawurlencode($string) . '&langpair=' . rawurlencode($from.'|'.$to);
    $response   = file_get_contents($url,
            null,
            stream_context_create(
            array(
            'http'=>array(
            'method'=>"GET",
            'header'=>"Referer: http://test.com/\r\n"
            )
            )
        ));
usleep(250000); # means 1/4 of second deliberate pauze
return self::cleanText($response);
}

3 个答案:

答案 0 :(得分:1)

你可以从较低的等待时间开始,只有在你没有得到回应时才增加它。这样的事情。

$delay = 0;
$i = 0;
$nStrings = count($strings);

while ($i < $nStrings) {
    $response = $this->getTranslation($strings[$i]);
    if ($response) {
        $i++;
        # save the response somewhere
    else {
        $delay += 1000;
        usleep($delay);
    }
}

答案 1 :(得分:1)

  

如何逐步限制每秒与服务器建立的连接数量?

这取决于。在理想的世界中,如果您期望任何级别的流量,您可能希望您的刮刀成为通过message or work queue与之通信的守护进程。在这种情况下,守护进程将能够严格控制每秒的请求并适当地限制事情。

听起来你实际上是根据用户请求进行直播。说实话,你目前的睡眠策略很好。当然,它是“粗糙”,但它很简单并且有效。当您可能有多个用户同时发出请求时会出现问题,在这种情况下,这两个请求将不知道另一个请求,并且每秒最终会有比服务允许的更多请求。< / p>

这里有一些策略。如果URL永远不会更改,即您只限制单个服务,则基本上需要semaphore来协调多个脚本。

考虑使用简单的锁定文件。或者,更确切地说,锁定文件上的文件锁定:

// Open our lock file for reading and writing; 
// create it if it doesn't exist, 
// don't truncate, 
// don't relocate the file pointer.
$fh = fopen('./lock.file', 'c+');
foreach($list_of_requests as $request_or_whatever) {
// At the top of the loop, establish the lock.
    $ok = flock($fh, LOCK_EX):
    if(!$ok) {
        echo "Wow, the lock failed, that shouldn't ever happen.";
        break; // Exit the loop.
    }
// Insert the actual request *and* sleep code here.
    $foo->getTranslation(...);
// Once the request is made and we've slept, release the lock
// to allow another process that might be waiting for the lock
// to grab it and run.
   flock($fh, LOCK_UN);
}
fclose($fh);

这在大多数情况下都能正常使用。如果您使用的是超低成本或低质量的共享主机,由于底层文件系统(不能)的工作方式,锁可能会适得其反。 flock is also a bit finicky on Windows

如果您要处理多项服务,事情会变得更加棘手。我的第一直觉是在数据库中创建一个表,并开始跟踪每个请求,如果在过去的Z秒内对域Y进行了多次X请求,则添加额外的限制。

  

Q1。如何以速度为代价,如何使连接更加强大/可靠?

如果您坚持使用Google翻译,则可能需要switch to the Translate v2 RESTful API。这需要一个API密钥,但注册过程将强制您通过他们的服务条款,这应该记录他们的请求/期间最大限制。通过这种方式,您可以将系统限制请求到他们的服务支持的任何速率,并保持可靠性。

答案 2 :(得分:1)

以下是我在my CURL wrapper上使用的代码片段,延迟呈指数增长 - 这是一件好事,否则您可能最终只是强调服务器并且永远不会得到积极响应:

function CURL($url)
{
    $result = false;

    if (extension_loaded('curl'))
    {
        $curl = curl_init($url);

        if (is_resource($curl))
        {
            curl_setopt($curl, CURLOPT_FAILONERROR, true);
            curl_setopt($curl, CURLOPT_AUTOREFERER, true);
            curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

            for ($i = 1; $i <= 8; ++$i)
            {
                $result = curl_exec($curl);

                if (($i == 8) || ($result !== false))
                {
                    break;
                }

                usleep(pow(2, $i - 2) * 1000000);
            }

            curl_close($curl);
        }
    }

    return $result;
}

这里的$ i变量的最大值为8,这意味着该函数将尝试总共获取URL 8次,相应的延迟分别为0.5,1,2,4,8,16,32和64秒(或总计127.5秒)。

对于并发进程,我建议使用APC或类似设置共享内存变量。

希望它有所帮助!