Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Before start coding in Node.js

guldenpt
September 19, 2012

Before start coding in Node.js

Following on the Node.js hype, I've noticed that a lot of people are talking about Node.js but do you really know how it works?
Before start coding in Node.js is necessary to understand how it works internally and understand a new programming paradigm. So, in my talk i'll start talking about the internal architecture of Node.js and which core libraries are being used in windows and linux. It is very important to understand the concept of event driven programming as well as how the event loop works internally and, therefore, prevent the development of bad code or apply Node.js for a function for which it was not designed. The fundamental concepts about Node.js are very simple, but first you have to learn them.

Finally, I will talk about how to do profiling in Node.js, some performance tips and present some real cases where Node.js is being used.

Presentation Topics

Internal Architecture
Asynchronous I / O
Event Driven Programming
EventLoop
Node.js is single threaded?
Flow control
Performance tips
WebSockets
Who & How is using Node.js

If you are interested in this talk, please contact me.

guldenpt

September 19, 2012
Tweet

Other Decks in Technology

Transcript

  1. Asynchronous Non blocking Event Driven Single thread? Event loop I/O

    libio libev IOCP server side AIO libuv Thread pool callback
  2. Handle requests • One request at a time (simple, blocks

    loop,...) • Process per request (easy, heavy, overkill,...) • Thread per request (easy, memory expensive!, race conditions, context switching ) OR • Event Driven Programming (Apache vs Nginx) OR • Hybrid solutions...
  3. Blocking vs Non-Blocking Blocking var data = fs.readFileSync('/etc/passwd'); console.log(data); Non-Blocking

    (Asynchronous) fs.readFile('/etc/passwd', function (err, data) { if (err) throw err; console.log(data); }); console.log("do something else...");
  4. Asynchronous I/O «Asynchronous I/O or non-blocking I/O, is a form

    of input/output processing that permits other processing to continue before the transmission has finished. Many operating system functions exist to implement asynchronous I/O at many levels.» wikipedia
  5. Asynchronous I/O • Processes(heavy, IPC) • Polling(wastes cpu cycles) •

    Select(/poll) loops ◦ select (operates at O (n) ) ◦ poll ◦ epoll(linux, operates at O (1) ) ◦ kqueue(FreeBSD's) ◦ /dev/poll(Solaris) • Signals(interrupts) • Callback functions • LWP or threads(thread poll, erlang) • Completion queue/ports (IOCP, win, Solaris, AIX)
  6. Event Driven Programming «In computer programming, event-driven programming or event-based

    programming is a programming paradigm in which the flow of the program is determined by events» Wikipedia
  7. $ vi checkThreads.js #!/usr/local/bin/node var file = process.argv[2] console.log(process.pid) //

    optional if(file){ require('fs').readFile(file, function() {}); } setTimeout(function(){console.log("Hello Threads!!")}, 2000); :wq
  8. $ ./checkthreads.js & pstack $! Thread 2 (Thread 0x4150b940 (LWP

    14745)): #0 0x0000003a7d60cd01 in sem_wait () from /lib64/libpthread.so.0 #1 0x000000000093b29a in v8::internal::LinuxSemaphore::Wait() () #2 0x00000000008808e7 in v8::internal::RuntimeProfiler::WaitForSomeIsolateToEnterJS() () #3 0x0000000000880914 in v8::internal::RuntimeProfilerRateLimiter::SuspendIfNecessary() () #4 0x000000000093c736 in v8::internal::SignalSender::Run() () #5 0x000000000093b480 in v8::internal::ThreadEntry(void*) () #6 0x0000003a7d60673d in start_thread () from /lib64/libpthread.so.0 #7 0x0000003a7cad40cd in clone () from /lib64/libc.so.6 Thread 1 (Thread 0x2af2ca740a90 (LWP 14740)): #0 0x0000003a7cad44b8 in epoll_wait () from /lib64/libc.so.6 --> wait for events #1 0x00000000005df436 in epoll_poll () -- > use epoll #2 0x00000000005d54f4 in uv__run () -- > libuv: watch out for events #3 0x00000000005d577c in uv_run () #4 0x0000000000589663 in node::Start(int, char**) () #5 0x0000003a7ca1d994 in __libc_start_main () from /lib64/libc.so.6 #6 0x0000000000582179 in _start () Hello Threads!! $ RESTRICTIONS check if pstack works in your OS.
  9. $ ./checkthreads.js /dev/null & pstack $! Thread 3 (Thread 0x403b7940

    (LWP 10801)): #0 0x0000003a7d60cd01 in sem_wait () from /lib64/libpthread.so.0 #1 0x000000000093b29a in v8::internal::LinuxSemaphore::Wait() () #2 0x00000000008808e7 in v8::internal::RuntimeProfiler::WaitForSomeIsolateToEnterJS() () #3 0x0000000000880914 in v8::internal::RuntimeProfilerRateLimiter::SuspendIfNecessary() () #4 0x000000000093c736 in v8::internal::SignalSender::Run() () #5 0x000000000093b480 in v8::internal::ThreadEntry(void*) () #6 0x0000003a7d60673d in start_thread () from /lib64/libpthread.so.0 #7 0x0000003a7cad40cd in clone () from /lib64/libc.so.6 Thread 2 (Thread 0x40d7d940 (LWP 10807)): #0 0x0000003a7d60aee9 pthread_cond_waitin @@GLIBC_2.3.2 () from /lib64/libpthread.so.0 #1 0x00000000005d68a1 in etp_proc () -- > libio: wait for io requests #2 0x0000003a7d60673d in start_thread () from /lib64/libpthread.so.0 #3 0x0000003a7cad40cd in clone () from /lib64/libc.so.6 Thread 1 (Thread 0x2ab220d84a90 (LWP 10796)): 1. #0 0x0000003a7cad44b8 in epoll_wait () from /lib64/libc.so.6 #1 0x00000000005df436 in epoll_poll () #2 0x00000000005d54f4 in uv__run () #3 0x00000000005d577c in uv_run () #4 0x0000000000589663 in node::Start(int, char**) () #5 0x0000003a7ca1d994 in __libc_start_main () from /lib64/libc.so.6 #6 0x0000000000582179 in _start () Hello Threads!! $
  10. javascript fits well in Node • no API's for I/O

    • supports callbacks, closures • event-driven nature of JS • client/server standardisation
  11. callback pyramid of doom function archiveOrders(date, cb) { db.connect(function(err, conn)

    { if (err) return cb(err); conn.query("select * from orders where date < ?", [date], function(err, orders) { if (err) return cb(err); helper.each(orders, function(order, next) { conn.execute("insert into archivedOrders ...", [order.id, ...], function(err) { if (err) return cb(err); conn.execute("delete from orders where id=?", [order.id], function(err) { if (err) return cb(err); next(); }); }); }, function() { console.log("orders have been archived"); cb(); }); }); }); } // source streamline.js
  12. Flow control func1( ); function func1( ) { func2( );

    } function func2( ) { func3(); } function func3( ) { func4(); } // ...
  13. Flow control libraries • async • step • futures •

    after.js • stack • chainsaw • streamline.js • ...
  14. Series async.series([ function(callback){ // do some stuff ... callback(null, 'one');

    }, function(callback){ // do some more stuff ... callback(null, 'two'); }, ], // optional callback function(err, results){ // results is now equal to ['one', 'two'] });
  15. Parallel async.parallel([ function(callback){ setTimeout(function(){ callback(null, 'one'); }, 200); }, function(callback){

    setTimeout(function(){ callback(null, 'two'); }, 100); }, ], // optional callback function(err, results){ // the results array will equal ['one','two'] even though // the second function had a shorter timeout. });
  16. DB transactions • new connection • use a dedicated pool

    connection • use a stored procedure • use node-pool • use api's
  17. var app = require('http').createServer(handler), // create server io = require('socket.io').listen(app),

    // bind & listen for ws static = require('node-static'); // serve static files var fileServer = new static.Server('./'); function handler (request, response) { request.addListener('end', function () { fileServer.serve(request, response); // serve the file }); } io.sockets.on('connection', function (socket) { socket.on('message', function (data) { socket.broadcast.emit('newmsg', data); // broadcast }); }); app.listen(8000); Server
  18. <head> <title>Board</title> <link rel="stylesheet" href="index.css" type="text/css" media="screen" charset="utf-8"> <script src="/socket.io/socket.io.js"

    language="javascript"></script> <script src="/jquery-1.8.1.min.js" language="javascript"></script> <script src="/client.js" language="javascript"></script> </head> <body> <div> <span id="status">Connecting...</span> <input type="text" id="input"/> </div> <div id="board"> <h1 class="message">Welcome abord</h1> </div> </body> Client
  19. var url = 'ws://localhost:8000'; // url var socket = io.connect(url);

    // connect socket.on('newmsg', function (data) {processMsg(data)}); // on recv msg $('#input').keydown( function(e){ // submitted msg if(e.keyCode === 13){ var msg = $(this).val(); socket.emit('message', msg); // send msg processMsg(msg); $(this).val(''); } }); function processMsg(msg){ $("#board h1").each(function(){ $(this).animate({"font-size":"-=15px", "opacity": "-=0.15"},200); }); $("#board").prepend($("<h1>"+msg+"</h1>").fadeIn('slow')) } Client
  20. based on nodetime (look don't send any data outside your

    server) $ npm install look require('look').start(); http://[yourhost]:5959 look
  21. STRACE (profile syscalls) $ strace -cf -p 3222 % time

    seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 65.99 0.716905 47 15202 1846 futex 31.36 0.340671 164 2082 nanosleep 1.16 0.012639 2 5136 epoll_wait 0.52 0.005697 1 7234 write 0.19 0.002022 0 5137 clock_gettime 0.17 0.001894 0 5080 read 0.15 0.001636 74 22 mmap 0.14 0.001555 1 2402 1198 accept 0.13 0.001463 1 1204 close 0.08 0.000864 1 1204 epoll_ctl 0.00 0.000000 0 7 munmap ------ ----------- ----------- --------- --------- ---------------- 100.00 1.086430 49526 3044 total
  22. Pros •easy to implement •it's fast (V8 JS engine) •WebSockets

    support •SPDY support •huge JS developers community •event driven •shared nothing •without threads, locks, race conditions •lots of concurrent connections with low overhead
  23. Use Cases • REST/JSON APIs • WebSockets • real time

    data applications • mobile application backend • streaming data • proxy server • DNS Server • FTP Server • file uploading • chat server • ad server • ...
  24. • linkedIn (mobile server) • transloadit (real time encoding) •

    koding (browser based IDE and cloud platform) • trello (project management) • Etsy (StatsD listen for stats & fw to graphite) • Opa (web framework client/server) • browserling ( test multiple browsers) • github Projects, Applications, and Companies Using Node https://github.com/joyent/node/wiki/Projects%2C-Applications%2C-and-Companies-Using-Node Who & How (is using Node.js)
  25. Performance tips (from linkedin mobile) •Avoid synchronous code •Turn off

    socket pooling •Don't use node.js for static assets •Render on the client-side •Use gzip •Go parallel •Go session-free •Use binary modules •Use standard V8 JavaScript instead of client-side libraries •Keep your code small and light
  26. NVM - Node Version Manager To download, compile, and install

    the v0.6.14 release of node, do this: $ nvm install v0.6.14 And then in any new shell just use the installed version: $ nvm use v0.6.14 Or you can just run it: $ nvm run v0.6.14 If you want to see what versions are available: $ nvm ls To set a default Node version to be used in any new shell, use the alias 'default': $ nvm alias default 0.6