You are on page 1of 30

SCALING

NODE.JS
APPLICATIONS WITH

REDIS, RABBITMQ & COTE.JS


Armagan Amcalar
JSIST 2014, Istanbul
Sep 27th, 2014

WHO AM I?
Armagan Amcalar
Co-founder, Chief Software Architect
Startup Kitchen
dashersw

AUTHORED ON GITHUB

HOBBY PROJECTS

pedalboard.js

pedals.io

tartJS

trax.io

geneJS
cote
semaver
jira-bot

NODE.JS
We love it.
We develop all kinds of software with it.
We love to daemonize it.

THE PROBLEM
It doesn't scale well.

Programming model encourages stateful app design
Works great as single process
Works OK as a cluster

WHAT'S NEXT?
What if you need more computing power?
How about horizontal scalability?

CURRENT SOLUTION
REVERSE PROXY
NGINX
NODE-HTTP-PROXY

NGINX

NODE-HTTP-PROXY

Easy to set up if you're familiar


with nginx

Hard to set up even if you're


familiar

Hard to maintain

Hard to maintain

Yet another technology


dependency

Very low level

WE NEED A DIFFERENT SOLUTION.


Because we have more problems
We're not just building express apps
We were programming the DOM, we need that flexibility

MORE PROBLEMS?
Be fast with your API response
Asynchronous processing (e.g., analytics)
You may need to scale very dynamically
Fault tolerance
THE YEAR'S 2014, WHERE ARE THE EVENTS?

LET'S TAKE A BREAK.


MONOLITHIC APPS
VS
SERVICE ORIENTED ARCHITECTURE & MICROSERVICES

MONOLITHIC APPLICATIONS
Single code base
One process to rule them all
A bug anywhere crashes the whole system
May consume lots of stale resources
Hard to scale; needs even more stale resources
Requestresponse flow is one huge piece

Easy to manage

MICROSERVICES
Separate code base
Multi processes for each service
A bug in a service crashes only that service
Consumes minimal resources
Scales well, needs minimal additional resources
Supports event-driven architecture
Requestresponse flow breakdown

Hard to manage

EVENT-DRIVEN ARCHITECTURE
PUB-SUB PATTERN
OBSERVER PATTERN

PUB-SUB PATTERN
Just like DOM events, what we're used to build.
Instead of click events, you have custom events (e.g. in jQuery)
Instead of DOM element interaction, you have daemon
interaction

OBSERVER PATTERN
First-of-its-kind event driven pattern
You
an object property, not an arbitrary event
Like all your click handlers have to have the same name
Limits possibilities

ENTER REDIS
Originally a NoSQL database
Key-value pair server with lots of great features like sets, etc.

Pub-sub capability
Supports events based on channels and patterns
Very cool node.js library

A REDIS PUBSUB-BASED ARCHITECTURE


d2

session storage

notifies of foo

d1
client request

publishes foo

redis

notifies of foo

notifies of foo

d4
logs

d3
API

EXAMPLE
Client
var redis = require('redis'),
client = redis.createClient(6379, '127.0.0.1');
client.publish('request', JSON.stringify({
body: 'some cool request'
}));

Logger
var redis = require('redis'),
logger = redis.createClient(6379, '127.0.0.1');
logger.subscribe('request');
logger.on('message', function(channel, message) {
if (channel == 'request')
console.log(JSON.parse(message));
});

QUICK DEMO

ENTER RABBITMQ
A message broker for distributed applications
Like redis pubsub, with heavy focus on additional features
such as
flexible message routing

work queues, topics, etc.
QoS management
round robin load balancing
message acks
rate limiting

unfriendly node.js library

WORK QUEUES

REMOTE PROCEDURE CALLS

EXAMPLE WORK QUEUE


var amqp = require('amqp'),
connection = amqp.createConnection(),
workId = 0;
connection.on('ready', function() {
connection.queue('work_queue', {autoDelete: false, durable: true}, function(queue) {
setInterval(function() {
connection.publish('work_queue', 'message #' + ++workId, { deliveryMode: 2 });
console.log('sent message #' + workId);
}, 1000);
});
});

var amqp = require('amqp'),


connection = amqp.createConnection();
connection.on('ready', function () {
connection.queue('work_queue', {autoDelete: false, durable: true}, function(queue) {
queue.subscribe({ack: true, prefetchCount: 1}, function(msg) {
var body = msg.data.toString('utf-8');
console.log("received", body);
queue.shift(); // basic_ack equivalent
});
});
});

QUICK DEMO

ENTER COTE.JS
node.js framework for fault tolerant, distributed apps
developed at Startup Kitchen
partially funded by TUBITAK

COTE.JS FEATURES
auto-discovery
mesh network, peer-to-peer communication
pubsub pattern
requester/responder pattern
client-side communication with websockets
load balancing with different strategies
daemon monitor

EXAMPLE ARCHITECTURE

EXAMPLE PUB-SUB IMPLEMENTATION


var Publisher = require('cote').Publisher,
publisher = new Publisher({
name: 'publisher',
broadcasts: ['update']
}),
workId = 0;
publisher.on('ready', function() {
setInterval(function() {
console.log('emitting', ++workId);
publisher.publish('update', workId);
}, 3000);
});

var Subscriber = require('cote').Subscriber,


subscriber = new Subscriber({
name: 'subscriber'
});
subscriber.on('update', function(message) {
console.log('update', message);
});

QUICK DEMO

CONCLUSION
With Redis, RabbitMQ or cote.js we can;

Apply sophisticated programming paradigms
Scale nearly infinitely
Have fault-tolerant systems

THANK YOU!
examples at https://github.com/dashersw/node-scale

CONTRIBUTE TO COTE.JS
github.com/dashersw/cote

LET'S KEEP IN TOUCH!


Armagan Amcalar
armagan@amcalar.com
twitter: @aamcalar
github: dashersw
blog: arm.ag

You might also like