efficient use of nodejs
TRANSCRIPT
Efficient use of NodeJS
Yuriy BogdanovInspiration-driven software engineer
My experience
• 10 years of web development
• 2009-2012 own projects
• 3 years of NodeJS on production, starting from earliest versions
• Full-stack-JS projects
Eventr, 2010
• Have ~70k RSS/Atom up to date
• Tricky TTL logic
• ~10 feeds per second (in peak)
• A lot of I/O, less CPU
• On PHP was a lot of processes, and a lot of redundancy
• http://habrahabr.ru/post/95526/
Eventr, 2010
• NodeJS v0.1.x
• Rewritten feeds updating on Node
• Performance x25 vs PHP
• Despite the newness of technology, it was successful
Tactoom, 2011
• Being inspired, I decided to write the next project completely on JS
• NodeJS v0.4.x
• It was a failure, the technology wasn’t justified in this context
• http://habrahabr.ru/post/130345/
NodeJS, 2012
• Successful experience with NodeJS
• Realtime solutions for IP-telephony
• Big data exchange on S3
Efficient use of NodeJS
• NodeJS is easy-going, but it's unpredictable outside of your laptop
• NodeJS though seems to be multipurpose, but for my opinion, has a rather narrow scope of effective usage
• You better not use NodeJS in cases where Ruby, PHP, etc. will do it easily
MythologyNode.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
(c) nodejs.org
Fast?
• V8 - yes, fast, but this speed is not the main bottleneck today
• non-blocking I/O - makes sense, if you really have a lot of I/O
A typical taskUser’s page
• Display a page with following data:
1. Posts
2. Following
3. Followers
Arithmetics
• db.getUserFeed()
• db.getUserFollowing()
• db.getUserFollowers()
I/O90%
CPU10%
Time
• I/O - query to DB
• CPU - handling data
Time:
User’s page:
ArithmeticsuserPageAction: function(callback) { db.getUserFeed(function(err, feed){ if (err) return callback(err); db.getUserFollowing(function(err, following){ if (err) return callback(err); db.getUserFollowers(function(err, followers){ if (err) return callback(err); callback(null, { feed: feed, following: following, followers: followers }); }); }); });}
50ms
30ms
40ms
~120ms
ArithmeticsuserPageAction: function(callback) { async.parallel({ feed: function(callback) { db.getUserFeed(callback); }, following: function(callback) { db.getUserFollowing(callback); }, followers: function(callback) { db.getUserFollowers(callback); } }, callback);}
node-asyncby Caolan McMahon
30ms
50ms
40ms
45 + 5 = 50ms
45 + 5
27 + 3
36 + 4
50ms
ArithmeticsuserPageAction: function() { var feed = db.getUserFeed.future(db), following = db.getUserFollowing.future(db), followers = db.getUserFollowers.future(db); return { feed: feed.yield(), following: following.yield(), followers: followers.yield() };}.async()
30ms50ms
40ms
node-syncby Yuriy Bogdanov
45 + 5 = 50ms
Arithmetics
120ms
I/O90%
CPU10%
Sequent ia l
I/O79%
CPU21%
Para l le l
50ms
CPU utilization
5 + 3 + 4 = 12ms
Arithmetics
CPU100%
ProductionYour laptop
I/O79%
CPU21%
While CPU is free,parallelism is efficient
Arithmetics concurrency
benchmark expected real
ab -n 1 -c 1 50ms 52ms
ab -n 100 -c 1 50ms 50ms
ab -n 100 -c 10 50ms
ab -n 100 -c 100 50ms
123msx2
981msx20
120ms x 8
CPU 21% ~ Response time
https://github.com/0ctave/node-bench
Arithmetics concurrency
CPU Response time Response time under load
21% 50ms 981ms
10% 120ms
ab -n 100 -c 100
1212ms+23%
http://www.slideshare.net/yurabogdanov/nodejs-8223169
Arithmetics PHP
CPU/IOthread
NodeJS
CPUthread
I/Othreads
Time
Arithmetics conclusions
• As more I/O part, as more profitable to use NodeJS
• And vice-versa :)
• Parallelism within a single request does nothing (under load)
• That is, synchronous Ruby have done better with given task
• But there are other problems...
Language & Platform• JavaScript is super flexible, which is not
always an advantage for the server technology
• There are many non-obvious nuances of the technology itself, which must always be considered
• In the absence of a clear convention it’s difficult to design a great app
getUserNetwork: function(callback) { var db = this.getDb(); userId = this.getSessionUserId();
db.getUserFollowing(userId, function(err, following){ if (err) return callback(err);
db.getUserFollowers(userId, function(err, followers){ if (err) return callback(err);
callback(null, { following: following, followers: followers }); }); });}
JavaScript
JavaScript
$ node --use_strict app.js
./node_modules/express/node_modules/debug/lib/debug.js:119 + ' +' + humanize(ms) + '\033[0m'
SyntaxError: Octal literals are not allowed in strict mode.
• CoffeeScript
• JSLint
• node --use_strict (starting from 0.9.х)
Language & Platform• monkey-patching is convenient, but it
leads to difficulties when debugging
• event emitter difficult to debug and it is often misused
• Difficult to avoid memory leaks, especially with the use of third-party libraries
• There is no decent way to debug, especially on production
Language & Platform
• No multi-user aspect
• Memory leaks is not a such problem
• Less async stuff
• Mature frameworks and standards
JavaScript is much easier on front-end:
Language & Platform
• One process serves many request at the time
• Therefore, the error in a single request can:
• lead to loss / collision of data
• hanging the hundreds of other requests
• compromise the integrity of the system
• No guaranteed isolation stack for each request / session (as, for example, in erlang)
Bad reliability
Language & Platform
CPU1 CPU2 CPU3 CPU4
Bad reliability
node1 node2 node3 node4
-250
connections1,000
http://mr-aleph.livejournal.com/322682.html
Shared state
• Very convenient for a sort of tasks
• Loses favor when scaling
• Difficult to make reliable
var counter = 0;app.get('/', function(req, res){ res.send('Counter: ' + counter); counter++;});
So what to do with NodeJS?
• Far from users as possible
• Where the load is predictable, where you can "pinch throat"
• I/O intensive, CPU free
• Do «kill -9» reliable
• have a persistence data layer
• do atomic operations
• use transactions when possible
• Not for a vital features
• Things you can not do without it
Yuriy Bogdanov
Thanks for your attention
http://about.me/bogdanovhttps://github.com/0ctavehttp://twitter.com/yuriybogdanovhttp://linkedin.com/in/yuriybogdanovhttp://octave.habrahabr.ru/
About.me:Github:Twitter:LinkedIn:Habrahabr:
Email: