服务器因 Ajax 次调用而饱和

Server saturation with Ajax calls

我在 Windows Server 2008 上使用 PHP over IIS 7.5。

我的 Web 应用程序在后台重复请求 Ajax 3 个不同的 JSON 页面:

他们检索与某些表的当前状态相关的数据。这样我就可以保持视图更新。

通常我对此没有太大问题,但最近我发现我的服务器充满了数百个未答复的请求,我认为问题可能是由于其中一个请求的延迟造成的。

如果每 6 秒请求一次的 page1 需要 45 秒才能响应(由于数据库查询速度慢或其他原因),那么在我看来,请求开始一个接一个地堆积起来。 如果我有多个用户同时连接到 Web 应用程序(或使用多个选项卡),事情可能会变得糟糕。

关于如何避免此类问题有什么建议吗?

我正在考虑使用诸如 ZMQ together with Sockets.io in the client side 之类的东西,但由于我请求的数据不会因任何用户操作而被触发,所以我不知道如何从服务器端。

I was thinking about using some thing such as ZMQ together with Sockets.io in the client side...

这几乎绝对是长 运行 请求的最佳选择。

...but as the data I'm requesting doesn't get fired from any user action, I don't see how this could be triggered from the server side.

在这种情况下,有问题的 'user action' 正在连接到 socket.io 服务器。这个缩减示例取自 socket.io getting started 文档之一:

var io = require('socket.io')(http);

io.on('connection', function(socket) {
  console.log('a user connected');
});

当触发 'connection' 事件时,您可以开始侦听 ZMQ 消息队列中的消息。如有必要,您还可以启动 long-运行 查询。

这是一个非常糟糕的设置。如果可能,您应该始终避免轮询。不是每 6 秒从客户端向服务器发送一次请求,而是从服务器向客户端发送数据。您应该在服务器端检查数据是否有任何变化,然后使用 websockets 将数据传输到客户端。您可以在服务器端使用nodejs来监控数据的任何变化。

我最终按照@epascarello 的建议解决了这个问题,如果我在 X 时间内没有得到回应,我会稍微改进它。

If the request has not come back, do not send another. But fix the serverside code and speed it up.

基本上我做了类似下面的事情:

var ELAPSED_TIME_LIMIT = 5; //5 minutes
var responseAnswered = true;
var prevTime = new Date().getTime();

setInterval(function(){
    //if it was answered or more than X m inutes passed since the last call
    if(responseAnsswered &&  elapsedTime() > ELAPSED_TIME_LIMIT){
        getData()
        updateElapsedTime();
    }
}, 6000);

function getData(){
    responseAnswered = false;
    $.post("http://whatever.com/action.json", function(result){
        responseAnswered = true
    });
}

//Returns the elapsed time since the last time prevTime was update for the given element.
function elapsedTime(){
    var curTime = new Date().getTime();

    //time difference between the last scroll and the current one
    var timeDiff = curTime - prevTime;

    //time in minutes
    return (timeDiff / 1000) / 60;
}

//updates the prevTime with the current time
function updateElapsedTime(){
    prevTime = new Date().getTime();
}