Search code examples
node.jscassandraconnection-poolinglsofhelenus

Node.js lsof - many open DB connections


When I run "lsof | grep node" on my server (running a node.js app), I get about 1000+ lines (db connections to port 9160). Each line looks like this:

node      17006      root  160u     IPv4         1362100969       0t0        TCP localhost:47813->localhost:9160 (ESTABLISHED)

This is a test node.js server, doing something very simple. (logging the request to Cassandra DB with the Helenus module)

I was surprised that there were so many open connections, when there definitely should be no more than a 1-2 connections at this moment.

Does this mean that I am I not ending my DB connections properly in the Node app? My code is below. Thanks.

var express = require('express')
 , routes = require('./routes')
 , app = express.createServer();


        app.configure(function(){
                        app.use(express.bodyParser());
                        app.use(express.methodOverride());
                        app.use(app.router);
                        });

        process.on('uncaughtException', function (err) {
                        logger.error('Caught exception: ' + err);
                        });

        function respond_test(req, res, next) {
                        var q = JSON.parse(req.query.q);
                        insert_db(q);
                        res.send('OK');
       }

       function insert_db(q) {
    var helenus = require('helenus'),
            pool = new helenus.ConnectionPool({
                 hosts      : ['localhost:9160'],
                    keyspace   : 'Test',
                    timeout    : 3000
        });

    pool.on('error', function(err){
                logger.error(err.name, err.message);
    });

           //makes a connection to the pool, this will return once there is at least one
           //valid connection, other connections may still be pending
           pool.connect(function(err, keyspace){
                        if(err){   throw(err);    }

                       keyspace.get('Test', function(err, cf){
                                        if(err){    throw(err);     }
                                        cf.insert(Date.now(), q, function(err){
                                                if(err){  throw(err);   }
                                       });
                         });
             });
    pool.close();
        }

        app.get('/test', respond_test);
       app.listen(80);

Solution

  • You are effectively connecting and disconnecting from cassandra on every request. The pool is designed to hold the connections open for you so you don't have to open and close constantly. This will greatly increase your performance as creating and destroying connections are expensive. I refactored your code a bit to give you an idea of how it is supposed to be used. I added some comments in there to help you out:

    var express = require('express'),
        routes = require('./routes'),
        app = express.createServer(),
        //define cf in this scope to be set once connected
        test_cf;
    
    
    function respond_test(req, res, next) {
      var q = JSON.parse(req.query.q);
    
      test_cf.insert(Date.now(), q, function(err){
        if(err){
          res.send('ERROR');
          throw(err);
        } else {
         res.send('OK');
        }
      });
    }
    
    var helenus = require('helenus'),
        pool = new helenus.ConnectionPool({
          hosts      : ['localhost:9160'],
          keyspace   : 'Test',
          timeout    : 3000
        });
    
    app.configure(function(){
      app.use(express.bodyParser());
      app.use(express.methodOverride());
      app.use(app.router);
    });
    
    process.on('uncaughtException', function (err) {
      logger.error('Caught exception: ' + err);
    });
    
    pool.on('error', function(err){
      logger.error(err.name, err.message);
    });
    
    pool.connect(function(err, keyspace){
      if(err){
        throw(err);
      }
    
      keyspace.get('Test', function(err, cf){
        if(err){ throw(err); }
        test_cf = cf;
        //don't start listening until connected
        app.listen(80);
      });
    });
    
    app.on('close', function(){
      //close the pool if we stop listening on http
      pool.close();
    });
    
    app.get('/test', respond_test);