Node.js ¡Eventos para todos! BarCamp BA 2011 Mariano Iglesias @mgiglesias (No es un plan del gobierno)
¿Quién habla? Miramarense por elección
No sirvo para otra cosa más que programar
CakePHP & Lithium
Muu..uuchos proyectos FOSS C++, Python, PHP, Node.js Amo Apple
Tirá todo lo que hiciste Si creés que eso es positivo, debés creer que Grondona es un tipo honesto Usá  diferentes  tecnologías para resolver problemas distintos PHP
Python
Node.js
C++
NGINx / Lighttpd
¿En qué estaba pensando Ryan? ¿Qué hace normalmente una aplicación?
¿Qué puedo hacer? Agregar  cache
Agregar  workers
Mejor manejo de  DB
Escalado  Vertical : más hardware
Escalado  Horizontal : más servers ¿No llegás a los 10k usuarios concurrentes?
Threads vs. eventos http://blog.wefaction.com/a-little-holiday-present Me niego a decir hilos
¿Qué es Node.js? Simplificando, es  JavaScript  en el  servidor Engine V8 JavaScript I/O basada en Eventos + =
Engine V8 Acceso a propiedades (clases ocultas)
Código máquina
Garbage collection La rapidez como mantra http://code.google.com/apis/v8/design.html
La rapidez no es lo único “ Tiene que haber un balance entre  performance  y  productividad .“ “ Si no fuese así, seguiríamos programando en  Assembler “ Dedicado a los benchmarks de Erlang, Tornado, etc.
I/O basada en Eventos libeio : async I/O
libev : event loop libuv db. query (). select ( '*' ). from ( 'users' ). execute ( function () { fs. readFile ( 'settings.json' ,   function () { // ... }); });
Libuv == Node.exe http_simple (/bytes/1024) over 1-gbit network, with 700 concurrent connections: windows-0.5.4  : 3869 r/s windows-latest  : 4990 r/s linux-latest-legacy  : 5215 r/s linux-latest-uv  : 4970 r/s
Más cosas buffer : muchos bytes
c-ares : DNS asíncrono
child_process : spawn(), exec(), fork() (0.5.x)
crypto : OpenSSL
http_parser : parser HTTP más rápido que Berlusconi
timer : setTimeout(), setInterval()
Primer servidor node.js var   http   =   require ( 'http' ); http. createServer ( function (req,   res) { res. writeHead ( 200 , { 'Content-type' :   'text/plain' }); res. end ( 'Hello World!' ); }). listen ( 1337 ); console. log ( 'Server running at http://localhost:1337' );

Node.js - Eventos para Todos

  • 1.
    Node.js ¡Eventos paratodos! BarCamp BA 2011 Mariano Iglesias @mgiglesias (No es un plan del gobierno)
  • 2.
  • 3.
    No sirvo paraotra cosa más que programar
  • 4.
  • 5.
    Muu..uuchos proyectos FOSSC++, Python, PHP, Node.js Amo Apple
  • 6.
    Tirá todo loque hiciste Si creés que eso es positivo, debés creer que Grondona es un tipo honesto Usá diferentes tecnologías para resolver problemas distintos PHP
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
    ¿En qué estabapensando Ryan? ¿Qué hace normalmente una aplicación?
  • 12.
    ¿Qué puedo hacer?Agregar cache
  • 13.
  • 14.
  • 15.
    Escalado Vertical: más hardware
  • 16.
    Escalado Horizontal: más servers ¿No llegás a los 10k usuarios concurrentes?
  • 17.
    Threads vs. eventoshttp://blog.wefaction.com/a-little-holiday-present Me niego a decir hilos
  • 18.
    ¿Qué es Node.js?Simplificando, es JavaScript en el servidor Engine V8 JavaScript I/O basada en Eventos + =
  • 19.
    Engine V8 Accesoa propiedades (clases ocultas)
  • 20.
  • 21.
    Garbage collection Larapidez como mantra http://code.google.com/apis/v8/design.html
  • 22.
    La rapidez noes lo único “ Tiene que haber un balance entre performance y productividad .“ “ Si no fuese así, seguiríamos programando en Assembler “ Dedicado a los benchmarks de Erlang, Tornado, etc.
  • 23.
    I/O basada enEventos libeio : async I/O
  • 24.
    libev : eventloop libuv db. query (). select ( '*' ). from ( 'users' ). execute ( function () { fs. readFile ( 'settings.json' , function () { // ... }); });
  • 25.
    Libuv == Node.exehttp_simple (/bytes/1024) over 1-gbit network, with 700 concurrent connections: windows-0.5.4 : 3869 r/s windows-latest : 4990 r/s linux-latest-legacy : 5215 r/s linux-latest-uv : 4970 r/s
  • 26.
    Más cosas buffer: muchos bytes
  • 27.
    c-ares : DNSasíncrono
  • 28.
    child_process : spawn(),exec(), fork() (0.5.x)
  • 29.
  • 30.
    http_parser : parserHTTP más rápido que Berlusconi
  • 31.
    timer : setTimeout(),setInterval()
  • 32.
    Primer servidor node.jsvar http = require ( 'http' ); http. createServer ( function (req, res) { res. writeHead ( 200 , { 'Content-type' : 'text/plain' }); res. end ( 'Hello World!' ); }). listen ( 1337 ); console. log ( 'Server running at http://localhost:1337' );
  • 33.
    Regla #1: NO BLOQUEAR
  • 34.
    Regla #1: NO BLOQUEAR ¿Querés abrir un archivo? Tirá el open, y esperá Pero mientras esperás, ¡laburá canejo! ¿Llamás a un binario para encodear? Nuevamente, esperá Pero acordate, seguí laburando Todo esto es posible gracias a la programación basada en... EVENTOS (obvio)
  • 35.
    Regla #2: TERMINA RAPIDO
  • 36.
    Regla #2: TERMINA RAPIDO Si tenés que procesar algo grande, pensá en subprocesos
  • 37.
    Si no tenéssubprocesos, bancatela y programá en C++ Después me lo agradecés Lo importante es que si lo vas a hacer, hacelo rápido
  • 38.
    Entendiendo el eventloop eventos Abrir archivo Sigo trabajando... FIN En espera Procesar loop Kernel I/O KERNEL Listo Callback
  • 39.
    Entendiendo el eventloop Hay un solo thread corriendo en Node.js
  • 40.
    No hay ejecuciónparalela... para VOS var http = require ( 'http' ); http. createServer ( function (req, res) { console. log ( 'New request' ); // Block for five seconds var now = new Date (). getTime (); while ( new Date (). getTime () < now + 5000 ) ; // Response res. writeHead ( 200 , { 'Content-type' : 'text/plain' }); res. end ( 'Hello world!' ); }). listen ( 1337 ); console. log ( 'Server running at http://localhost:1337' );
  • 41.
    ¡¿ UN THREAD?! ¿Y qué hago con este monstruo de 48 núcleos?
  • 42.
    ¡Tengo más de1 procesador! :1337 :1338 :1339 Usando load balancer Usando al SO var http = require ( 'http' ), cluster = ...; var server = http. createServer ( function (req, res) { res. writeHead ( 200 , { 'Content-type' : 'text/plain' }); res. end ( 'Hello world!' ); }); cluster (server). listen ( 1337 ); http://learnboost.github.com/cluster
  • 43.
    ¡Tengo más de1 procesador! var http = require ( 'http' ), cluster = require ( 'cluster' ); if (cluster.isMaster) { cluster. startMaster ({ workers: 4 }); process. on ( 'SIGCHLD' , function () { cluster. spawnWorker (); }); } else { http. createServer ( function (req, res) { res. writeHead ( 200 , { 'Content-type' : 'text/plain' }); res. end ( 'Hello world!' ); }). listen ( 1337 ); }
  • 44.
    Me convenciste Node.jssuena interesante... ¡pero es Javascript!
  • 45.
    Ok, Javascript noes tan malo... Pero en PHP tengo un montón de documentación
  • 46.
    Bueno, acepto la comunidad ... Pero no tengo todas las librerías que tengo en Java
  • 47.
    Yo soy cool,y uso Ruby nomás www.nodojs.org
  • 48.
    Módulos, módulos, módulos$ curl http://npmjs.org/install.sh | sh $ npm install db-mysql Hay más de 4700 paquetes, y más de 14 se agregan cada día
  • 49.
    Módulos, módulos, módulosvar m = require ( './module' ); m. sum ( 1 , 3 , function (err, res) { if (err) { return console. log ( 'ERROR: ' + err); } console. log ( 'RESULT IS: ' + res); }); exports.sum = function (a, b, callback) { if ( isNaN (a) || isNaN (b)) { return callback ( new Error ( 'Invalid parameter' )); } callback ( null , a+b); };
  • 50.
    Mostrame un lenguaje,y te vomito frameworks Entornos configurables
  • 51.
  • 52.
  • 53.
  • 54.
    Sesiones (duh pordos!) http://expressjs.com
  • 55.
    express var express = require ( 'express' ); var app = express. createServer (); app. get ( '/' , function (req, res) { res. send ( 'Hello world!' ); }); app. listen ( 3000 ); console. log ( 'Server listening in http://localhost:3000' ); app. configure ( function () { app. use (express. bodyParser ()); }); app. configure ( 'dev' , function () { app. use (express. logger ()); }); $ NODE_ENV=dev node app.js
  • 56.
    express app. configure( function () { app. set ( 'views' , __dirname + '/views' ); app. set ( 'view engine' , 'jade' ); }); app. get ( '/users/:id?' , function (req, res, next) { if (!req.params.id) { return next (); } if (!users[req.params.id]) { return next ( new Error ( 'Invalid user' )); } res. send (users[req.params.id]); }); app. get ( '/users' , function (req, res) { res. render ( 'index' , { layout: false , locals: { users: users } }); }); html body h1 Node.js ROCKS ul - each user, id in users li a(href='/users/#{id}') #{user.name} views/index.jade
  • 57.
    Middleware en rutasfunction getUser (req, res, next) { if (!req.params.id) { return next (); } else if (!users[req.params.id]) { return next ( new Error ( 'Invalid user' )); } req.user = users[req.params.id]; next (); } app. get ( '/users/:id?' , getUser, function (req, res, next) { if (!req.user) { return next (); } res. send (req.user); });
  • 58.
  • 59.
    Bases de datossoportadas
  • 60.
  • 61.
    API Tipos JSONBuffer http://nodejsdb.org
  • 62.
    node-db var mysql = require ( 'db-mysql' ); new mysql. Database ({ hostname: 'localhost' , user: 'root' , password: 'password' , database: 'db' }). connect ( function (err) { if (err) { return console. log ( 'CONNECT error: ' , err); } this . query (). select ([ 'id' , 'email' ]). from ( 'users' ). where ( 'approved = ? AND role IN ?' , [ true , [ 'user' , 'admin' ] ]). execute ( function (err, rows, cols) { if (err) { return console. log ( 'QUERY error: ' , err); } console. log (rows, cols); }); });
  • 63.
    Para ir pispeandoPool de conexiones con generic_pool
  • 64.
  • 65.
  • 66.
  • 67.
    Libs para MongoDB,Redis, CouchDB...
  • 68.
  • 69.

Notas del editor

  • #5 ** QUE HACE: Esperando. Entra conexión, consultás la DB, y esperas resultados. Escribís un archivo, y esperás q se escriba. Encodeás un video, y esperás q termine. ** CACHING: Memcached ** WORKERS: Gearman, o ActiveMQ / RabbitMQ ** FASTER DB: NoSQL (MongoDB, CouchDB)
  • #6 No podés simplemente abrir nuevos procesos o threads para cada conexión NGINX basado en eventos, uso de memoria muy bajo APACHE lanza un thread por request (o proceso dependiendo de la conf) THREADS están mucho tiempo bloqueados por operaciones I/O EVENTOS son mejores cuando se emplea mucho tiempo esperando recursos
  • #7 ** V8: Sin soporte DOM
  • #8 ** PROPS: Propiedades de objetos se cambian en runtime en JS: diccionarios de propiedades Variables de instancia tienen offsets fijos por compilador. V8 crea clases ocultas, una para cada propiedad agregada y las transiciones de clases representan cambios en las propiedades del obj (solo 1ra vez) ** CODIGO MAQUINA: en primera ejecucion de JS, se compila a maquina, NO a codigo intermedio ** GARBAGE: cuando se corre GC, se bloquea. Cada ciclo GC procesa parte del heap. En V8 3.7 (node 0.6) hay un nuevo GC q permite heaps de tamaño ilimitado
  • #9 ** Tornado (Python). Tambien Event Machine (Ruby)
  • #10 ** LIBEIO: similar a LIBEV, por Marc Lehmann. Puede ser usado con cualq lib de eventos, o en modo POLLING. Se basa unicamente en POSIX threads. Usa threads internamente, es usado por Node.JS para acceso de file/network, integrato en node via LIBEV ** LIBEV: tamb por Marc Lehmann. Notificacion asincrona de cambios en file descriptor a traves de ev_io() ** LIBUV: Separa lo propio del OS de V8 ** ReadFile(): mucho codigo JS, arriba de fs.open(), q es un wrapper sobre C++ Open(), q usa libeio
  • #11 Node sobre Windows es tan rapido como Linux Soporte desde Windows Server 2003 a Windows 7
  • #12 ** BUFFER: Fuera del heap V8. Conversion a JS a través de encoding (binary, utf8, ascii, etc.) ** C-ARES: gethostbyname(), consultas DNS ** CHILD_PROCESSES: fork() esta en tierra JS, uso particular de spawn(), con mensajeo IPC ** CRYPTO: crear hashes, ciphers con diferentes algoritmos, firmar con private keys, verificar firmas ** HTTP_PARSER: NO allocation, NO buffer ** TIMER: setTimeout() una sola vez, setInterval() repetidas
  • #18 * Todo pasa en un solo thread * Cola de eventos vacia * Al abrir archivo, se agrega tarea al event loop * Cuando hay tiempo libre, se procesa el event loop * El I/O se realiza usando herramientas del kernel que NO bloquean: epoll(), select(), kqueue() * El event loop sigue esperando * Kernel notifica al event loop q la tarea ta realizada * Event loop ejecuta callback * Cuando el event loop está vacío, el programa termina
  • #19 ** SOLO THREAD: todo lo que bloquea el thread ppal imposibilita procesar nuevas requests ** Para VOS: si tu código usa I/O de node, ese I/O NO bloquea ** Llamadas I/O es el punto en el que Node.js procesa otras requests. Entonces Node.js espera que las requests se procesen rápido. Tareas intensivas de CPU debieran ser en otro proceso
  • #21 Como Node.JS corre en un solo proceso, esta atado a un solo CPU ** Usando al SO: el kernel hace load balancing de las conexiones a traves de los CPUs ** CLUSTER: usa muchos workers (en diferentes CPUs). Alternativa para Node &lt; 0.6
  • #23 ** RUBY: Usá CoffeeScript
  • #24 ** Los paquetes pueden instalarse local o globalmente
  • #25 ** COMMONJS: defines JS APIs for any purpose, such as server side JS. Amongst the things it defines, are modules ** The EXPORTS object is created by the module system. If you want your module to be a class, assign the export object to MODULE.EXPORTS
  • #26 ** ROUTING: Including support for HTTP methods ** MIDDLEWARE: for manipulating all requests, or for specific routes ** VIEW RENDERING: with different template engines, and including partials (sort of like CakePHP elements) ** SESSION SUPPORT: part of Connect, can be configured even with Redis ** ENVIRONMENTS: Can specify different middleware for each environment, and change settings
  • #27 ** MIDDLEWARES: order is important. ** BodyParser() allows the parsing of forms (including JSON posted data as part of body) ** Other middlewares include: cookieParser(), session()
  • #28 ** JADE is one of the view engines available: $ npm install jade
  • #29 With route middleware, it&apos;s easy to add authentication
  • #32 * GENERIC_POOL: definis name, max (conexiones), create(), y destroy(). Luego adquiris con acquire(), y liberas con release() * ASYNC: SERIES (): corre en orden y stop on error, llama callback() cuando terminado. PARALLEL() no para si hay error. WATERFALL() es como series(), p cada resultado se pasa com arg al siguiente * NODEUNIT: usa modulo assert de node * SOCKET.IO: transportes WebSocket, Flash, AJAX long polling, AJAX multipart streaming, JSONP polling. IE 5.5+, Safari 3+, Chrome 4+, Firefox 3+, Opera 10.61+. Mobile (iPhone, iPad, Android, WebOs) * UNDERSCORE: Array, funciones, Object