nodejs的10个性能优化技巧


Posted in NodeJs onJuly 15, 2014

下面是我们使用Node.js时遵循的10个性能规则:

1. 避免使用同步代码

在设计上,Node.js是单线程的。为了能让一个单线程处理许多并发的请求,你可以永远不要让线程等待阻塞,同步或长时间运行的操作。Node.js的一个显著特征是:它从上到下的设计和实现都是为了实现异步。这让它非常适合用于事件型程序。

不幸的是,还是有可能会发生同步/阻塞的调用。例如,许多文件系统操作同时拥有同步和异步的版本,比如writeFile和writeFileSync。即使你用代码来控制同步方法,但还是有可能不注意地用到阻塞调用的外部函数库。当你这么做时,对性能的影响是极大的。

// Good: write files asynchronously
fs.writeFile('message.txt', 'Hello Node', function (err) {
 console.log("It's saved and the server remains responsive!");
});
 
// BAD: write files synchronously
fs.writeFileSync('message.txt', 'Hello Node');
console.log("It's saved, but you just blocked ALL requests!");

我们的初始化log在实现时无意地包含了一个同步调用来将内容写入磁盘。如果我们不做性能测试那么就会很容易忽略这个问题。当以developer box中一个node.js实例来作为标准测试,这个同步调用将导致性能从每秒上千次的请求降至只有几十个。

2.关闭套接字池

Node.js的http客户端会自动地使用套接字池:默认地,它会限制每台主机只能有5个套接字。虽然套接字的重复使用可能会让资源的增加在控制之下,但如果你需要处理许多数据来自于同一主机的并发请求时,将会导致一系列的瓶颈。在这种情况下,增大maxSockets 的值或关闭套接字池是个好主意:

// Disable socket pooling
 
var http = require('http');
var options = {.....};
options.agent = false;
var req = http.request(options)

3.不要让静态资源使用Node.js

对于css和图片等静态资源,用标准的WebServer而不是Node.js。例如,领英移动使用的是nginx。我们同时还利用内容传递网络(CDNs),它能将世界范围内的静态资拷贝到服务器上。这有两个好处:(1)能减少我们node.js服务器的负载量(2)CDNs可以让静态内容在离用户较近的服务器上传递,以此来减少等待时间。

4.在客户端渲染

让我们快速比较一下服务器渲染和客户端渲染的区别。如果我们用node.js在服务器端渲染,对于每个请求我们都会回送像下面这样的HTML页面:

<!-- 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>

请注意观察这个页面所有的内容,除了用户的名字,其余都是静态内容:对于每个用户和页面重载内容都是一样的。因此更有效的作法是让Node.js仅以JSON形式返回页面需要的动态内容。

{"name": "John"}
页面的其余部分—所有静态的HTML标记-能放在JavaScript模板中(比如underscore.js模板):

<!-- 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>

性能的提升来自于这些地方:如第三点所说,静态JavaScript模板能通过webserver(比如nginx)在服务器端提供,或者用更好的CDN来实现。此外,JavaScript模板能缓存在浏览器中或存储在本地,所有初始页面加载以后,唯一需要发送给客户端的数据就是JSON,这将是最有效果的。这个方法能极大性地减少CPU,IO,和Node.js的负载量。

5.使用gzip

nodejs的10个性能优化技巧

许多服务器和客户端支持gzip来压缩请求和应答。无论是应答客户端还是向远程服务器发送请求,请确保充分使用它。

6.并行化

nodejs的10个性能优化技巧

试着让你所有的阻塞操作-向远程服务发送请求,DB调用,文件系统访问并行化。这将能减少最慢的阻塞操作的等待时间,而不是所有阻塞操作的等待时间。为了保持回调和错误处理的干净,我们使用Step来控制流量。

7.Session自由化

领英移动使用Express框架来管理请求/应答周期。许多express的例子都包含如下的配置:

app.use(express.session({ secret: "keyboard cat" }));
默认地,session数据是存储在内存中的,这会给服务器增加巨大的开销,特别是随着用户量的增长。你可以使用一个外部session存储,比如MongoDB或Redis,不过每一个请求将会导致远程调用来取得session数据的开销。在可能的情况下,最好的选择就是在服务器端存储所有的无状态数据。通过不包含上述express配置让session自由化,你会看到更好的性能。

8.使用二进制模块

如果可能,用二进制模块取代JavaScript模块。例如,当我们从用JavaScript写的SHA模块转换到Node.js的编译版本,我们会看到性能的一个大跃进:

// Use built in or binary modules
var crypto = require('crypto');
var hash = crypto.createHmac("sha1",key).update(signatureBase).digest("base64");

9.用标准的 V8 JavaScript 取代客户端库

许多JavaScript库都是为了在web浏览器上使用而创建的,因为在JavaScript环境不同时:比如,一些浏览器支持forEach,map和reduce这样的函数,但有些浏览器不支持。因此客户端库通常用许多低效的代码来克服浏览器的差异。另一方面,在Node.js中,你能确切地知道哪些JavaScript方法是有效的:V8 JavaScript引擎支撑Node.js实现ECMA-262第五版中指定的ECMAScript。直接用标准的V8 JavaScript函数替代客户端库,你会发现性能得到显著的提高。

10.让你的代码保持小且轻

使用移动设备会让访问速度慢且延迟高,这告诉我们要让我们的代码保持小且轻。对于服务器代码也保持同样的理念。偶尔回头看看你的决定且问自己像这样的问题:“我们真的需要这个模块吗?”,“我们为什么用这个框架,它的开销值得我们使用吗?”,“我们能用简便的方法实现它吗?”。小轻且的代码通常更高效、快速。

试试看

我们很努力地让自己的移动应用变得快速。在IPhone应用,Android应用和HTML5移动版本这些平台上尝试一下,让我们知道自己做得怎么样。

NodeJs 相关文章推荐
基于NodeJS的前后端分离的思考与实践(五)多终端适配
Sep 26 NodeJs
Nodejs中读取中文文件编码问题、发送邮件和定时任务实例
Jan 01 NodeJs
浅谈Nodejs观察者模式
Oct 13 NodeJs
nodeJs内存泄漏问题详解
Sep 05 NodeJs
nodejs模块nodemailer基本使用-邮件发送示例(支持附件)
Mar 28 NodeJs
深入浅析Nodejs的Http模块
Jun 20 NodeJs
NodeJS链接MySql数据库的操作方法
Jun 27 NodeJs
原生nodejs使用websocket代码分享
Apr 07 NodeJs
详解Nodejs mongoose
Jun 10 NodeJs
nodejs 十六进制字符串型数据与btye型数据相互转换
Jul 30 NodeJs
Nodejs中获取当前函数被调用的行数及文件名详解
Dec 12 NodeJs
nodejs实现百度舆情接口应用示例
Feb 07 NodeJs
提高NodeJS中SSL服务的性能
Jul 15 #NodeJs
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
Jul 15 #NodeJs
nodejs 实现模拟form表单上传文件
Jul 14 #NodeJs
14款NodeJS Web框架推荐
Jul 11 #NodeJs
基于promise.js实现nodejs的promises库
Jul 06 #NodeJs
我的NodeJs学习小结(一)
Jul 06 #NodeJs
nodejs中使用monk访问mongodb
Jul 06 #NodeJs
You might like
乱谈我对耳机、音箱的感受
2021/03/02 无线电
firefox火狐浏览器与与ie兼容的2个问题总结
2010/07/20 Javascript
自动刷新网页,自动刷新当前页面,JS调用
2013/06/24 Javascript
firefox浏览器不支持innerText的解决方法
2013/08/07 Javascript
jQuery中get()方法用法实例
2014/12/27 Javascript
Bootstrap对话框使用实例讲解
2016/09/24 Javascript
jQueryUI 拖放排序遇到滚动条时有可能无法执行排序的小bug及解决方案
2016/12/19 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
详解node.js中的npm和webpack配置方法
2018/01/21 Javascript
JavaScript实现一个简易的计算器实例代码
2018/05/10 Javascript
Puppeteer 爬取动态生成的网页实战
2018/11/14 Javascript
vue-router实现编程式导航的代码实例
2019/01/19 Javascript
原生JS检测CSS3动画是否结束的方法详解
2019/01/27 Javascript
vue中的过滤器及其时间格式化问题
2020/04/09 Javascript
Jquery高级应用Deferred对象原理及使用实例
2020/05/28 jQuery
解决vue页面渲染但dom没渲染的操作
2020/07/27 Javascript
微信小程序实现可拖动悬浮图标(包括按钮角标的实现)
2020/12/29 Javascript
[38:41]2014 DOTA2国际邀请赛中国区预选赛 LGD VS CNB
2014/05/22 DOTA
[38:38]完美世界DOTA2联赛PWL S3 access vs Rebirth 第二场 12.17
2020/12/18 DOTA
Python字符串格式化输出方法分析
2016/04/13 Python
Python实现PS滤镜碎片特效功能示例
2018/01/24 Python
使用Python进行AES加密和解密的示例代码
2018/02/02 Python
python添加模块搜索路径和包的导入方法
2019/01/19 Python
pandas 数据结构之Series的使用方法
2019/06/21 Python
python计算n的阶乘的方法代码
2019/10/25 Python
Python3.7下安装pyqt5的方法步骤(图文)
2020/05/12 Python
Python如何在windows环境安装pip及rarfile
2020/06/15 Python
美国儿童玩具、装扮和玩偶商店:Magic Cabin
2018/09/02 全球购物
俄罗斯家居用品购物网站:Евродом
2020/11/21 全球购物
优秀实习自我鉴定
2013/12/04 职场文书
小学生考试获奖感言
2014/01/30 职场文书
毕业生实习期转正自我鉴定
2014/09/26 职场文书
简易离婚协议书范本
2014/10/24 职场文书
《山中访友》教学反思
2016/02/24 职场文书
旅游安全责任协议书
2016/03/22 职场文书
python中urllib包的网络请求教程
2022/04/19 Python