The document discusses strategies for horizontally scaling Node.js applications. It covers monitoring metrics like response times and CPU usage to determine when an application needs to be scaled. Methods for scaling include adding more servers running the application code, using clustering to distribute load across CPU cores, leveraging an in-memory data store like Redis to share state, and load balancing traffic across servers.
19. ROLLING UPDATES
1. UPDATE SCRIPT
2. WORKER -> STOP LISTENING
3. KILL WORKER
4. CALL FORK() AGAIN
Thursday, April 4, 13
20. CLUSTER MODULE
mydomain.com
> NODE > NODE
> NODE > NODE
SERVER
Thursday, April 4, 13
21. HURTLE: SHARED STATE
> NODE > NODE
NO SHARED STATE
> NODE > NODE
SERVER
Thursday, April 4, 13
22. INSTALL REDIS
> NODE > NODE
> NODE > NODE
REDIS
SERVER
Thursday, April 4, 13
23. EXAMPLE 1: SESSION
MEMORY STORE
var express = require('express'),
app = express();
app.use(express.cookieParser());
app.use(express.session({
secret: 'My Cookie Signing Secret'
}));
app.get('/', function(req, res) {
req.session.somekey = 'some value';
});
Thursday, April 4, 13
24. EXAMPLE 1: SESSION
REDIS STORE
var express = require('express'),
RedisStore = require('connect-redis')(express),
app = express();
app.use(express.cookieParser());
app.use(express.session({
store: new RedisStore({ host: 'localhost', port: 6379 }),
secret: 'My Cookie Signing Secret'
}));
app.get('/', function(req, res) {
req.session.somekey = 'some value';
});
Thursday, April 4, 13
25. EXAMPLE 2: SOCKET.IO
var RedisStore = require('socket.io/lib/stores/redis')
, redis = require('socket.io/node_modules/redis')
, pub = redis.createClient()
, sub = redis.createClient()
, client = redis.createClient();
io.set('store', new RedisStore({
redisPub : pub
, redisSub : sub
, redisClient : client
}));
https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
Thursday, April 4, 13
26. RUNNING SMOOTH
mydomain.com
> NODE > NODE
> NODE > NODE
REDIS
SERVER
Thursday, April 4, 13
27. LAST HURTLE: HORIZONTAL
> NODE > NODE > NODE > NODE
> NODE > NODE > NODE > NODE
REDIS REDIS
APP SERVER A APP SERVER B
Thursday, April 4, 13
28. SEPARATE REDIS
> NODE > NODE > NODE > NODE
> NODE > NODE > NODE > NODE
APP SERVER A APP SERVER B
REDIS
SERVER
Thursday, April 4, 13
29. LOAD BALANCING
mydomain.com LOAD BALANCER
SERVER
> NODE > NODE > NODE > NODE
> NODE > NODE > NODE > NODE
APP SERVER A APP SERVER B
REDIS
SERVER
Thursday, April 4, 13
30. LOAD BALANCING
1. MANAGED
2. INSTALL ONE
3. WRITE YOUR OWN
Thursday, April 4, 13
31. NGINX
http {
upstream mydomain_com {
server host1.mydomain.com:80;
server host2.mydomain.com:80;
} LOAD BALANCER
server {
SERVER
listen 80;
server_name www.mydomain.com;
location / {
proxy_pass http://mydomain_com;
}
}
}
Thursday, April 4, 13
32. WRITE ONE
https://github.com/substack/bouncy
Thursday, April 4, 13
33. BOUNCY
var bouncy = require('bouncy'); bouncy module
var hosts = [
'host1.mydomain.com',
'host2.mydomain.com'
];
var count = 0;
var server = bouncy(function(req, res, bounce) {
count++;
var host = hosts[count % hosts.length];
bounce(host, 80);
});
server.listen(80);
Thursday, April 4, 13
34. BOUNCY
var bouncy = require('bouncy');
var hosts = [ Server collection
'host1.mydomain.com',
'host2.mydomain.com'
];
var count = 0;
var server = bouncy(function(req, res, bounce) {
count++;
var host = hosts[count % hosts.length];
bounce(host, 80);
});
server.listen(80);
Thursday, April 4, 13
35. BOUNCY
var bouncy = require('bouncy');
var hosts = [
'host1.mydomain.com',
'host2.mydomain.com'
];
var count = 0;
var server = bouncy(function(req, res, bounce) { Create server
count++;
var host = hosts[count % hosts.length];
bounce(host, 80);
});
server.listen(80);
Thursday, April 4, 13
36. BOUNCY
var bouncy = require('bouncy');
var hosts = [
'host1.mydomain.com',
'host2.mydomain.com'
];
var count = 0;
var server = bouncy(function(req, res, bounce) {
count++;
var host = hosts[count % hosts.length];
bounce(host, 80); Bounce request
});
server.listen(80);
Thursday, April 4, 13
37. AFFINITY
SESSION AFFINITY
STICKY SESSIONS
SEND THE SAME PERSON
BACK TO THE SAME SERVER
Thursday, April 4, 13
38. NGINX AFFINITY
http {
upstream mydomain_com {
sticky;
server host1.mydomain.com:80;
server host2.mydomain.com:80;
}
server {
listen 80;
server_name www.mydomain.com;
location / {
proxy_pass http://mydomain_com;
}
}
}
Thursday, April 4, 13
39. CUSTOM AFFINITY
req.headers['x-forwarded-for']
req.connection.remoteAddress
Thursday, April 4, 13
40. RUNNING SMOOTH
mydomain.com LOAD BALANCER
SERVER
> NODE > NODE > NODE > NODE
> NODE > NODE > NODE > NODE
APP SERVER A APP SERVER B
REDIS
SERVER
Thursday, April 4, 13
41. ROLLING UPDATES
1. REMOVE APP SERVER FROM LOAD BALANCER
2. UPGRADE APP SERVER
3. ADD BACK
4. REPEAT
Thursday, April 4, 13
43. SSL
LB SSL SSL TERMINATOR
SERVER
> NODE > NODE > NODE > NODE
> NODE > NODE > NODE > NODE
APP SERVER A APP SERVER B
REDIS
SERVER
Thursday, April 4, 13
44. SSL
mydomain.com
80 443
LB SSL
SERVER
Thursday, April 4, 13
45. STUD
EXAMPLE CONFIG FILE
frontend = [*]:443
backend = [127.0.0.1]:80
ssl = on
pem-file = "myCert.pem"
https://github.com/bumptech/stud
Thursday, April 4, 13
46. RUNNING SMOOTH W/SSL
mydomain.com LB SSL
SERVER
> NODE > NODE > NODE > NODE
> NODE > NODE > NODE > NODE
APP SERVER A APP SERVER B
REDIS
SERVER
Thursday, April 4, 13
47. HUGE
LB SSL LB SSL
SERVER SERVER
REDIS
SERVER
Thursday, April 4, 13
48. DNS
ROUND-ROBIN DNS
MULTIPLE RECORDS,
ONE DOMAIN
Thursday, April 4, 13
49. ROUND-ROBIN DNS
CLIENT 1 1. xxx.xxx.xxx.x
2. xxx.xxx.xxx.y
CLIENT 2 1. xxx.xxx.xxx.y
2. xxx.xxx.xxx.x
Thursday, April 4, 13
50. RUNNING SMOOTH
LB SSL LB SSL
SERVER SERVER
REDIS
SERVER
Thursday, April 4, 13
51. BIG ENOUGH
> NODE
SERVER
Thursday, April 4, 13
52. BIG ENOUGH
> NODE
SERVER
Thursday, April 4, 13