Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Node.js Async for the Rest of Us

Node.js Async for the Rest of Us

As presented at the Denver Open Source Users Group August 2011

7071119714e1a32441aca0c336657d3e?s=128

Mike Brevoort

March 06, 2012
Tweet

Transcript

  1. node.js asynchronous... for the rest of us Mike Brevoort code

    sample can be found at https://github.com/mbrevoort/node.js-presentation 1
  2. agenda the case for node.js developing with node look at

    a few popular modules lessons from the trenches 2
  3. 3

  4. 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 4
  5. typical i/o latency L1: 3 cycles L2: 14 cycles RAM:

    250 cycles DISK: 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 5
  6. http://xach.livejournal.com/ 170311.html 6

  7. “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/ 7
  8. node.js An Evented I/O network server for Javascript created by

    Ryan Dahl sponsored by 8
  9. http://platformjs.wordpress.com/2010/11/24/node-js-under- the-hood/ Runs Javascript, but isn’t primarily Javascript 9

  10. 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 10
  11. 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! 10
  12. the event loop single threaded = no execution concurrency all

    execution initiated by an event events may have zero to many callbacks events are executed in order 11
  13. Installing node mac, linux or windows (with cygwin hell) fear

    not! stable windows support coming in v0.6.0 (any day)... BUT # clone the git repo git clone git://github.com/joyent/node.git cd node # checkout the version you want git checkout v0.4.10 # build and install ./configure make && sudo make install 12
  14. Running Node REPL Read-Eval-Print-Loop Invoke script node 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+z 6 > require('fs').statSync('./blocking.js') { dev: 234881026, ino: 3162208, mode: 33188, nlink: 1, ..... 13
  15. 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/'); 14
  16. Not just HTTP var 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/ 15
  17. simple irc demo 16

  18. Developing with Node install node install npm your favorite text

    editor Sublime Text 2, Textmate, vim, Emacs, Eclipse, whatever 17
  19. npm node package manager created by Isaac Schlueter (Joyent) 18

  20. npm publish, install, discover, and develop node programs puts modules

    in a place where node can find them manages dependencies 19
  21. npm search, install # install a module (copy to node_modules)

    npm install socket.io # install a specific version npm install socket.io@0.6.0 # install module globally npm install socket.io -g # search npm search socket #info npm info socket.io 20
  22. npm registry http://registry.npmjs.org/ 21

  23. npmjs.org stats 22

  24. package.json { "name": "express", "description": "Sinatra inspired web development framework",

    "version": "3.0.0", "author": "TJ Holowaychuk <tj@vision-media.ca>", "contributors": [ { "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" }, { "name": "Aaron Heckmann", "email": "aaron.heckmann+github@gmail.com" }, { "name": "Ciaran Jessup", "email": "ciaranj@gmail.com" }, { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" } ], "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" } } 23
  25. 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 . 24
  26. npm list ~/ npm list my_project@0.1.0 /Users/mikebre/my_project !"# cluster@0.6.9 invalid

    $ %"" log@1.2.0 !"# connect-gzip@0.1.0 $ !"# connect@1.4.6 $ $ %"" qs@0.1.0 $ %"" mime@1.2.2 !"# date@1.0.1 $ %"" require-kiss@1.0.5 !"" docco@0.3.0 extraneous !"# express@2.3.2 $ !"" connect@1.4.6 $ !"" mime@1.2.2 $ %"" qs@0.1.0 !"" hbs@0.0.7 !"" log@1.1.0 extraneous !"" metrics@0.1.1 !"" request-forked@1.9.8 !"" semver@1.0.6 invalid %"# xml2js@0.1.6 %"" sax@0.1.4 25
  27. Public NPM Private NPM NPM Proxy back at the ranch...

    26
  28. Public NPM Private NPM NPM Proxy GETs back at the

    ranch... 26
  29. Public NPM Private NPM NPM Proxy 1 GETs back at

    the ranch... 26
  30. Public NPM Private NPM NPM Proxy 1 2 GETs back

    at the ranch... 26
  31. Public NPM Private NPM NPM Proxy 1 2 GETs publish

    search back at the ranch... 26
  32. Public NPM Private NPM NPM Proxy 1 2 GETs publish

    search search back at the ranch... 26
  33. Public NPM Private NPM NPM Proxy 1 2 GETs publish

    search search http://npm.petdev.com:9000 back at the ranch... 26
  34. Public NPM Private NPM NPM Proxy 1 2 GETs publish

    search search http://npm.petdev.com:9000 http://npm.petdev.com:5984 back at the ranch... 26
  35. a very strong community nodejs.org Google Group mailing list IRC

    #node.js on freenode Stack Overflow, LinkedIn groups nodeconf, node summercamp, etc. 27
  36. debugging ndb - command line debugger Eclipse debugger plugin for

    V8 node-inspector is very nice! 28
  37. node-inspector uses WebKit Web Inspector # install with npm npm

    -g install node-inspector # start node-inspector node-inspector & # start node in debug mode node --debug app.js 29
  38. node-inspector uses WebKit Web Inspector # install with npm npm

    -g install node-inspector # start node-inspector node-inspector & # start node in debug mode node --debug app.js 29
  39. profiling node-inspector optionally supports the V8 profiler collects CPU and

    heap snapshots Speaking of heaps... 30
  40. garbage collection --trace-gc option to watch GC behavior V8 is

    a VM --> must GC tuned for the browser 20Mb - 40Mb per tab Large node heap sizes == :( 31
  41. GC Demo 32

  42. several popular node modules http://splashinthepacific.files.wordpress.com/2010/10/looking-glass-721.jpg 33

  43. Express Sinatra (Ruby) inspired web framework created by TJ Holowaychuk

    34
  44. Express request routing content negotiation view templating and partials session

    support static file serving fast, clean and powerful 35
  45. Express Demo 36

  46. Express Demo 36

  47. a RESTful service? cute, terse. boring let’s do something a

    bit more interesting... 37
  48. streaming demo 38

  49. Socket.io Unified API for Websockets + fallbacks created by Guillermo

    Rauch 39
  50. Socket.io unified API for Comet style apps transport negotiation server

    and client libraries feature rich, above and beyond what the websocket protocol prescribes heartbeats, timeouts, namespacing, volatile messages, message acknowledgements, etc. 40
  51. socket.io demo 41

  52. Lessons from the trenches 42

  53. 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 43
  54. uncaught errors on error, node emits an ‘error’ event on

    the corresponding object if 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!"); }); prudent approach nuclear approach > > 44
  55. plan for multiple processes from the start each node process

    is bound to one core many small processes better than one big one use Cluster https://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') 45
  56. keep the heap small 200Mb or less if you’re worried

    about GC pause move data out of the node process instead use Redis, MongoDb, etc encourages statelessness, encourages scalability reduces risk of losing a single node process 46
  57. everything you do blocks http://redriverpak.files.wordpress.com/ 2010/08/vwtouareg-road-block.jpg 47

  58. everything you do blocks No CPU for you! http://redriverpak.files.wordpress.com/ 2010/08/vwtouareg-road-block.jpg

    47
  59. everything you do blocks No CPU for you! http://redriverpak.files.wordpress.com/ 2010/08/vwtouareg-road-block.jpg

    47
  60. be weary of loops for (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! 48
  61. non-blocking loops // order matters function processEntry(entries, index) { index

    = index || 0; if(index === entries.length) return done(); doSomething(entries[index]); process.nextTick(function() { processEntry(entries, index++) }); } processEntry(entries); 49
  62. non-blocking loops // order doesn't matter var 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]); } 50
  63. 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 parallel for (var i=0, l=entries.length; i<l; i++) { (function(foo) { process.nextTick(function() { doSomethingAsync(foo, function() { if(--leftToProcess === 0) { done(); } }); }); })(entries[i]); } 51
  64. set ulimit -n node can handles 1000’s of connections? but

    your OS says... Too many open files default # file descriptors on most linux systems is 1024 1 FD per socket means max open sockets < 1024 increase the max # of file descriptors ulimit -n <max # FD> ulimit -a to see current max 52
  65. pooled outbound connections node pools outbound http(s) connections by default

    for host + port combinations default concurrent maxSockets per host + port is 5 is this what you want? // for http as of node v0.4.10 require ('http') .getAgent("api.twitter.com", 80) .maxSockets = 100; // for https as of node v0.4.10 require ('https') .getAgent({ host:"docs.google.com", port: 443 }) .maxSockets = 100; 53
  66. timeouts expect that any callback could fail and may not

    be called anticipate conditions where both inbound or outbound connections may hang use Mikeal Roger’s ‘request’ module I contributed timeout functionality should be part of node core ~v0.7/0.8 54
  67. offload anything computationally intensive spawn a child process require('child_process').spawn call

    out to another system more apt to handle heavy lifting use a job queue 55
  68. be specific with package dependencies { "name": "Foo Package", "description":

    "my Foo package", "version": "1.0.0", "author": "Mike Brevoort <mikebre@ecollege.com>", "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? > 56
  69. Thank You! Questions? 58