性能优化 - 让nodejs再快一点

区块链游侠
• 阅读 17091
本文首次发表于北斗同构github, 转载请注明出处

前言

很多前端工程师在做页面性能调优的过程中,极少关注代码本身的执行效率,更多关注的是网络消耗,比如资源合并减少请求数、压缩降低资源大小、缓存等. 我并不觉得这不合理,相反,在很大程度上这是足够正确的做法,举个例子, JS本身的执行时间是30ms(毫秒),在动辄三五秒的页面加载时间中的占比实在太低了,就算拼了命把性能提升10倍,执行时间降到3ms,整体性能提升也微不足道,甚至在用户层面都无法感知. 因此去优化其它性能消耗的大头更加明智.

但从Node.js(服务端)的角度来看,JS本身的执行时间却变得至关重要,还是之前的例子,如果执行时间从30ms降到3ms, 理论上QPS就能提升10倍,换句话说,以前要10台服务器才能扛住的流量现在1台服务器就能扛住,而且响应时间更短.

那到底Node端如何做性能优化呢?

方法

有两种方法,一种是通过Node/V8自带的profile能力 , 另一种是通过alinode的 CPU profile功能. 前者只列出了各函数的执行占比, 后者包括更加完整的调用栈,可读性更强,更加容易定位问题,建议采用后者.

方法1: Node 自带 profile

  • 第1步: 以--prof参数启动Node应用
$ node --prof index.js
  • 第2步: 通过压测工具loadtest向服务施压
$ loadtest  http://127.0.0.1:6001 --rps 10
  • 第3步: 处理生成的log文件
$ node --prof-process isolate-0XXXXXXXXXXX-v8-XXXX.log > profile.txt 
  • 第4步: 分析profile.txt文件

profile.txt文件如下图,包括JS和C++代码各消耗多少ticks, 具体分析方法详见node profile文档

性能优化 - 让nodejs再快一点

方法2: alinode的CPU profile

  • 第1步: 安装alinode

alinode是与 Node 社区版完全兼容的二进制运行时环境, 推荐使用tnvm工具进行安装

$ wget -O- https://raw.githubusercontent.com/aliyun-node/tnvm/master/install.sh | bash

完成安装后,需要将tnvm添加为命令行程序. 根据平台的不同,可能是~/.bashrc,~/.profile 或 ~/.zshrc等

$ source ~/.zshrc

以alinode-v3.8.0为例, 对应node-v8.9.0, 下载该版本并启用它

$ tnvm install alinode-v3.8.0
$ tnvm use alinode-v3.8.0
  • 第2步: 用安装的alinode运行时启动应用
$ node --perf-basic-prof-only-functions index.js
  • 第3步: 通过压测工具loadtest向服务施压
$ loadtest  http://127.0.0.1:6001 --rps 10
  • 第4步: cpu profile

假设启动的worker进程号为6989, 执行以下脚本, 三分钟后将在/tmp/目录下生成一个cpuprofile文件/tmp/cpu-profile-6989-XXX.cpuprofile
脚本详见take_cpu_profile.sh

$ sh take_cpu_profile.sh 6989
  • 第5步: 将生成的cpuprofile文件导入到Chrome Developer Tools进行分析

性能优化 - 让nodejs再快一点

实战

下面通过一个真实的案例展示如何一步步地做性能调优.

通过loadtest请求1000次,统计平均RT, 初始RT为15.8ms

性能优化 - 让nodejs再快一点

剔除program和GC消耗,性能消耗的前三位分别是get,J_eval三个方法

性能优化 - 让nodejs再快一点

展开最耗性能的get方法调用栈,可以定位到get方法所在的位置,具体代码如下

{
    key: 'get',
    value: function get(propName) {
      if (!this.state[propName]) {
        return null;
      }
      return JSON.parse(JSON.stringify(this.state[propName]));
    }
  }

方法体中,JSON.parse(JSON.stringify(obj))虽然使用便捷,但却是CPU密集型操作. 做一次验证,去除该操作, 直接返回this.state[propName]. RT时间降为12.3ms了

性能优化 - 让nodejs再快一点

这仅仅是一次试验,肯定不能直接移除JSON.parse(JSON.stringify(obj)), 不然会影响业务逻辑的. 参考下常用拷贝方法的性能对比, 自配梯子. 截图如下:

性能优化 - 让nodejs再快一点

其中性能最优的是lodash deep clone,采用该库替换,再验证一遍, RT降为12.8ms

性能优化 - 让nodejs再快一点

第二耗性能是的J方法,里面大部分是各个组件的render时间,暂时略过,以同样的方式对_eval方法进行一次优化, RT降为10.1ms.

性能优化 - 让nodejs再快一点

以此类推,根据CPU profile找出性能消耗的点,逐个去优化.

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Uber准备放弃自动驾驶,转手卖给前谷歌无人车CTO,估值曾被孙正义炒到72.5亿美元
!(https://oscimg.oschina.net/oscnet/0fe7cb00a0cf4872b022342d1e21d47e.png)杨净发自凹非寺量子位报道|公众号QbitAI最新消息,Uber要出售无人驾驶部门(ATG)了。据TechCrunch报道,Uber有意向出售,而也有人愿意买。
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这