我设计了一个像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);
答案 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调用。
此外,我已将响应中的公告更改为数组。这样,如果在脚本运行时有多个通知,则所有通知都将被恢复。