你所未知的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 在定义的时候立即执行的函数表达式(function)写法
Jan 16 Javascript
扩展js对象数组的OrderByAsc和OrderByDesc方法实现思路
May 17 Javascript
JS判断数组中是否有重复值得三种实用方法
Aug 16 Javascript
jQuery中eq()方法用法实例
Jan 05 Javascript
基于jquery实现可定制的web在线富文本编辑器附源码下载
Nov 17 Javascript
JavaScript实现显示函数调用堆栈的方法
Apr 21 Javascript
JS中substring与substr的用法
Nov 16 Javascript
js 定位到某个锚点的方法
Nov 19 Javascript
Bootstrap源码学习笔记之bootstrap进度条
Dec 24 Javascript
浅谈js script标签中的预解析
Dec 30 Javascript
AngularJS使用拦截器实现的loading功能完整实例
May 17 Javascript
js实现上下左右键盘控制div移动
Jan 16 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 数组的合并、拆分、区别取值函数集
2010/02/15 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十)
2014/06/24 PHP
thinkPHP3.1验证码的简单实现方法
2016/04/22 PHP
PHP 二维array转换json的实例讲解
2018/08/21 PHP
php如何获取Http请求
2020/04/30 PHP
JS无限极树形菜单,json格式、数组格式通用示例
2013/07/30 Javascript
jquery上传插件fineuploader上传文件使用方法(jquery图片上传插件)
2013/12/05 Javascript
javascript圆盘抽奖程序实现原理和完整代码例子
2014/06/03 Javascript
setTimeout()递归调用不加引号出错的解决方法
2014/09/05 Javascript
javascript使用prototype完成单继承
2014/12/24 Javascript
jQuery中remove()方法用法实例
2014/12/25 Javascript
Vue.js报错Failed to resolve filter问题的解决方法
2016/05/25 Javascript
基于jquery二维码生成插件qrcode
2017/01/07 Javascript
JavaScript 程序错误Cannot use 'in' operator to search的解决方法
2017/07/10 Javascript
JavaScript实现跟随滚动缓冲运动广告框
2017/07/15 Javascript
把vue-router和express项目部署到服务器的方法
2018/02/21 Javascript
详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序
2018/11/21 Javascript
vue+elementUI实现表单和图片上传及验证功能示例
2019/05/14 Javascript
前后端常见的几种鉴权方式(小结)
2019/08/04 Javascript
[01:03]悬念揭晓 11月26日DOTA2完美盛典不见不散
2017/11/23 DOTA
Python中MySQLdb和torndb模块对MySQL的断连问题处理
2015/11/09 Python
python 用opencv调用训练好的模型进行识别的方法
2018/12/07 Python
分析运行中的 Python 进程详细解析
2019/06/22 Python
Python实现蒙特卡洛算法小实验过程详解
2019/07/12 Python
python时间日期操作方法实例小结
2020/02/06 Python
python3 deque 双向队列创建与使用方法分析
2020/03/24 Python
Python OpenCV去除字母后面的杂线操作
2020/07/05 Python
pymongo insert_many 批量插入的实例
2020/12/05 Python
2021年值得向Python开发者推荐的VS Code扩展插件
2021/01/25 Python
python实现银行账户系统
2021/02/22 Python
CSS中的字体大小设置属性总结
2016/05/24 HTML / CSS
使用html5 canvas创建太空游戏的示例
2014/05/08 HTML / CSS
GAP美国官网:美国休闲时尚品牌
2016/08/26 全球购物
安全生产实施方案
2014/02/23 职场文书
舞蹈专业大学生职业规划范文
2014/03/12 职场文书
幼儿园安全工作总结2015
2015/04/20 职场文书