Upload
piotr-pelczar
View
6.492
Download
2
Embed Size (px)
DESCRIPTION
Node.js facts and myths, revealed architecture and scaling eventapproach.
Citation preview
About me
Piotr [email protected]
About me
getfokus.com useselly.com
How software lives in hardware?
•Operating systems are process based• Each process has assigned processor,
registers, memory
http://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/4_Threads.html
How software lives in hardware?
•Process paralelism using threads (thread pools)• Switching processor over
processes/threads causes context switching
http://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/4_Threads.html
How software lives in hardware?
1. Avoid context switching = wasting time
How software lives in hardware?
In trivial, sequential approach
• Each operation is executed sequentially:
O(t) > O(t+1)
• if O(t) stucks, O(t+1) waits…
http://cs.brown.edu/courses/cs196-5/f12/handouts/async.pdf
How software lives in hardware?
This is cool, software flow is predictibleBut not in high throughput I/O
http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/
How software lives in hardware?
High throughput I/O doesn’t mean:
•Memory operations• Fast single-thread computing
How software lives in hardware?
High throughput I/O means:
•HTTP requests•Database connections•Queue system dispatching•HDD operations
Single-threaded, event loop model
Problem:
Imagine a man, who has a task:1. Walk around2. When bucket is full of water,
just pour another bucket3. Go to next bucket
http://www.nightmare.com/medusa/async_sockets.html
Single-threaded, event loop model
What is nonblocking I/O?
Imagine a man, who has a task:1. Walk around2. When bucket is full of water,
just pour another bucket3. Go to next bucket
http://www.nightmare.com/medusa/async_sockets.html
Single-threaded, event loop model
Problem:
Imagine a man, who has a task:1. Walk around2. When bucket is full of water,
just pour another bucket,if not… continue
3. Go to next buckethttp://www.nightmare.com/medusa/async_sockets.html
Single-threaded, event loop model
How it is realised in low-level operating system?
•select()•/dev/pool descriptors•kqueue•pool•epool
Single-threaded, event loop model
How it is realised in low-level operating system?
#include <sys/types.h>
#include <sys/socket.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timeval *timeout);
Single-threaded, event loop model
2. Avoid I/O blocking
Node.js architecture
http://nodejs.org/logos/
Node.js architecture
Node std library
node bindings (socket, http, …)
Event loop(libev)Google V8 Thread Pool
(libeio)
JavaScript
C/C++
Node.js architecture
• Single-threadedno context switching
• Event loopno waits
• Javascript (Google V8)• ECMA-262 support
Node.js architecture
http://www.tocadoelfo.com.br/2012/04/por-que-estou-aprendendo-nodejs.html
ECMA-262 support
var arr = []
for(var i = 0, j = arr.length; i < j; ++i) {
var row = arr[i] // ufff…
}
var arr = []
arr.forEach(function(row) {
})
„Parallelism”is a myth
Node.js architecture
• Everything runs in parallel except your code
•When currently code is running,(not waiting for I/O descriptors)whole event loop is blocked
„Parallelism”
• Let’s compute Fibonacci
function fib(n) {
return (n < 2) ? 1 : (fib(n-2)+fib(n-1));
}
This will simply block main (single) thread.
„Parallelism”
•How about process.nextTick() ?
„Parallelism”
•… but next iteration over function is delayed into next event loop iteration• That means each descriptor is checked before
computation.
„Parallelism”
process.nextTick()to speed up computations is a myth
Node.js is not good solution to make single-process computations
„Parallelism”
You can still fork another process
• threads_a_gogopool = require('threads_a_gogo').createPool(5)pool.any.eval('myFunction( ... )')
• Fork processvar fork = require('child_process').fork;var child = fork(__filename, [ 'arg1' ]);
Callback hellis a mythwe can deal with it
Callback hell
• Language construction – callback function•When operation is ready, call function passed as an
argument
someOperation(arg1, arg2, function() {
console.log('cool!');
})
Callback hell
•When many operations are ready…
var amqp = require('amqp');var connection = amqp.createConnection();
connection.on('ready', function() { connection.exchange("ex1", function(exchange) {
connection.queue('queue1', function(q) {q.bind(exchange, 'r1');
q.subscribe(function(json, headers, info, m) {console.log("msg: " +
JSON.stringify(json));});
});});
}); This is callback hell
Callback hell
Deal with callback hell in many ways:
•Define callbacks as local variables•Use async module•Use PROMISE design pattern
Callback hell
Define callbacks as local variables, like this:
var whenSthElseDone = function() {
// done...
}
var whenSthDone = function() {
operation(whenSthElseDone)
}
operation(whenSthDone)
Callback hell
Use async module:
async.series([
function(callback) {
operation1(callback)
},
function(callback) {
operationBloking()
return callback()
}
],
function() {
// all done...
})
Callback hell
PROMISE design pattern:
var Promise = require('promise');
var promise = new Promise(function (resolve, reject) {
operation1(function (err, res) {
if (err) reject(err);
else resolve(res);
});
});
Callback hell
PROMISE design pattern:
promise.then(function(res) {
// done...
})
Events (event bus)Triggering event does’t block whole event loop is a myth
Eventsvar eventbus = require('events').EventEmitter
myFunction() {
operation1(function() {
eventbus.emit('myFunctionIsDone', {
result: 1234
})
}
}
Eventsvar eventbus = require('events').EventEmitter
eventbus.on('myFunctionIsDone', function(data) {
console.log('cool! ')
})
Trigger waits until all listeners are done. So do not make long-running operations in event subscribers.
Scaling EventEmitterTriggering events in event bus via EventEmitter does not scale!
Scaling EventEmitter
• Triggering events in event bus via EventEmitterdoes not scale!• Events are visible locally in main thread
Scaling EventEmitter
We need to use external queue system
to touch distributed nodes(3rd party for our application written in Node.js)
Scaling EventEmitter
RabbitMQ is cool because:
•based on AMQP protocol(so integrates 3rd party software – an abstraction)•Queue async system•Publish-subscribe async model•Request-Response model
Scaling EventEmitter
Emit:
1. Trigger event in your application via EventEmitter2. Catch it locally3. Re-trigger via RabbitMQ
Scaling EventEmitter
Receive:
1. Subscribe on RabbitMQ exchange2. Trigger local event in application
Scaling EventEmitter
This is only to separate responsibilitiesand good design of application
Not only Node.jsNode.js is not a religion! It is only an implementation of async programming model
Not only Node.js
Node.js is not a religion. Last time - hype.It only utilizes event-loop model, known from a long time…
• GUI frameworks• Tornado – Python• Linkedin parseq – Java• Async and Await – C#• Cramp – Ruby• reactphp – PHP, ehhh… WAT?!
Event loop, single-threaded model is not solution for all your problems…Especially for long-running computings in single thread.It’s good for high throughput I/O.
Thank you.Q&A?
Piotr [email protected]