【问题标题】:Too many sql connections error : due to long polling太多 sql 连接错误:由于长轮询
【发布时间】:2014-01-24 08:21:20
【问题描述】:

我已经设计了一个类似于 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);

【问题讨论】:

  • 你设置的最大连接数是多少?如果您进行长轮询的并发用户数接近该数量,那么您可能会用完连接,并且最好在轮询之间断开与数据库的连接。另一方面,您可能会遇到为每个用户触发多个轮询脚本的问题,每个用户都有一个连接。
  • @Kickstart:我应该怎么做才能克服这个问题。允许的最大连接数应该是多少?对于第二种情况,即克服“触发多个轮询脚本......”该怎么办?我对此完全陌生。请解释

标签: mysql long-polling


【解决方案1】:

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

如果将其设置为非常低的值(例如 10)并且您有(例如)15 个用户,您将很快达到限制。您为每个长轮询脚本提供了自己的连接,并且该连接可能处于打开状态,直到该长轮询脚本结束。您可以通过在每次检查数据库后让脚本断开连接,然后在下次检查时重新连接来减少这种情况(即,如果您的长轮询脚本每 5 秒检查一次数据库,那么您可能有超过 4.5 秒的 5 秒当前存在与数据库的连接但未使用该连接的位置)

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

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

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

请注意,我不确定您的 dbconnect.php 包含在做什么。我可能可以轻松地调用该包含中的连接/断开连接函数,但我只是将它放在这个示例代码中,因为它使用了 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 调用。

我还将响应中的公告更改为数组。这样,如果在脚本运行时有多个公告,则会全部恢复。

【讨论】:

  • 我明白了你所说的......我已经在编辑中发布了我的长轮询代码。当使用另一个 php/javascript 代码通过 ajax 以 10 秒的 settimeout 发布新评论时,再次调用此代码。你能帮我修改代码吗?我对这个概念完全陌生
  • 我的 max_connections 默认设置为 151 我应该设置多少才能顺利连接。
  • 抱歉耽搁了。如果没有添加 cmets,则查看您的代码是一个永无止境的脚本。它可能需要几个小时才能完成,并且每次刷新页面时,您都可能触发该脚本运行的另一次事件。我在上面粘贴了一些更改。
  • 我得到了关闭连接的东西。但是您提到的while循环的超时计数器将在1分钟后中断,但是如果其他通知会在1分钟后发生,那么我将如何获得它。我力求重新提交的东西。请说明何时重新提交以及如何重新提交以及何时不重新提交。 # dbconnect.php 只包含与我的 sql 的连接
  • 在调用 ajax 脚本的 javascript 中,您期望得到响应。目前,当您收到回复时,它是您输出的新公告。我假设您然后再次调用 ajax 请求以获取下一个公告。使用更新后的脚本,您只需要识别它何时返回而没有数据,然后再次执行 ajax 请求,此时无需输出任何新公告。
猜你喜欢
  • 2018-10-30
  • 2013-09-24
  • 2014-01-22
  • 2021-11-19
  • 1970-01-01
  • 2010-11-15
  • 2017-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多