Multi-tiered Node.js
Architectures

Tom Hughes-Croucher
@sh1mmer
tom@joyent.com
Scalable Server-Side Code with JavaScript




Node                     Up and Running




                        Tom Hughes-Croucher
Goal 1.
Minimise client
response time
Goal 2.
Maximise resource
efficiency on server
Client → Server   Server → DB




         Computation     Computation
Pre-allocate resources
 to the client for the
   entire duration
Get efficiency within
 each connection
Pre-allocation = sacrificing
  resource efficiency for
connection response times
Server
Request
In order to serve the
fastest request memory
     is heavily wasted
When you run out of
memory the server
 gets overwhelmed
And that sucks.
Don’t pre-allocate
    memory
Create a place-holder
   for ‘slow’ tasks
Place-
holder
Shared
  Work
Resources
Deal with tasks when
 they are ready in a
     FIFO way
App
         (event loop)

 App
Events

                 Event
 OS              Stack
Events
If we block the event
  loop then we can’t
    serve requests
If we do “big” work in the event
   loop then we can only serve
    requests after the work is
             finished
Blocking the main event
 loop is bad. Mmmkay.
Event-loop harassment Pan-da
Multi-tiered
Architectures
The obvious
architecture
Client   Front-end   Database




User       Node        DB
What about this?
Front-end     JSDom
Client                             Database
           Farm      Render Farm




User       Node
           Node        Node
                       Node          DB
            Node
            Node        Node
                        Node
Why an architecture
     like this?
Parallelisation?
Client → Server   Server → DB




         Computation     Computation
Non-blocking I/O
    removes resource
allocation during latency
Pushing client-facing processing
 off the main process does not
     improve response time
Better multi-tier
 architectures
Front-end
Client                Database
           Farm

                         DB


User       Node
           Node
            Node
            Node                    Big Slow
                     Logging farm
                                      Disk

                        Node
                        Node          Disk
Move work which isn’t
user-facing out of main
      event loop
Use pre-forking to
distribute work across
processors into ‘farms’
Distributing work
Cluster
children.js:

var server = require('http')
.createServer(
  function(req, res) {
      res.writeHead(200, {});
      res.end("Sever stuff");
  });
Run
var cluster = require('cluster');

cluster('children').listen(80);
Use load balancers to
  distribute across
       servers
node-proxy
   squid
  varnish
 haproxy
Sharding
Disclaimer:
Sharding is hard
Node processes can
 hold many clients so
you can do big shards
Inter-process
communication on
     machine
Use file descriptor
 sharing to do on
machine multicast
Load      Front-end
Client                           Database
         balancers     Shards

                      Node
                      Node
                       Node
                       Node
User     Node
         Node                       DB
          Node
          Node



                      Node
                      Node
                       Node
                       Node
Unix FDs have much
  lower unbounded
latency than network
Summary
1. Don’t sweat client facing
            CPU time
2. Move non client-facing away
3. Cluster to use all processors
Fin.

(You should follow me,
     @sh1mmer
 on Twitter. Like now!)
Bonus

Multi-tiered Node Architectures - JSConf 2011