/ ghost

Clustering Ghost

Following from my post about running Ghost as an npm module, I decided to see if I could run Ghost using cluster. As you are probably aware, Node.js runs as a single asynchronous thread. While this works extremely well in most cases, sometimes you just run out of cpu power from a single core. Cluster changes that, it runs multiple instances of your node application and load balances between them. It is extremely simple to use.

While I was think about this, I decided to run some load tests to see how much of an improvement it would be. The standard Ghost setup, a single instance of Ghost with MySQL was able to handle about 50 req/s. I was able to load test with up to 1000 simultaneous connections using blitz.io(gives me a credit if you sign up). Ghost performed pretty consistently with the 50 res/s. Personally, I find that to be a bit too slow but, I'm willing to accept that considering how great Ghost is for writing.

To setup cluster, you'll need to be running MySQL. SQLite is not thread safe in some functions so I think its better to be safe and simply not try this with SQLite. You also need to be running Ghost as an npm module. Once you have all of that setup, it actually really simple. All you need to do is modify your app.js file to match:

{% highlight javascript %}

"use strict";

/**

  • Module dependencies.

    */

var ghost = require('ghost');

var path = require('path');

var cluster = require('cluster');

var numCPUs = require('os').cpus().length;

var environment = process.env.NODE_ENV;

var threads = process.env.NODE_ENV === 'production' ? numCPUs : 1;

if (cluster.isMaster) {

for (var i = 0; i < threads; i++) {

cluster.fork();

}

cluster.on('exit', function(worker, code, signal) {

console.log('worker ' + worker.process.pid + ' died. Restarting...');

cluster.fork();

});

} else {

ghost({

config: path.join(__dirname, 'config.js')

});

}

{% endhighlight %}

Thats it. When you start your Ghost site with npm start --prod, it will spawn a worker for each core. If you start it in development mode (i.e. npm start), it will only run a single worker.

After setting this up, I did another load test. This time around, I managed to get 110 res/s. I run this site on Mac Mini with dual core, hyper threading processor. Its not surprising that I only get a scaling factor of 2 since there are only 2 real cores.

For reference, I also ran the load test using SQLite. It managed 40 res/s, which isn't terrible.