node.js - async for the rest of us
DESCRIPTION
presented at the Denver Open Source Users Group 8/2/2011TRANSCRIPT
![Page 1: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/1.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/2.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/3.jpg)
![Page 4: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/4.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/5.jpg)
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 6: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/6.jpg)
http://xach.livejournal.com/170311.html
![Page 7: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/7.jpg)
“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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/8.jpg)
node.jsAn Evented I/O network server for Javascript
created by Ryan Dahl
sponsored by
![Page 9: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/9.jpg)
http://platformjs.wordpress.com/2010/11/24/node-js-under-the-hood/
Runs Javascript, but isn’t primarily Javascript
![Page 10: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/10.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/11.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/12.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/13.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/14.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/15.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/16.jpg)
simple irc demo
![Page 17: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/17.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/18.jpg)
npmnode package manager
created by Isaac Schlueter (Joyent)
![Page 19: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/19.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/20.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/21.jpg)
npm registry
http://registry.npmjs.org/
![Page 22: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/22.jpg)
npmjs.org stats
![Page 23: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/23.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/24.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/25.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/26.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/27.jpg)
debugging
ndb - command line debuggerEclipse debugger plugin for V8node-inspectoris very nice!
![Page 28: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/28.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/29.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/30.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/31.jpg)
GC Demo
![Page 32: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/32.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/33.jpg)
ExpressSinatra (Ruby) inspired web framework
created by TJ Holowaychuk
![Page 34: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/34.jpg)
Expressrequest routingcontent negotiationview templating and partialssession supportstatic file servingfast, clean and powerful
![Page 35: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/35.jpg)
Express Demo
![Page 36: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/36.jpg)
a RESTful service?cute, terse. boring
let’s do something a bit more interesting...
![Page 37: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/37.jpg)
streaming demo
![Page 38: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/38.jpg)
Socket.ioUnified API for Websockets + fallbacks
created by Guillermo Rauch
![Page 39: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/39.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/40.jpg)
socket.io demo
![Page 41: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/41.jpg)
Lessons from the trenches
![Page 42: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/42.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/43.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/44.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/45.jpg)
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 46: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/46.jpg)
everything you do blocksNo CPU for YOU!
http://redriverpak.files.wordpress.com/2010/08/vwtouareg-road-block.jpg
![Page 47: Node.js - async for the rest of us](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/47.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/48.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/49.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/50.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/51.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/52.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/53.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/54.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/55.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/56.jpg)
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](https://reader036.vdocuments.us/reader036/viewer/2022062300/5557d572d8b42af2178b4d6e/html5/thumbnails/57.jpg)
Thank You!Questions?
Mike Brevoort@mbrevoortmike [at] brevoort [dot] com