Node.js - Eventos para Todos

download Node.js - Eventos para Todos

If you can't read please download the document

Transcript of Node.js - Eventos para Todos

Node.js

Eventos para todos!

BarCamp BA 2011

Mariano Iglesias

@mgiglesias

(No es un plan del gobierno)

Quin habla?

Miramarense por eleccin

No sirvo para otra cosa ms que programar

CakePHP & Lithium

Muu..uuchos proyectos FOSSC++, Python, PHP, Node.js

Amo Apple

Tir todo lo que hiciste

Si cres que eso es positivo, debs creer que Grondona es un tipo honesto

Us diferentes tecnologas para resolver problemas distintos

PHP

Python

Node.js

C++

NGINx / Lighttpd

En qu estaba pensando Ryan?

Qu hace normalmente una aplicacin?

Qu puedo hacer?Agregar cache

Agregar workers

Mejor manejo de DB

Escalado Vertical: ms hardware

Escalado Horizontal: ms servers

No llegs a los 10k usuarios concurrentes?

** QUE HACE: Esperando. Entra conexin, consults la DB, y esperas resultados. Escribs un archivo, y espers q se escriba. Encodes un video, y espers q termine.** CACHING: Memcached** WORKERS: Gearman, o ActiveMQ / RabbitMQ** FASTER DB: NoSQL (MongoDB, CouchDB)

Threads vs. eventos

http://blog.wefaction.com/a-little-holiday-present

Me niego a decir hilos

No pods simplemente abrir nuevos procesos o threads para cada conexinNGINX basado en eventos, uso de memoria muy bajoAPACHE lanza un thread por request (o proceso dependiendo de la conf)THREADS estn mucho tiempo bloqueados por operaciones I/OEVENTOS son mejores cuando se emplea mucho tiempo esperando recursos

Qu es Node.js?

Simplificando, es JavaScript en el servidor

Engine V8 JavaScript

I/O basada en Eventos

+

=

** V8: Sin soporte DOM

Engine V8

Acceso a propiedades (clases ocultas)

Cdigo mquina

Garbage collection

La rapidez como mantra

http://code.google.com/apis/v8/design.html

** PROPS: Propiedades de objetos se cambian en runtime en JS: diccionarios de propiedadesVariables 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 tamao ilimitado

La rapidez no es lo nico

Tiene que haber un balance entre performance y productividad.Si no fuese as, seguiramos programando en Assembler

Dedicado a los benchmarks de Erlang, Tornado, etc.

** Tornado (Python). Tambien Event Machine (Ruby)

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

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

Libuv == Node.exe

http_simple (/bytes/1024) over 1-gbit network, with 700 concurrent connections:

windows-0.5.4 : 3869 r/swindows-latest : 4990 r/slinux-latest-legacy : 5215 r/slinux-latest-uv : 4970 r/s

Node sobre Windows es tan rapido como LinuxSoporte desde Windows Server 2003 a Windows 7

Ms cosas

buffer: muchos bytes

c-ares: DNS asncrono

child_process: spawn(), exec(), fork() (0.5.x)

crypto: OpenSSL

http_parser: parser HTTP ms rpido que Berlusconi

timer: setTimeout(), setInterval()

** BUFFER: Fuera del heap V8. Conversion a JS a travs 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

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

Regla #1: NO BLOQUEAR

Regla #1: NO BLOQUEAR

Quers abrir un archivo? Tir el open, y esperPero mientras espers, labur canejo!

Llams a un binario para encodear? Nuevamente, esperPero acordate, segu laburando

Todo esto es posible gracias a la programacin basada en... EVENTOS (obvio)

Regla #2: TERMINA RAPIDO

Regla #2: TERMINA RAPIDO

Si tens que procesar algo grande, pens en subprocesos

Si no tens subprocesos, bancatela y program en C++Despus me lo agradecs

Lo importante es que si lo vas a hacer, hacelo rpido

Entendiendo el event loop

eventos

Abrir archivo

loopSigo trabajando...

FIN

En espera

Procesar loop

Kernel I/O

KERNEL

Listo

Callback

* 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 vaco, el programa termina

Entendiendo el event loop

Hay un solo thread corriendo en Node.js

No hay ejecucin paralela... 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');

** SOLO THREAD: todo lo que bloquea el thread ppal imposibilita procesar nuevas requests** Para VOS: si tu cdigo 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 rpido. Tareas intensivas de CPU debieran ser en otro proceso

UN THREAD ?!

Y qu hago con este monstruo de 48 ncleos?

Tengo ms de 1 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

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

Tengo ms de 1 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);}

Me convenciste

Node.js suena interesante... pero es Javascript!

Ok, Javascript no es tan malo... Pero en PHP tengo un montn de documentacin

Bueno, acepto la comunidad... Pero no tengo todas las libreras que tengo en Java

Yo soy cool, y uso Ruby noms

www.nodojs.org

** RUBY: Us CoffeeScript

Mdulos, mdulos, mdulos

$ curl http://npmjs.org/install.sh | sh$ npm install db-mysql

Hay ms de 4700 paquetes, y ms de 14 se agregan cada da

** Los paquetes pueden instalarse local o globalmente

Mdulos, mdulos, mdulos

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

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

Mostrame un lenguaje, y te vomito frameworks

Entornos configurables

Middleware

Routing

Vistas (duh!)

Sesiones (duh por dos!)

http://expressjs.com

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

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

** MIDDLEWARES: order is important. ** BodyParser() allows the parsing of forms (including JSON posted data as part of body)** Other middlewares include: cookieParser(), session()

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

** JADE is one of the view engines available: $ npm install jade

Middleware en rutas

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

With route middleware, it's easy to add authentication

node-db

Para qu?

Bases de datos soportadas

ConsultasManuales

API

Tipos JSONBuffer

http://nodejsdb.org

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

Para ir pispeando

Pool de conexiones con generic_pool

Tareas paralelas con async

Unit Testing con nodeunit

Socket.io

Libs para MongoDB, Redis, CouchDB...

_ (underscore.js)

* 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

Preguntas?

@mgiglesiashttp://marianoiglesias.com.ar

Klicken Sie, um das Format des Titeltextes zu bearbeiten

Text