Node.js - Eventos para Todos
-
Upload
mariano-iglesias -
Category
Technology
-
view
4.829 -
download
1
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