你所未知的3种Node.js代码优化方式


Posted in Javascript onFebruary 25, 2016

Node.js 程序的运行可能会受 CPU 或输入输出操作的限制而十分缓慢。从 CPU 角度看,程序运行缓慢的典型原因之一就是未经优化的「热点路径」(一段经常被访问的代码)。从输入输出角度看,程序运行速度的局限可能是受底层操作系统影响,也可能是出于 Node 本身的故障。更或者,一个运行缓慢的程序可能跟 Node 本身没有任何关系,问题在于外部资源,比如数据库查询或是 API 调用缓慢,未经过优化处理。

在本文中,我们将重点识别并优化代码库中会导致 CPU 繁重运行的操作。同时,将探讨生产应用的配置文件,分析并作出可提高运作效率的改动。

由于 Node 的单线程性质,避免繁重的 CPU 负载对服务器来说尤为重要。因为在 CPU 上消耗的时间会占用响应其他请求的时间。如果你注意到自己的应用响应速度缓慢,而且 CPU 在这个过程中始终占用率较高,分析你的程序有助于找出瓶颈,并且使程序恢复快速运行的状态。

分析应用
复制生产环境中出现的缓慢程序问题非常难解决,而且十分耗时。值得庆幸的是,你不需要亲自做这些了。你可以在生产服务器上收集配置文件数据,然后离线分析。下面让我们来看一下几种分析方法。

1、使用内核级工具
首先,你可以使用内核级工具,比如 DTrace(Solaris, BSD),perf(Linux),或者 XPerf(Windows),从运行的进程中收集堆栈跟踪信息,然后生成火焰图。内核级分析对运行中的进程影响最小。火焰图是根据调用栈生成的支持放大缩小查看的向量图形。来自 Netflix 公司的 Yunong Xiao 针对 Linux 系统中 perf,发表过超赞的演讲和推文,帮助你加深对该技术的了解。如果你想在生产程序中保持高吞吐量,可以参考使用这种方法。

你所未知的3种Node.js代码优化方式2、

2、使用 V8 分析器
另一个选项是直接使用 V8 分析器。这种方式会与程序共享进程,因此它会影响程序性能。基于这个原因,请只在你遇到此类问题时运行 V8 分析器来捕获相关输出。该方法的好处是:你可以使用 Chrome 的所有分析工具,结合其输出结果(包括火焰图),对程序进行调查。

请运行以下代码来测试你的程序:

npm install v8-profiler --save

之后,在你的程序中添加以下代码:

const profiler = require('v8-profiler')
const fs = require('fs')
var profilerRunning = false
function toggleProfiling () {
 if (profilerRunning) {
  const profile = profiler.stopProfiling()
  console.log('stopped profiling')
  profile.export()
   .pipe(fs.createWriteStream('./myapp-'+Date.now()+'.cpuprofile'))
   .once('error', profiler.deleteAllProfiles)
   .once('finish', profiler.deleteAllProfiles)
  profilerRunning = false
  return
 }
 profiler.startProfiling()
 profilerRunning = true
 console.log('started profiling')
}
process.on('SIGUSR2', toggleProfiling)

只要你发送 SIGUSR2 信号到此进程,它就会开始分析。再次发送一个 SIGUSR2 信号可以停止分析(代码如下)。

kill -SIGUSR2 [pid]

该进程的分析结果将被写入到当前工作路径的文件中(请确保该路径可被写入)。由于这是一个可编程接口,你可以随意触发它(使用 web endpoint,IPC,等等)。如果你对程序在何时变得缓慢有预感,你可以在任一时期触发该接口。建立自动触发对避免持续监看程序是非常有用的,但是它要求你对捕获时间以及捕获时长有预测性认知。

一旦已经收集好配置文件数据,将它加载到Chrome开发工具中,开始分析吧!

你所未知的3种Node.js代码优化方式

3、使用进程管理器
尽管直接使用 V8 分析器是非常有效且可定制的,但是它会进入你的代码库,并且会向项目添加又一项你可能不想要的依赖性条件。一种替代方式就是使用进程管理器,它可以在你需要分析时,用各种工具将你的程序包装起来。一种可选的工具是来自 StrongLoop 的 SLC 命令行工具。

首先,运行npm install strongloop ?g,然后运行以下代码:

slc start [/path/to/app]

上述代码会在进程管理器中启动你的程序,你可以按需提取 CPU 分析数据。要想验证并获取应用程序 id,请运行:

slc ctl

你将得到与下面类似的运行结果:

Service ID: 1
Service Name: my-sluggish-app
Environment variables:
  Name   Value
  NODE_ENV production
Instances:
  Version Agent version Debugger version Cluster size Driver metadata
   5.0.1    2.0.2      1.0.0       1       N/A
Processes:
    ID   PID  WID Listening Ports Tracking objects? CPU profiling? Tracing? Debugging?
  1.1.61022 61022  0
  1.1.61023 61023  1   0.0.0.0:3000

定位应用的进程 id。在此例中,id 为1.1.61023。现在我们就能在任意时间开始分析了,运行如下代码即可:

slc ctl cpu-start 1.1.61023

当我们觉得已经捕获到了迟滞行为,就可以运行以下代码来停止分析器:

slc ctl cpu-stop 1.1.61023

以下代码将写文件至硬盘:

CPU profile written to `node.1.1.61023.cpuprofile`, load into Chrome Dev Tools

好啦,就是这样。你可以像在 V8 分析器里那样把文件加载到 Chrome 里面进一步分析。

作出正确决定
在本文中,笔者展示了三种在 Node 中捕获生产环境下 CPU 使用量的方式。那么,你应该选用哪一种呢?下面是一些帮助你缩小决策范围的想法:

  • 我需要分析很长一段时间:使用内核级工具。
  • 我想用 Chrome 开发工具:使用 V8 分析器或者过程管理器。
  • 我想捕获应用中的特定行为:使用 V8 分析器。
  • 我不想影响到程序性能:使用内核级程序
  • 我希望我不用挨个测试文件来获取程序分析信息:使用过程管理器

以上就是本文的全部内容,3种Node.js代码优化方式,希望大家可以熟练掌握。

Javascript 相关文章推荐
js解析与序列化json数据(三)json的解析探讨
Feb 01 Javascript
JS+ACTIVEX实现网页选择本地目录路径对话框
Mar 18 Javascript
jQuery页面元素动态添加后绑定事件丢失方法,非 live
Jun 16 Javascript
javascript时间差插件分享
Jul 18 Javascript
AngularJs基于角色的前端访问控制的实现
Nov 07 Javascript
Vue 表单控件绑定的实现示例
Aug 11 Javascript
使用vue官方提供的模板vue-cli搭建一个helloWorld案例分析
Jan 16 Javascript
JavaScript使用math.js进行精确计算操作示例
Jun 19 Javascript
详解webpack loader和plugin编写
Oct 12 Javascript
使用微信小程序开发弹出框应用实例详解
Oct 18 Javascript
axios如何利用promise无痛刷新token的实现方法
Aug 27 Javascript
原生JS实现相邻月份日历
Oct 13 Javascript
jQuery使用contains过滤器实现精确匹配方法详解
Feb 25 #Javascript
原生javascript实现addClass,removeClass,hasClass函数
Feb 25 #Javascript
javascript随机抽取0-100之间不重复的10个数
Feb 25 #Javascript
JavaScript实现多种排序算法
Feb 24 #Javascript
JavaScript中的时间处理小结
Feb 24 #Javascript
JS设置cookie、读取cookie
Feb 24 #Javascript
jquery form表单获取内容以及绑定数据
Feb 24 #Javascript
You might like
php Notice: Undefined index 错误提示解决方法
2010/08/29 PHP
Symfony2获取web目录绝对路径、相对路径、网址的方法
2016/11/14 PHP
Laravel框架中队列和工作(Queues、Jobs)操作实例详解
2020/04/06 PHP
HTML TO JavaScript 转换
2006/06/26 Javascript
解决IE下select标签innerHTML插入option的BUG(兼容IE,FF,Opera,Chrome,Safari)
2010/05/13 Javascript
javascript的数组和常用函数详解
2014/05/09 Javascript
java、javascript实现附件下载示例
2014/08/14 Javascript
前端轻量级MVC框架CanJS详解
2014/09/26 Javascript
JavaScript实现的经典文件树菜单效果
2015/09/08 Javascript
手机端转盘抽奖代码分享
2015/09/10 Javascript
jQuery实现商品活动倒计时
2015/10/16 Javascript
实现easyui的datagrid导出为excel的示例代码
2016/11/10 Javascript
BootStrap Table后台分页时前台删除最后一页所有数据refresh刷新后无数据问题
2016/12/28 Javascript
jquery easyui dataGrid动态改变排序字段名的方法
2017/03/02 Javascript
JS文件/图片从电脑里面拖拽到浏览器上传文件/图片
2017/03/08 Javascript
微信、QQ、微博、Safari中使用js唤起App
2018/01/24 Javascript
JS对象和字符串之间互换操作实例分析
2019/02/02 Javascript
JavaScript实现的开关灯泡点击切换特效示例
2019/07/08 Javascript
VUE实现图片验证码功能
2020/11/18 Javascript
vue项目中使用eslint+prettier规范与检查代码的方法
2020/01/16 Javascript
javascript实现多边形碰撞检测
2020/10/24 Javascript
[01:07:41]IG vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python Sleep休眠函数使用简单实例
2015/02/02 Python
Python获取当前公网ip并自动断开宽带连接实例代码
2018/01/12 Python
python自动查询12306余票并发送邮箱提醒脚本
2018/05/21 Python
基于Python对数据shape的常见操作详解
2018/12/25 Python
快速解决pyqt5窗体关闭后子线程不同时退出的问题
2019/06/19 Python
python之pexpect实现自动交互的例子
2019/07/25 Python
对django layer弹窗组件的使用详解
2019/08/31 Python
python 使用raw socket进行TCP SYN扫描实例
2020/05/05 Python
详解Canvas 跨域脱坑实践
2018/11/07 HTML / CSS
Net Remoting把服务器端激活两种模式
2014/01/22 面试题
幼儿园家长会邀请函
2014/01/15 职场文书
优乐美广告词
2014/03/14 职场文书
地震捐款简报
2015/07/21 职场文书
古诗之感恩老师
2019/10/24 职场文书