Blazing fast node.js: 10 performance tips from LinkedIn Mobile
2011-12-06 22:50
543 查看
In a previous post, we discussed how we test LinkedIn's mobile stack, including our Node.js mobile
server. Today, we’ll tell you how we make this mobile server fast. Here are our top 10 performance takeaways for working with Node.js:
By design, Node.js is single threaded. To allow a single thread to handle many concurrent requests, you can never allow the thread to wait on a blocking, synchronous, or long running operation. A distinguishing feature of Node.js is that it was designed and
implemented from top to bottom to be asynchronous. This makes it an excellent fit for evented applications.
Unfortunately, it is still possible to make synchronous/blocking calls. For example, many file system operations have both asynchronous and synchronous versions, such as writeFile and writeFileSync.
Even if you avoid synchronous methods in your own code, it's still possible to inadvertently use an external library that has a blocking call. When you do, the impact on performance is dramatic.
view rawSynchronous.jsThis
Gist brought to you by GitHub.
Our initial logging implementation accidentally included a synchronous call to write to disc. This went unnoticed until we did performance testing. When benchmarking a single instance of Node.js on a developer box, this one synchronous call caused a performance
drop from thousands of requests per second to just a few dozen!
The Node.js http client automatically uses socket pooling: by default, this
limits you to 5 sockets per host. While the socket reuse may keep resource growth under control, it will be a serious bottleneck if you need to handle many concurrent requests that all need data from the same host. In these scenarios, it's a good idea
to increase maxSockets or
entirely disable socket pooling:
view rawDisableSocketPooling.jsThis
Gist brought to you by GitHub.
For static assets, such as CSS and images, use a standard webserver instead of Node.js. For example, LinkedIn mobile uses nginx. We also take advantage of Content
Delivery Networks (CDNs), which copy the static assets to servers around the world. This has two benefits: (1) we reduce load on our Node.js servers and (2) CDNs allow static content to be delivered from a server close to the user, which reduces latency.
Let's quickly compare rendering a page server-side vs. client-side. If we have Node.js render server-side, we'll send back an HTML page like this for every request:
view rawServerSideRenderedHTML.htmlThis
Gist brought to you by GitHub.
Note that everything on this page, except for the user's name, is static: that is, it's identical for every user and page reload. So a much more efficient approach is to have Node.js return just the dynamic data needed for the page as JSON:
view rawReturnJustJson.jsThis
Gist brought to you by GitHub.
The rest of the page - all the static HTML markup - can be put into a JavaScript template (such as anunderscore.js template):
view rawJavaScriptTemplate.htmlThis
Gist brought to you by GitHub.
Here's where the performance benefit comes in: as per tip #3, the static JavaScript
template can be served from your webserver (e.g. nginx) and, even better, from a CDN. Moreover, JavaScript templates can be cached in the browser or saved in LocalStorage, so after the initial page load, the only data sent to the client is the dynamic
JSON, which is maximally efficient. This approach dramatically reduces the CPU, IO, and load on Node.js.
Most servers and clients support gzip to compress requests and responses. Make sure you take advantage of it, both when responding to clients and when making
requests to remote servers:
Try to do all your blocking operations - that is, requests to remote services, DB calls, and file system access - in parallel. This will reduce latency to the slowest of the blocking operations rather than the sum of each one in sequence. To keep the callbacks
and error handling clean, we use Step for flow control.
LinkedIn mobile uses the Express framework to manage the request/response cycle. Most express examples include the following configuration:
view rawExpressSession.jsThis
Gist brought to you by GitHub.
By default, session data is stored in memory, which can add significant overhead to the server, especially as the number of users
grows. You could switch to an external session store, such as MongoDB or Redis, but then each request incurs the overhead of a remote call to fetch session data. Where possible, the best option is to store no state on the server-side at all. Go session free
by NOT including the express config above and you'll see better performance.
When available, use binary modules instead of JavaScript modules. For example, when we switched from a SHA module written in JavaScript to the compiled version that comes with Node.js, we saw a big performance bump:
view rawBinaryModules.jsThis
Gist brought to you by GitHub.
Most JavaScript libraries are built for use in a web browser, where the JavaScript environment is inconsistent: for example, one browser may support functions like forEach, map and reduce,
but other browsers don't. As a result, client-side libraries usually have a lot of inefficient code to overcome browser differences. On the other hand, in Node.js, you know exactly what JavaScript functions are available: the V8
JavaScript engine that powers Node.js implements ECMAScript as specified inECMA-262, 5th edition.
By directly using the standard V8 functions instead of client libraries, you may see significant performance gains.
Working with mobile, where devices are slower and latencies are higher, teaches you to keep your code small and light. Apply this same idea to your server code as well. Revisit your decisions from time to time and ask yourself questions like: “Do we really
need this module?”, “Why are we using this framework? Is it worth the overhead?”, “Can we do this in a simpler way?”. Smaller, lighter code is usually more efficient and faster.
We worked hard to make our mobile apps fast. Try them out and let us know how we did: we have aniPhone app, Android
app and an HTML5 mobile version.
原文地址:http://engineering.linkedin.com/nodejs/blazing-fast-nodejs-10-performance-tips-linkedin-mobile
server. Today, we’ll tell you how we make this mobile server fast. Here are our top 10 performance takeaways for working with Node.js:
1. Avoid synchronous code
By design, Node.js is single threaded. To allow a single thread to handle many concurrent requests, you can never allow the thread to wait on a blocking, synchronous, or long running operation. A distinguishing feature of Node.js is that it was designed andimplemented from top to bottom to be asynchronous. This makes it an excellent fit for evented applications.
Unfortunately, it is still possible to make synchronous/blocking calls. For example, many file system operations have both asynchronous and synchronous versions, such as writeFile and writeFileSync.
Even if you avoid synchronous methods in your own code, it's still possible to inadvertently use an external library that has a blocking call. When you do, the impact on performance is dramatic.
// Good: write files asynchronouslyfs.writeFile('message.txt', 'Hello Node', function (err) { console.log("It's saved and the server remains responsive!");}); // BAD: write files synchronouslyfs.writeFileSync('message.txt', 'Hello Node');console.log("It's saved, but you just blocked ALL requests!");
view rawSynchronous.jsThis
Gist brought to you by GitHub.
Our initial logging implementation accidentally included a synchronous call to write to disc. This went unnoticed until we did performance testing. When benchmarking a single instance of Node.js on a developer box, this one synchronous call caused a performance
drop from thousands of requests per second to just a few dozen!
2. Turn off socket pooling
The Node.js http client automatically uses socket pooling: by default, thislimits you to 5 sockets per host. While the socket reuse may keep resource growth under control, it will be a serious bottleneck if you need to handle many concurrent requests that all need data from the same host. In these scenarios, it's a good idea
to increase maxSockets or
entirely disable socket pooling:
// Disable socket pooling var http = require('http');var options = {.....};options.agent = false;var req = http.request(options)
view rawDisableSocketPooling.jsThis
Gist brought to you by GitHub.
3. Don't use Node.js for static assets
For static assets, such as CSS and images, use a standard webserver instead of Node.js. For example, LinkedIn mobile uses nginx. We also take advantage of ContentDelivery Networks (CDNs), which copy the static assets to servers around the world. This has two benefits: (1) we reduce load on our Node.js servers and (2) CDNs allow static content to be delivered from a server close to the user, which reduces latency.
4. Render on the client-side
Let's quickly compare rendering a page server-side vs. client-side. If we have Node.js render server-side, we'll send back an HTML page like this for every request:<!-- An example of a simple webpage rendered entirely server side --> <!DOCTYPE html><html> <head> <title>LinkedIn Mobile</title> </head> <body> <div class="header"> <img src="http://mobile-cdn.linkedin.com/images/linkedin.png" alt="LinkedIn"/> </div> <div class="body"> Hello John! </div> </body></html>
view rawServerSideRenderedHTML.htmlThis
Gist brought to you by GitHub.
Note that everything on this page, except for the user's name, is static: that is, it's identical for every user and page reload. So a much more efficient approach is to have Node.js return just the dynamic data needed for the page as JSON:
{"name": "John"}
view rawReturnJustJson.jsThis
Gist brought to you by GitHub.
The rest of the page - all the static HTML markup - can be put into a JavaScript template (such as anunderscore.js template):
<!-- An example of a JavaScript template that can be rendered client side --> <!DOCTYPE html><html> <head> <title>LinkedIn Mobile</title> </head> <body> <div class="header"> <img src="http://mobile-cdn.linkedin.com/images/linkedin.png" alt="LinkedIn"/> </div> <div class="body"> Hello <%= name %>! </div> </body></html>
view rawJavaScriptTemplate.htmlThis
Gist brought to you by GitHub.
Here's where the performance benefit comes in: as per tip #3, the static JavaScript
template can be served from your webserver (e.g. nginx) and, even better, from a CDN. Moreover, JavaScript templates can be cached in the browser or saved in LocalStorage, so after the initial page load, the only data sent to the client is the dynamic
JSON, which is maximally efficient. This approach dramatically reduces the CPU, IO, and load on Node.js.
5. Use gzip
Most servers and clients support gzip to compress requests and responses. Make sure you take advantage of it, both when responding to clients and when makingrequests to remote servers:
6. Go parallel
Try to do all your blocking operations - that is, requests to remote services, DB calls, and file system access - in parallel. This will reduce latency to the slowest of the blocking operations rather than the sum of each one in sequence. To keep the callbacksand error handling clean, we use Step for flow control.
7. Go session-free
LinkedIn mobile uses the Express framework to manage the request/response cycle. Most express examples include the following configuration:app.use(express.session({ secret: "keyboard cat" }));
view rawExpressSession.jsThis
Gist brought to you by GitHub.
By default, session data is stored in memory, which can add significant overhead to the server, especially as the number of users
grows. You could switch to an external session store, such as MongoDB or Redis, but then each request incurs the overhead of a remote call to fetch session data. Where possible, the best option is to store no state on the server-side at all. Go session free
by NOT including the express config above and you'll see better performance.
8. Use binary modules
When available, use binary modules instead of JavaScript modules. For example, when we switched from a SHA module written in JavaScript to the compiled version that comes with Node.js, we saw a big performance bump:// Use built in or binary modulesvar crypto = require('crypto');var hash = crypto.createHmac("sha1",key).update(signatureBase).digest("base64");
view rawBinaryModules.jsThis
Gist brought to you by GitHub.
9. Use standard V8 JavaScript instead of client-side libraries
Most JavaScript libraries are built for use in a web browser, where the JavaScript environment is inconsistent: for example, one browser may support functions like forEach, map and reduce,but other browsers don't. As a result, client-side libraries usually have a lot of inefficient code to overcome browser differences. On the other hand, in Node.js, you know exactly what JavaScript functions are available: the V8
JavaScript engine that powers Node.js implements ECMAScript as specified inECMA-262, 5th edition.
By directly using the standard V8 functions instead of client libraries, you may see significant performance gains.
10. Keep your code small and light
Working with mobile, where devices are slower and latencies are higher, teaches you to keep your code small and light. Apply this same idea to your server code as well. Revisit your decisions from time to time and ask yourself questions like: “Do we reallyneed this module?”, “Why are we using this framework? Is it worth the overhead?”, “Can we do this in a simpler way?”. Smaller, lighter code is usually more efficient and faster.
Try it out
We worked hard to make our mobile apps fast. Try them out and let us know how we did: we have aniPhone app, Androidapp and an HTML5 mobile version.
原文地址:http://engineering.linkedin.com/nodejs/blazing-fast-nodejs-10-performance-tips-linkedin-mobile
相关文章推荐
- 翻译--Blazing fast node.js: 10 performance tips from LinkedIn Mobile
- 翻译--Blazing fast node.js: 10 performance tips from LinkedIn Mobile
- 高性能Node.js:来自LinkedIn Mobile的10条优化建议
- node.js在windows下的学习笔记(10)---URL模块
- 夺命雷公狗---node.js---10之POST的接收
- 10 Tips to Improve your LINQ to SQL Application Performance
- 转 10 个最佳的 Node.js 的 MVC 框架
- No. 10 - K-th Node from End
- 10 tips for advancing from a beginner to an intermediate developer(转)
- Node.js howto: make asynchronous callback from thread
- Felix's Node.js Style Guide——from http://nodeguide.com/index.html
- 10 Tips to Improve an ASP.NET Applications Performance
- 【Node.js】mongoose教程10--聚合(Aggregation)的应用
- Top 10 Performance Problems taken from Zappos, Monster, Thomson and Co
- 46 Tips & Tricks for 2D mobile Performance in Unity
- 10node.js工具类util.inherits和util.inspect
- Tips for optimizing mobile graphic performance
- 极速Node.js:来自LinkedIn的10个性能提升秘籍
- Node.js 应用跑得更快 10 个技巧
- 10 款不错的 Node.js 框架