Socket.io 1.0.6,nodejs CPU超过100%

时间:2014-07-16 01:34:04

标签: node.js tcp websocket socket.io streaming

我正在创建一个管理实时数据订阅的Web服务器。这些数据通过TCP流式传输到nodejs,然后流式传输到使用Socket.io通过websockets订阅特定主题的客户端。

这是工作流程。

客户端针对特定主题发送订阅请求。 Nodejs应用程序将此订阅代理到java应用程序,然后该应用程序将开始通过TCP将数据推送到nodejs。 Java应用程序为每个可以收听的可能类别的新闻启动9个不同的套接字连接,每个插槽一个类别

值得一提的是,这些数据可能非常庞大,因为当客户订阅时,他们首先获取历史数据(最多45MB),并且每次后续推送都包含一小部分增量。

我遇到的问题是初始推送nodejs应用程序使用超过100%的CPU。最初我认为问题在于解析发送给我的数据。经过几天的调试后,我发现当评论socket.emit(data.topic, data)时,CPU下降到1% - 3%。这让我相信我遇到的问题是socket.io。

我在这里滥用socket.io吗?有没有可以推动不同主题/渠道的替代方案?我的代码中有什么问题吗?

感谢您的时间!

//needed for REST subscribe services
var app = require('express')()
    //needed for HTTP server
    , server = require('http').createServer(app) 
    //WebSocket library (TODO see how to implement this)
    //, sockjs = require('sockjs') 
    //backend subscriptions
    , subUtil = require('./subscriptions/subscriptionManager')
    , bodyParser = require('body-parser')
    //Using Socket.io for now
    , io = require('socket.io').listen(server)
    , config = require('./settings/config')
    , tcpServer = require('./servers/tcpServer')
    //logger
    , logger = require('./logging/logger');

//Parser used for parsing JSON out of HTTP body
app.use(bodyParser.json()); 
// error handlers
app.use(function(err, req, res, next){
  logger.log.error(err.stack);
  res.send(500, 'Something broke!');
});

app.post('/subscribe/worldnews', subUtil.subWorldNews);
app.post('/subscribe/sportnews', subUtil.subSoirtNews);
app.post('/subscribe/sciencenews', subUtil.subScienceNews);
app.post('/subscribe/townnews', subUtil.subTownNews);
app.post('/subscribe/countrynews', subUtil.subCountryNews); 
app.post('/subscribe/regionnews', subUtil.subRegionNews);
app.post('/subscribe/weathernews', subUtil.subWeatherNews);
app.post('/subscribe/hotnews', subUtil.subHotNews);
app.post('/subscribe/relatednews', subUtil.subRelatedNews);
app.post('/unsubscribe', subUtil.unsubscribe);

//Start tcp server
tcpServer.startServer();
//Set max number of listeners, 100 users can connect
tcpServer.setMaxListeners(100);
//Create Socket.IO connection
io.sockets.on('connection', function (socket) {

    //handling incoming backend data
    var incomingHandler = function(data) {
        //send data to the user
        socket.emit(data.topic, data);
    };
    //Data is comming from backend 
    tcpServer.on('incoming', incomingHandler);
    //CLient has disconnected
    socket.on('disconnect', function (discData) {
        logger.log.info('User has disconnected');
        //remove listener
        tcpServer.removeListener('incoming', incomingHandler);
        //unsubscribe all topics with this token
        subUtil.unsubscribeAll(token); 
    });
});
//HTTP server listening
server.listen(config.httpPort);
logger.log.info('TCP connection on port ' + config.tcpPort + '; HTTP connection on the port ' + config.httpPort);

/ ************* TCP服务器模块低于************************* /

//import utils because it is easier to do inheritance
var util = require('util')
    //import core events
    , EventEmitter = require('events').EventEmitter
    , config = require('../settings/config')
    //needed for TCP connection
    , net = require('net')
    , JsonSocket = require('json-socket')
    , logger = require('../logging/logger');

var TcpServer = function() {
        EventEmitter.call(this);
}

//inherit from events
util.inherits(TcpServer, EventEmitter);

TcpServer.prototype.startServer = function(incomingData) {
    //make a reference to postRequest function(important)
    var self = this;

    var tcpServer = net.createServer(function(sock) {
        logger.log.info('backend connected');
        //Handle socket error
        sock.on('error', function(err) {
                logger.log.error('There was a socket error :( \r\n' + err.stack);
        });

        sock.on('data', function(data) {
            logger.log.info('Incoming data');
            _onData(data, self)
        })
        var _contentLength = null;
        var _buffer = '';

        var _onData = function(data, ref) {
            data = data.toString();
            try {
                _handleData(data, ref);
            } catch (e) {
                logger.log.error(e);
            }
        }
        var _handleData = function(data, ref) {
            _buffer += data;
            if (_contentLength == null) {
                var i = _buffer.indexOf('#');
                //Check if the buffer has a #, if not, the end of the buffer string might be in the middle of a content length string
                if (i !== -1) {
                    var rawContentLength = _buffer.substring(0, i);
                    _contentLength = parseInt(rawContentLength);
                    if (isNaN(_contentLength)) {
                        _contentLength = null;
                        _buffer = '';
                        var err = new Error('Invalid content length supplied ('+rawContentLength+') in: '+ _buffer);
                        err.code = 'E_INVALID_CONTENT_LENGTH';
                        throw err;
                    }
                    _buffer = _buffer.substring(i+1);
                }
            }
            if (_contentLength != null) {
                if (_buffer.length == _contentLength) {
                    _handleMessage(_buffer, ref);
                } else if (_buffer.length > _contentLength) {
                    var message = _buffer.substring(0, _contentLength);
                    var rest = _buffer.substring(_contentLength);
                    _handleMessage(message, ref);
                    _onData(rest, ref);
                }
            }
        }

        var _handleMessage = function(data, ref) {
            _contentLength = null;
            _buffer = '';
            var message;
            try {
                message = JSON.parse(data);
            } catch (e) {
                var err = new Error('Could not parse JSON: '+e.message+'\nRequest data: '+data);
                err.code = 'E_INVALID_JSON';
                throw err;
            }
            message = message || {};
            ref.emit('incoming', message);
        }
    });

    //Handle server error
    tcpServer.on('error', function(err) {
        logger.log.error('There was a connection err \r\n' + err.stack);
    });
    //listen fot backend data on port
    tcpServer.listen(config.tcpPort);
}

module.exports = new TcpServer();

0 个答案:

没有答案