node.js - async for the rest of us

57
node.js asynchronous... for the rest of us Mike Brevoort 8.2.2011 DOSUG code sample can be found at https://github.com/mbrevoort/node.js-presentation

Upload: mike-brevoort

Post on 17-May-2015

12.498 views

Category:

Technology


0 download

DESCRIPTION

presented at the Denver Open Source Users Group 8/2/2011

TRANSCRIPT

Page 1: Node.js - async for the rest of us

node.jsasynchronous...

for the rest of us

Mike Brevoort8.2.2011DOSUG

code sample can be found at https://github.com/mbrevoort/node.js-presentation

Page 2: Node.js - async for the rest of us

agenda

the case for node.jsdeveloping with node

look at a few popular moduleslessons from the trenches

Page 3: Node.js - async for the rest of us
Page 4: Node.js - async for the rest of us

typical n-tier run-a-round

browser makes call to web server (waits)web server makes call to database (waits)web server returns result to browser

Response time is dominated by time waiting

Page 5: Node.js - async for the rest of us

typical i/o latencyL1: 3 cyclesL2: 14 cycles

RAM: 250 cyclesDISK: 41,000,000 cycles

NETWORK: 240,000,000 cycles

http://nodejs.org/jsconf.pdf

L1

L2

RAM

Disk

Network

0 60,000,000 120,000,000 180,000,000 240,000,000 300,000,000

Page 7: Node.js - async for the rest of us

“Most languages were designed to solve computational problems, but

Node.js is different.

Node.js was designed from the ground up to efficiently handle the communication that is at the heart

of modern web applications.”

http://www.joyentcloud.com/products/smart-appliances/node-js-smartmachine/

Page 8: Node.js - async for the rest of us

node.jsAn Evented I/O network server for Javascript

created by Ryan Dahl

sponsored by

Page 10: Node.js - async for the rest of us

Why Javascript?most widely used programing language of the web“never under estimate the power of familiarity and friendliness” - Stacey Higginbotham, GigaOM

async by nature - the browser is a single threaded event loop

BAH! It’s a toy language!

Page 11: Node.js - async for the rest of us

the event loopsingle threaded = no execution concurrencyall execution initiated by an eventevents may have zero to many callbacksevents are executed in orderTom Hughes-Croucher’s postman analogy

Page 12: Node.js - async for the rest of us

Installing nodemac, linux or windows (with cygwin hell)

fear not! stable windows support coming in v0.6.0 (~3wks)

# clone the git repogit clone git://github.com/joyent/node.gitcd node

# checkout the version you wantgit checkout v0.4.10

# build and install./configuremake && sudo make install

Page 13: Node.js - async for the rest of us

Running Node

REPL Read-Eval-Print-Loop

Invoke scriptnode app.js arg1 arg2

process.argv[0] === "node"process.argv[1] === "app.js"process.argv[2] === "arg1"process.argv[3] === "arg2"

~/ node> var x=1, y=2, z=3;> x+y+z6> require('fs').statSync('./blocking.js'){ dev: 234881026, ino: 3162208, mode: 33188, nlink: 1,.....

Page 14: Node.js - async for the rest of us

Hello World HTTP Server

var http = require('http');

http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n');}).listen(8080, "127.0.0.1");

console.log('Server running at http://127.0.0.1:8080/');

Page 15: Node.js - async for the rest of us

Not just HTTPvar net = require('net');

var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket);});

server.listen(1337, "127.0.0.1");

http://nodejs.org/

Page 16: Node.js - async for the rest of us

simple irc demo

Page 17: Node.js - async for the rest of us

Developing with Node

install nodeinstall npmyour favorite text editorSublime Text 2, Textmate, vim, Emacs, Eclipse, whatever

Page 18: Node.js - async for the rest of us

npmnode package manager

created by Isaac Schlueter (Joyent)

Page 19: Node.js - async for the rest of us

npm

publish, install, discover, and develop node programsputs modules in a place where node can find themmanages dependencies

Page 20: Node.js - async for the rest of us

npm search, install# install a module (copy to node_modules)npm install socket.io

# install a specific versionnpm install [email protected]

# install module globallynpm install socket.io -g

# searchnpm search socket

#infonpm info socket.io

Page 21: Node.js - async for the rest of us

npm registry

http://registry.npmjs.org/

Page 22: Node.js - async for the rest of us

npmjs.org stats

Page 23: Node.js - async for the rest of us

package.json{ "name": "express", "description": "Sinatra inspired web development framework", "version": "3.0.0", "author": "TJ Holowaychuk <[email protected]>", "contributors": [ { "name": "TJ Holowaychuk", "email": "[email protected]" }, { "name": "Aaron Heckmann", "email": "[email protected]" }, { "name": "Ciaran Jessup", "email": "[email protected]" }, { "name": "Guillermo Rauch", "email": "[email protected]" } ], "dependencies": { "connect": ">= 1.5.2 < 2.0.0", "mime": ">= 0.0.1", "qs": ">= 0.3.0" }, "devDependencies": { "connect-form": "0.2.1", "ejs": "0.4.2", "expresso": "0.8.1", "hamljs": "0.5.1", "jade": "0.13.0", "stylus": "0.13.0", "should": "0.2.1", "express-messages": "0.0.2", "node-markdown": ">= 0.0.1", "connect-redis": ">= 0.0.1" }, "keywords": ["framework", "sinatra", "web", "rest", "restful"], "repository": "git://github.com/visionmedia/express", "main": "index", "bin": { "express": "./bin/express" }, "scripts": { "test": "make test", "prepublish" : "npm prune" }, "engines": { "node": ">= 0.4.9 < 0.7.0" }}

Page 24: Node.js - async for the rest of us

npm install .package.json isn’t just for modules published to npm

npm can help you manage and install dependencies in any project

# from the same directory # as package.json npm install .

Page 25: Node.js - async for the rest of us

npm list~/ npm [email protected] /Users/mikebre/my_project!"# [email protected] invalid$ %"" [email protected] !"# [email protected] $ !"# [email protected] $ $ %"" [email protected] $ %"" [email protected] !"# [email protected] $ %"" [email protected] !"" [email protected] extraneous!"# [email protected] $ !"" [email protected] $ !"" [email protected] $ %"" [email protected] !"" [email protected] !"" [email protected] extraneous!"" [email protected] !"" [email protected] !"" [email protected] invalid%"# [email protected] %"" [email protected]

Page 26: Node.js - async for the rest of us

a very strong community

nodejs.orgGoogle Group mailing listIRC #node.js on freenodeStack Overflow, LinkedIn groupsnodeconf, node summercamp, etc.

Page 27: Node.js - async for the rest of us

debugging

ndb - command line debuggerEclipse debugger plugin for V8node-inspectoris very nice!

Page 28: Node.js - async for the rest of us

node-inspectoruses WebKit Web Inspector

# install with npmnpm -g install node-inspector

# start node-inspectornode-inspector &

# start node in debug modenode --debug app.js

Page 29: Node.js - async for the rest of us

profilingnode-inspector optionally supports the V8 profiler

collects CPU and heap snapshots

Speaking of heaps...

Page 30: Node.js - async for the rest of us

garbage collection--trace-gc option to watch GC behavior V8 is a VM --> must GC

tuned for the browser20Mb - 40Mb per tab

Large node heap sizes == :(

Page 31: Node.js - async for the rest of us

GC Demo

Page 32: Node.js - async for the rest of us

several popular node modules

http://splashinthepacific.files.wordpress.com/2010/10/looking-glass-721.jpg

Page 33: Node.js - async for the rest of us

ExpressSinatra (Ruby) inspired web framework

created by TJ Holowaychuk

Page 34: Node.js - async for the rest of us

Expressrequest routingcontent negotiationview templating and partialssession supportstatic file servingfast, clean and powerful

Page 35: Node.js - async for the rest of us

Express Demo

Page 36: Node.js - async for the rest of us

a RESTful service?cute, terse. boring

let’s do something a bit more interesting...

Page 37: Node.js - async for the rest of us

streaming demo

Page 38: Node.js - async for the rest of us

Socket.ioUnified API for Websockets + fallbacks

created by Guillermo Rauch

Page 39: Node.js - async for the rest of us

Socket.iounified API for Comet style appstransport negotiation server and client librariesfeature rich, above and beyond what the websocket protocol prescribesheartbeats, timeouts, namespacing, volatile messages, message acknowledgements, etc.

Page 40: Node.js - async for the rest of us

socket.io demo

Page 41: Node.js - async for the rest of us

Lessons from the trenches

Page 42: Node.js - async for the rest of us

asynchronous learning curve

app.get('/bar', function(req, res) { foo.fetchSomething(function(error, something) { if(!error) { foo.fetchSomeOne(something, function(error, someone) { if(!error) { foo.fetchBar(function(error, bar) { if(!error) { res.send("we got bar: " + bar); } else { res.send(error.statusCode); } }); } else { res.send(error.statusCode); } }); } else { res.send(error.statusCode); } }); });

easy to write code like this

Page 43: Node.js - async for the rest of us

uncaught errorson error, node emits an ‘error’ event on the corresponding objectif no listeners on object for ‘error’, a top level exception is raised and the process exits

process.on('uncaughtException', function(error) { console.log("Kaboom.... handle " + error);});

var server = http.createServer(function (req, res) {});server.on('error', function(error) { console.log("Caught error! Don't exit!");});

prudentapproach

nuclearapproach

>>

Page 44: Node.js - async for the rest of us

plan for multiple processes from the start

each node process is bound to one coremany small processes better than one big oneuse Clusterhttps://github.com/learnboost/cluster

var cluster = require('cluster');

cluster('app.js') .set('workers', 16) // defaults to # of cores .use(cluster.logger('logs')) .use(cluster.stats()) .use(cluster.cli()) .use(cluster.repl(8888)) .listen('80')

Page 45: Node.js - async for the rest of us

keep the heap small200Mb or less if you’re worried about GC pausemove data out of the node processinstead use Redis, MongoDb, etcencourages statelessness, encourages scalabilityreduces risk of losing a single node process

Page 47: Node.js - async for the rest of us

be weary of loopsfor (var i=0, l=entries.length; i<l; i++) { doSomething(entries[i]); }

innocent enough?

if # entries = 10,000

doSomething() takes ~1ms

you block for 10 seconds!

Page 48: Node.js - async for the rest of us

non-blocking loops// order mattersfunction processEntry(entries, index) { index = index || 0; if(index === entries.length) return done();

doSomething(entries[index]); process.nextTick(function() { processEntry(entries, index++) });}

processEntry(entries);

Page 49: Node.js - async for the rest of us

non-blocking loops// order doesn't mattervar leftToProcess = entries.length;

for (var i=0, l=entries.length; i<l; i++) { (function(foo) { process.nextTick(function() { doSomething(foo); if(--leftToProcess === 0) { done(); } }); })(entries[i]);}

Page 50: Node.js - async for the rest of us

non-blocking loops// order doesn't matter// doSomething takes callback and is Async// doSomethingAsync's happen in parallel var leftToProcess = entries.length;

// doSomething's will be executed in parallelfor (var i=0, l=entries.length; i<l; i++) { (function(foo) { process.nextTick(function() { doSomethingAsync(foo, function() { if(--leftToProcess === 0) { done(); } }); }); })(entries[i]);}

Page 51: Node.js - async for the rest of us

set ulimit -nnode can handles 1000’s of connections?

but your OS says... Too many open files

default # file descriptors on most linux systems is 10241 FD per socket means max open sockets < 1024 increase the max # of file descriptors

ulimit -n <max # FD>ulimit -a to see current max

Page 52: Node.js - async for the rest of us

pooled outbound connections

node pools outbound http(s) connections by default for host + port combinationsdefault concurrent maxSockets per host + port is 5is this what you want?

// for http as of node v0.4.10require ('http') .getAgent("api.twitter.com", 80) .maxSockets = 100;

// for https as of node v0.4.10require ('https') .getAgent({ host:"docs.google.com", port: 443 }) .maxSockets = 100;

Page 53: Node.js - async for the rest of us

timeoutsexpect that any callback could fail and may not be calledanticipate conditions where both inbound or outbound connections may hanguse Mikeal Roger’s ‘request’ moduleI contributed timeout functionalityshould be part of node core ~v0.7/0.8

Page 54: Node.js - async for the rest of us

offload anything computationally intensive

spawn a child processrequire('child_process').spawn

call out to another system more apt to handle heavy liftinguse a job queue

Page 55: Node.js - async for the rest of us

be specific with package dependencies

{ "name": "Foo Package", "description": "my Foo package", "version": "1.0.0", "author": "Mike Brevoort <[email protected]>", "dependencies": { "express": "2.3.2", "cluster": ">= 0.6.1", "mongodb": "0.9.x", "connect-gzip": "~0.1", "underscore": "= latest" }, "engines": { "node": "= 0.4.8" }}

is this what you really want? really?>

Page 56: Node.js - async for the rest of us

Let me tell you about my friend node

he’s a great multi-tasker but can only do one thing at a

time

Page 57: Node.js - async for the rest of us

Thank You!Questions?

Mike Brevoort@mbrevoortmike [at] brevoort [dot] com