ДОЛГИЙ ОПРОС (в php) начинает зависать после 5 запросов к БД

Я разрабатываю сайт живого аукциона с системой ставок в реальном времени. Я использую ДЛИТЕЛЬНЫЙ ОПРОС, когда пользователь делает ставку на товар. Я выбрал длинный опрос, потому что WebSockets еще не очень хорошо поддерживаются, а NODEJS мне сложно реализовать прямо сейчас. Итак, я застрял в этом простом длинном опросе ajax, который отлично работает примерно для пяти ставок.

Итак, проблема в том, что торги отлично работают для ставок на 5-6 товаров с интервалом в 1 секунду (я получаю мгновенный ответ от server-ajax), но 7-й (щелчок) на кнопке ставки этот ответ - длинный опрос зависает примерно на 16-22 секунды и затем завершает запрос. В конце все обновляется в базе данных и завершается, но после каждых 5-6 заявок ответ/вызов ajax зависает примерно на 16-22 секунды.

Как я могу сократить это время, чтобы все шло гладко независимо от того, сколько раз пользователи делают ставки, без задержек...

Я использую Apache/PHP/MySql на локальном хосте/wamp

Мой код: index.php

<script type="text/javascript" charset="utf-8">             
var old_timestamp = <?php echo $old_timestamp;?>; //here i'm echoing last timestamp of         auction

function waitForMsg(){
jq.ajax({
type: "POST",
url: "http://localhost/bid/comet/poll.php",
data: {"old_timestamp" : old_timestamp},
async: true,
cache: false,

success: function(data){
var json = eval('(' + data + ')');
if(json['msg'] != "") {
jq('#comet_display').html(json['msg']); //here I show ID of which auction item was bidded
}
old_timestamp = json['old_timestamp']; 
setTimeout('waitForMsg()',100);
},
error: function(XMLHttpRequest, textStatus, errorThrown){

setTimeout('waitForMsg()',1000);
}
});
}

jq(window).load(function(){ 
waitForMsg();
jq("#a_loader").show();
    var url = "http://localhost/bid/auctions-ajax"; // the script where you handle the form input.  
    jq.ajax({
           type: "POST",
           url: url,
           data: {au978 : true}, 
           async:false, //to sem dodal za časovni zamik
           success: function(data)
           {
             jq("#a_loader").hide();  
             jq("#show-category").html(data); // show response from the php script.              
           },
            error: function(result) {
                jq("#show-category").html("Sorry, something went wrong. Please try again later.");
            }
    });

});

function bid(id){

var url = "http://localhost/bid/comet/update-auction.php"; // the script where you handle the form input.
var user_id=<?php echo $user_id;?>; //user id from session
jq.ajax({
    type: "POST",
    url: url,
    data: {"auct_id" : id, "user_id" : user_id}, // serializes the form's elements.
    success: function(data)
    {
        //it updates in user table its remaining number of bids 
    },
    error: function(XMLHttpRequest, textStatus, errorThrown){
        alert("Something went wrong. Click OK to refresh.");

    }
});
}

</script>

poll.php

<?php

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
require_once($_SERVER['DOCUMENT_ROOT'] . 'bid/include/DEFINES.php');
require_once(CLASS_AUCTION);
require_once(CLASS_DB);

$a=new Auction();

$old_timestamp = $_POST['old_timestamp']; 
$bidded_id=0;
$db=DB::getInstance();  
$sql="SELECT timestamp, id FROM auction ORDER BY timestamp DESC LIMIT 1";   //desno doda tabelo kategorija  
$stmt=$db->db->prepare($sql) or die("Prepare Error");   
$stmt->execute();   
$result2=$stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($result2 as $rez){
    $current_timestamp=$rez['timestamp'];   
    $bidded_id=$rez['id'];
}
$stmt->closeCursor();


    while($current_timestamp <= $old_timestamp){
    usleep(1000);
    clearstatcache();
    $db=DB::getInstance();  
    $sql="SELECT timestamp, id FROM auction ORDER BY timestamp DESC LIMIT 1";       
    $stmt=$db->db->prepare($sql) or die("Prepare Error");   
    $stmt->execute();   
    $result=$stmt->fetchAll(PDO::FETCH_ASSOC);
    foreach ($result as $rez){
        $current_timestamp=$rez['timestamp'];   
        $bidded_id=$rez['id'];
    }
    $stmt->closeCursor();

}
$response = array();
$response['msg'] = 'BID na avkciji: '.$bidded_id;
$response['old_timestamp'] = $current_timestamp;
echo json_encode($response);
 }else{
require_once($_SERVER['DOCUMENT_ROOT'] . 'bid/errors/404.html');
 }
?>

и файл update-auction.php

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
require_once($_SERVER['DOCUMENT_ROOT'] . 'bid/include/DEFINES.php');
require_once(CLASS_AUCTION);
require_once(CLASS_USER);
require_once(CLASS_DB);
$u=new User(); 
$a=new Auction();
$auction_id=$_POST['auct_id'];
$user_id=$_POST['user_id'];
$date = new DateTime();
$timestamp=$date->getTimestamp();
$a->updateAuction($auction_id,$user_id,$timestamp/*,$bid_price,$bids_spent,$total_paid*/);
$u->updateUserBids($user_id);

}else{
require_once($_SERVER['DOCUMENT_ROOT'] . 'bid/errors/404.html');
}
?>

Спасибо за внимание к моей проблеме!


person Matjaž Železnik    schedule 23.03.2013    source источник


Ответы (2)


Подумайте о переходе на WebSockets. Он был разработан, чтобы исправить проблему с длинным опросом.

person beardedlinuxgeek    schedule 23.03.2013
comment
Но будет быстрее? Потому что я думаю, что у меня может быть проблема с базой данных... Потому что все делается, после 5 ставок требуется около 20 секунд. Разве это не то же самое в веб-сокетах? - person Matjaž Železnik; 24.03.2013
comment
А также проблема с кроссбраузерной совместимостью. Только cca. 60% браузеров поддерживают веб-сокеты... поддержка веб-сокетов - person Matjaž Železnik; 24.03.2013
comment
Разве это не должно быть комментарием? - person Buhake Sindi; 27.07.2013

Хорошо, я нашел решение, которое устраняет проблему ОТСТАВАНИЯ на 17-22 секунды. Теперь это почти мгновенно, независимо от того, сколько раз вы нажимаете. Но я все еще не уверен, что это лучшее решение для длительного опроса.

Выкладываю, вдруг у кого такая же проблема.

Я изменил функцию ДЛИТЕЛЬНЫЙ ОПРОС в файле poll.php на это:

<?php

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
require_once($_SERVER['DOCUMENT_ROOT'] . 'bid/include/DEFINES.php');
require_once(CLASS_AUCTION);
require_once(CLASS_DB);

$a=new Auction();
$db=DB::getInstance();  
$sql="SELECT timestamp, id, last_username FROM auction ORDER BY timestamp DESC LIMIT 1";        
$response = array();
while(1)
{
    $stmt=$db->db->prepare($sql) or die("Prepare Error");   
    $stmt->execute();   
    $result=$stmt->fetch(PDO::FETCH_ASSOC);
    if (!empty($result)){
        $current_timestamp=$result['timestamp'];        
        $response['msg'] = 'New BID';
        $response['old_timestamp'] = $current_timestamp;
        echo json_encode($response);
        break;
    }   
    sleep(3000);
    clearstatcache();
}
}else{
require_once($_SERVER['DOCUMENT_ROOT'] . 'bid/errors/404.html');
}
?>

и теперь я опрашиваю свой index.php следующим образом:

<?php
$db=DB::getInstance();  
$sql="SELECT timestamp FROM auction ORDER BY timestamp DESC LIMIT 1";    
$stmt=$db->db->prepare($sql) or die("Prepare Error");   
$stmt->execute();   
$result2=$stmt->fetch(PDO::FETCH_ASSOC);
$old_id=0;
$last_timestamp=$result2['timestamp'];
?>
<script type="text/javascript" charset="utf-8">             
var last_timestamp = <?php echo $last_timestamp;?>;
var old_timestamp=0;

function waitForMsg(){
jq.ajax({
type: "POST",
url: "http://localhost/bid/comet/poll.php",
async: true,
cache: false,

success: function(data){
var json = eval('(' + data + ')');
if(old_timestamp==0 || last_timestamp==old_timestamp){

}else{
    if(json['msg'] != "") {
    jq('#comet_display').html(json['msg']);
}
}
old_timestamp = json['old_timestamp']; 

setTimeout('waitForMsg()',500);
},
error: function(XMLHttpRequest, textStatus, errorThrown){

setTimeout('waitForMsg()',1000);
}
});
}

jq(window).load(function(){ 
waitForMsg();

});
function bid(id){   
var url = "http://localhost/bid/comet/update-auction.php"; //here I update auction and user's bids
var user_id=<?php echo json_encode($user_id);?>;
var user_name=<?php echo json_encode($user_name); ?>;
jq.ajax({
    type: "POST",
    async: true,
    cache: false,
    url: url,
    data: {"auct_id" : id, "user_id" : user_id, "username" : user_name}, // serializes the form's elements.
    success: function(data)
    {

        setTimeout('waitForMsg()',100);
        var cnt = parseInt(jq(".db_bids").text());
        if (!isNaN(cnt))
        {
            cnt--;
            jq(".db_bids").text(String(cnt));
        }    
    },
    error: function(XMLHttpRequest, textStatus, errorThrown){
        alert("Something went wrong. Click OK to refresh.");

    }
});
}
</script>

Я все еще разрабатываю это на локальном хосте и посмотрю, как это будет вести себя на реальном сервере с более чем 100 пользователями. Если у кого-то есть лучшее и быстрое решение с ДЛИТЕЛЬНЫМ ОПРОСОМ из баз данных, дайте мне знать :)

person Matjaž Železnik    schedule 24.03.2013
comment
Вы тестировали его на большем количестве клиентов? - person Ateev Chopra; 22.04.2014