Slide 1

Slide 1 text

Evented I/O for V8 javascript Marcos Garcia [email protected] Sep 2012

Slide 2

Slide 2 text

Trends

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

source:http://habrahabr.ru/post/108241/

Slide 5

Slide 5 text

JavaScript V8 engine

Slide 6

Slide 6 text

Architecture

Slide 7

Slide 7 text

Asynchronous Non blocking Event Driven Single thread? Event loop I/O libio libev IOCP server side AIO libuv Thread pool callback

Slide 8

Slide 8 text

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...

Slide 9

Slide 9 text

I/O How to do it?

Slide 10

Slide 10 text

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...");

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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)

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Callbacks http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); response.end('Hello World\n'); }); connection.query('SELECT 1', function(err, rows) { console.log( rows[0]); });

Slide 15

Slide 15 text

event loop

Slide 16

Slide 16 text

node.js single threaded ?

Slide 17

Slide 17 text

$ 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

Slide 18

Slide 18 text

$ ./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.

Slide 19

Slide 19 text

$ ./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!! $

Slide 20

Slide 20 text

«Well, in node everything runs in parallel, except your code.» @felixge goto>eventloop

Slide 21

Slide 21 text

PLEASE NO!!!

Slide 22

Slide 22 text

javascript fits well in Node ● no API's for I/O ● supports callbacks, closures ● event-driven nature of JS ● client/server standardisation

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Flow control func1( ); function func1( ) { func2( ); } function func2( ) { func3(); } function func3( ) { func4(); } // ...

Slide 25

Slide 25 text

Flow control libraries ● async ● step ● futures ● after.js ● stack ● chainsaw ● streamline.js ● ...

Slide 26

Slide 26 text

Series

Slide 27

Slide 27 text

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'] });

Slide 28

Slide 28 text

Parallel

Slide 29

Slide 29 text

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. });

Slide 30

Slide 30 text

You can mix'em up Check the API's for even more

Slide 31

Slide 31 text

DB transactions ● new connection ● use a dedicated pool connection ● use a stored procedure ● use node-pool ● use api's

Slide 32

Slide 32 text

Event Driven vs Thread Based

Slide 33

Slide 33 text

WebSockets Bi-directional full-duplex communications Stream of messages instead of Stream of bytes

Slide 34

Slide 34 text

Live Demo simple chat board

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Board
Connecting...

Welcome abord

Client

Slide 37

Slide 37 text

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($("

"+msg+"

").fadeIn('slow')) } Client

Slide 38

Slide 38 text

Alt + Tab

Slide 39

Slide 39 text

Profiling

Slide 40

Slide 40 text

$ npm install nodetime require('nodetime').profile() https://nodetime.com/[session_id nodetime

Slide 41

Slide 41 text

based on nodetime (look don't send any data outside your server) $ npm install look require('look').start(); http://[yourhost]:5959 look

Slide 42

Slide 42 text

V8 built in Profiler $ node --prof app.js $ tools/linux-tick-processor v8.log

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

PROS & CONS

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

Cons ●frequent releases (retro-compatibility) ●recent technology ●one bug could stop the service ●multicore is not mature enough

Slide 47

Slide 47 text

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 ● ...

Slide 48

Slide 48 text

● 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)

Slide 49

Slide 49 text

LinkedIn

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

final thoughts

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

read a book

Slide 56

Slide 56 text

use your brain critical thinking!! I'm a node.js evangelist