sql连接错误太多:由于长轮询

时间:2014-01-24 08:21:20

标签: mysql long-polling

我设计了一个像Spoj和Codeforces一样的编码平台,用于在我的学院 LAN 上组织比赛。

我在那里使用了长轮询,因此管理员的所有通知都可以通过 JavaScript 警告消息向所有用户广播。当论坛上发布任何内容时,管理员也会收到通知。

但是只有16位用户(包括1名管理员)访问该网站,服务器停止显示too many sql connections。我重新启动了我的笔记本电脑(服务器),它持续了一段时间,然后再次下降;提供与以前相同的错误消息。

当我删除两个长轮询流程时,一切都顺利进行。

用于长轮询的

服务器端代码:

include 'dbconnect.php';

$old_ann_id = $_GET['old_ann_id']; 
$resultann = mysqli_query($con,"SELECT cmntid FROM announcements ORDER BY cmntid DESC       LIMIT 1");

while($rowann = mysqli_fetch_array($resultann)){
    $last_ann_id = $rowann['cmntid']; 
}

while($last_ann_id <= $old_ann_id){
    usleep(10000000);
    clearstatcache();

    $resultann = mysqli_query($con,"SELECT cmntid FROM announcements ORDER BY cmntid DESC LIMIT 1");
    while($rowann = mysqli_fetch_array($resultann)){
        $last_ann_id = $rowann['cmntid']; 
    }
}

$response = array();
$response['msg'] = 'new';
$response['old_ann_id'] = $last_ann_id;
$resultann = mysqli_query($con, "Select announcements from announcements where    cmntid = $last_ann_id");
while($rowann = mysqli_fetch_array($resultann)){
     $response['announcement'] = $rowann['announcements'];
}

echo json_encode($response);

1 个答案:

答案 0 :(得分:1)

定义了最大连接数。认为默认值为100或151个连接,具体取决于MySQL的版本。您可以在phpmyadmin中查看“服务器变量和设置”中的值(或直接执行 *显示变量,如“max_connections”; * )。

如果将其设置为非常低(例如10)并且您(例如)有15个用户,则您将快速达到极限。您为每个长轮询脚本提供了自己的连接,并且该连接可能处于打开状态,直到该长轮询脚本结束。您可以通过在每次检查数据库后断开脚本来减少此操作,然后在下次检查时重新连接(即,如果您的长轮询脚本每隔5秒检查一次数据库,那么您可能在5秒内完成4.5秒目前存在与数据库连接但未使用连接的地方

但是,您可以拥有更多的连接,但如果您为每个用户多次触发ajax轮询,则每个连接可能会有多个连接。对于javascript中的小错误,这可能很容易。

如果您使用持久连接,可能会更糟糕的是,在用户离开调用长轮询脚本的页面后,您可能会打开连接。

编辑 - 根据您的脚本进行更新。

注意我不确定你的dbconnect.php包含了什么。我可能很容易在include中调用一个connect / disconnect函数,但我只是把它放在这个示例代码中,就像使用mysqlu_close和mysqli_connect函数一样。

<?php
include 'dbconnect.php';
$old_ann_id = $_GET['old_ann_id']; 
$resultann = mysqli_query($con,"SELECT MAX(cmntid) FROM announcements");
if($rowann = mysqli_fetch_array($resultann))
{
    $last_ann_id = $rowann['cmntid']; 
}
$timeout = 0;
while($last_ann_id <=$old_ann_id and $timeout < 6)
{
    $timeout++;
    mysqli_close($con);
    usleep(10000000);
    clearstatcache();
    $con = mysqli_connect("myhost","myuser","mypassw","mybd");
    $resultann = mysqli_query($con,"SELECT MAX(cmntid) FROM announcements");
    if($rowann = mysqli_fetch_array($resultann))
    {
        $last_ann_id = $rowann['cmntid']; 
    }
}
if ($last_ann_id >$old_ann_id)
{
    $response = array();
    $response['msg'] = 'new';
    $response['old_ann_id'] = $last_ann_id;
    $resultann=mysqli_query($con,"SELECT cmntid, announcements FROM announcements WHERE    cmntid>$old_ann_id ORDER BY cmntid");
    while($rowann = mysqli_fetch_array($resultann))
    {
         $response['announcement'][]=$rowann['announcements'];
         $response['old_ann_id'] = $rowann['cmntid'];
    }
    mysqli_close($con);
    echo json_encode($response);
}
else
{
    echo "No annoucements - resubmit";
}
?>

我在主循环中添加了一个计数。但是,一旦执行了6次,它是否会在循环中退出。这样,即使有人离开页面,脚本也只会在之后的短时间内运行(最多一分钟)。你将不得不修改你的javascript来捕获它并重新提交ajax调用。

此外,我已将响应中的公告更改为数组。这样,如果在脚本运行时有多个通知,则所有通知都将被恢复。