单节点js服务器来回答一堆网站

时间:2015-01-06 17:38:28

标签: node.js

我创建了以下代码来回答大约10个站点及其上的多个功能 问题是,如果网站有超过50个用户在线,同时CPU使用率将达到100%并崩溃服务器 能不能给我任何解决方案吗?

var app = require('http').createServer()
var io = require('socket.io')(app);
var fs = require('fs');
var moment = require('moment')();
moment .zone("+-8:00");
//moment.date() dat of month
//moment.month() dat of month


var mysql = require('mysql');
var connection;
// MYSQL CONFIG
connection = mysql.createConnection({
    host: '',
    user: '',
    password: '@@',
    database: 'nodejs'
});

// listen port 8084
// please open this port on firewall and iptables
app.listen(8084);
var xsocket = io.listen(app);
console.log('Listen On Port 8084  ' + connection);
var dblists = [];
var users = {};
var domains_tmp;

// get db list
connection.query('SELECT db_name, domain_name  FROM tbl_dblist order by id asc ;', function (err, rows, fields) {
    //  console.log('Connection result error ' + err);
    //  console.log('no of records is ' + rows.length);
    // send data to all servers
    var count = -1;
    rows.forEach(function (entry) {
        count++;
        dblists[entry["domain_name"]] = {
            dbname: entry["db_name"], cn: mysql.createConnection({
                host: '',
                user: '',
                password: '',
                database: entry["db_name"]
            })
        };
    })
    // console.log("DBLIST : ", dblists);
});

// handle request from clients
function handler(conn,conn_id) {

    if(!conn.connected)
        return;
    var i = String(users[conn_id].domain);
    // when db for domain not defined

    try {
        if (i.length <= 0 || i == "undefined")
            return;
        if (dblists[i].dbname.length == 0) {
            return;
        }
        dblists[i].cn.query('SELECT max(id) as id  FROM tbl_transaction  ;', function (err, maxrow, fields) {
            // send data to Connected Client
            if (maxrow.length > 0) {
                //console.log("length ",maxrow.length);
                if (maxrow[0].id > users[conn_id].maxrows) {
                    var last_id1 = maxrow[0].id;
                    var last_id = users[conn_id].maxrows;
                    // get last 20 record from table
                    dblists[i].cn.query('SELECT tbl_user.username as who, tbl_transaction.amount,tbl_transaction.date,tbl_transaction.note  FROM '+
                    'tbl_transaction inner join tbl_user on tbl_user.user_id = tbl_transaction.user_id '+
                    '  where tbl_transaction.id > ' + last_id + ' and tbl_transaction.id <=' + last_id1 + ' order by tbl_transaction.id desc limit 20;', function (err, rows, fields) {
                        //  console.log('Connection result error ' + err);
                        //console.log('no of records is ' + rows.length);

                        if(!conn.connected)
                            return;
                        // send data to Connected Client
                        conn.emit("alert", rows);
                        // console.log(rows);
                    });
                    users[conn_id].maxrows = maxrow[0].id;
                }
            }
        });


        // repeat data fetching every 0.5 seconds
        setTimeout(function () {
                handler(conn,conn_id);
            }
            , 1000);
    }
    catch (ex) {

    }
    finally {

    }

}

function mktime() {

    var d = new Date(),
        r = arguments,
        i = 0,
        e = ['Hours', 'Minutes', 'Seconds', 'Month', 'Date', 'FullYear'];

    for (i = 0; i < e.length; i++) {
        if (typeof r[i] === 'undefined') {
            r[i] = d['get' + e[i]]();
            r[i] += (i === 3); // +1 to fix JS months.
        } else {
            r[i] = parseInt(r[i], 10);
            if (isNaN(r[i])) {
                return false;
            }
        }
    }

    // Map years 0-69 to 2000-2069 and years 70-100 to 1970-2000.
    r[5] += (r[5] >= 0 ? (r[5] <= 69 ? 2e3 : (r[5] <= 100 ? 1900 : 0)) : 0);

    // Set year, month (-1 to fix JS months), and date.
    // !This must come before the call to setHours!
    d.setFullYear(r[5], r[3] - 1, r[4]);

    // Set hours, minutes, and seconds.
    d.setHours(r[0], r[1], r[2]);

    // Divide milliseconds by 1000 to return seconds and drop decimal.
    // Add 1 second if negative or it'll be off from PHP by 1 second.
    return (d.getTime() / 1e3 >> 0) - (d.getTime() < 0);
}
var i=1654;
function onlineu(socks,connection_online) {
    // die function when the client disconnected
    if (!socks.connected)
        return;
    var return_data = {played:0,total:0,players:0,today:0};

    dblists[connection_online].cn.query('Select sum(playnum) as cnt,sum(amount) as mnt from tbl_user  ;', function (err, rows, fields) {
        if (rows.length > 0) {
            console.log("Rows :", rows[0].cnt, rows[0].mnt);
            return_data.played = rows[0].cnt;
            return_data.total = rows[0].mnt;
        }
    });

    dblists[connection_online].cn.query('select count(user_id) as players from tbl_user  ;', function (err, rows, fields) {
        if (rows.length > 0) {
            console.log("Rows :", rows[0].players);
            return_data.players = rows[0].players;
        }
    });
    var d=moment.date();
    var m=moment.month()+1;
    var  begin=mktime(0,0,0, m, d );
    var end=mktime(23,59,59,m,d);

    dblists[connection_online].cn.query('Select count(id) as cnt,sum(amount) as today from tbl_transaction where date between '+ begin+' and '+ end+'  ;', function (err, rows, fields) {
        if (rows.length > 0) {
            console.log("Rows :", rows[0].today);
            return_data.today = rows[0].today;
        }
    });

    // die function when the client disconnected
    if (!socks.connected)
        return;

    //console.log("online Users", return_data);
    socks.emit("online", return_data);

    setTimeout(function () {
        onlineu(socks,domains_tmp);
    }, 1000);
}
// waiting for client html/js loaded
xsocket.set('authorization', function (handshakeData, callback) {
    query = handshakeData._query;
    if (query.domain == undefined || query.domain.length == 0) {
        console.log("No Domain Specified, Return False");
        return false;
    }
    domains_tmp = query.domain;
    callback(null, true);
});


xsocket.on('connection', function (conn) {
    console.log("New Client : " + conn.id);
    console.log("New Client Domain : " + domains_tmp);
    // Register Client Domain
    users[conn.id] = {id: conn.id, domain: domains_tmp, maxrows: 0};

    onlineu(conn,domains_tmp);
    handler(conn, conn.id);

    conn.on('disconnect', function (conn) {
        // Do Some Thing
    });
});


// end

由于

1 个答案:

答案 0 :(得分:0)

建议的选项

如果要在单个IP /服务器后面运行多个node.js应用程序,最好的办法是使用nginx,varnish,ha-proxy等服务器来反向代理对应用程序的请求。 Nginx在此角色中运行良好,也可用于缓存,SSL终止,spdy,pagespeed和其他增强功能。最近的nginx版本支持websockets。


关于您的申请

你有几个问题......

  • 您的数据库连接没有合并,看起来您没有将它们关闭。
    • 您应该在运行查询时从池中请求实例,并在
    • 之后释放它
  • 除了定时连接之外,您还在为每个连接客户端运行多个请求。
  • 您没有利用socket.io提供的内置命名空间和通道。

立即建议......

  • 您应该使用connection pooling进行数据库连接
  • 您应该抽象出您的数据访问权限,您可能需要考虑以下内容:
  • 您应该为普遍需要的数据实现缓存方案(可以是本地/内存,然后是缓存服务,然后是数据库查找)
  • 您应该使用socket.io名称空间/房间将邮件联合到其他连接的用户。
    • 对于多进程/服务器设置,您需要通过redis适配器或类似方式联合消息。

支持小型可测试模块和功能范例:

  • 破解代码会使测试更容易。
  • 抽象代码层使合成更容易
  • 在类/ oo层次结构上支持普通对象和组合

注意:这确实是一个大杂烩的建议,因为你的问题非常广泛,而且方法相当草率......一般将你的逻辑分解为可用于的功能模块对物体采取行动。从这里,您可以更好地测试和撰写应用程序。