很多前端工程师在做页面性能调优的过程中,极少关注代码本身的执行效率,更多关注的是网络消耗,比如资源合并减少请求数、压缩降低资源大小、缓存等. 我并不觉得这不合理,相反,在很大程度上这是足够正确的做法,举个例子, JS 本身的执行时间是 30ms(毫秒),在动辄三五秒的页面加载时间中的占比实在太低了,就算拼了命把性能提升 10 倍,执行时间降到 3ms,整体性能提升也微不足道,甚至在用户层面都无法感知. 因此去优化其它性能消耗的大头更加明智.
但从 Node.js(服务端) 的角度来看,JS 本身的执行时间却变得至关重要,还是之前的例子,如果执行时间从 30ms 降到 3ms, 理论上 QPS 就能提升 10 倍,换句话说,以前要 10 台服务器才能扛住的流量现在 1 台服务器就能扛住,而且响应时间更短.
那到底 Node 端如何做性能优化呢?
有两种方法,一种是通过 Node/V8 自带的 profile 能力 , 另一种是通过 alinode 的 CPU profile 功能. 前者只列出了各函数的执行占比, 后者包括更加完整的调用栈,可读性更强,更加容易定位问题,建议采用后者.
- $ node--prof index.js
- $ loadtest http://127.0.0.1:6001 --rps 10
- $ node--prof - process isolate - 0XXXXXXXXXXX - v8 - XXXX.log > profile.txt
文件如下图,包括 JS 和 C++ 代码各消耗多少 ticks, 具体分析方法详见 node profile 文档
- profile.txt
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
- $ node--perf - basic - prof - only - functions index.js
- $ loadtest http://127.0.0.1:6001 --rps 10
假设启动的 worker 进程号为 6989, 执行以下脚本, 三分钟后将在 / tmp / 目录下生成一个 cpuprofile 文件
脚本详见 take_cpu_profile.sh
- /tmp/cpu-profile-6989-XXX.cpuprofile
- $ sh take_cpu_profile.sh 6989
下面通过一个真实的案例展示如何一步步地做性能调优.
通过 loadtest 请求 1000 次,统计平均 RT, 初始 RT 为 15.8ms
剔除 program 和 GC 消耗,性能消耗的前三位分别是
,
- get
和
- J
三个方法
- _eval
展开最耗性能的
方法调用栈,可以定位到
- get
方法所在的位置,具体代码如下
- get
- {
- key: 'get',
- value: function get(propName) {
- if (!this.state[propName]) {
- return null;
- }
- return JSON.parse(JSON.stringify(this.state[propName]));
- }
- }
方法体中,
虽然使用便捷,但却是 CPU 密集型操作. 做一次验证,去除该操作, 直接返回
- JSON.parse(JSON.stringify(obj))
. RT 时间降为 12.3ms 了
- this.state[propName]
这仅仅是一次试验,肯定不能直接移除
, 不然会影响业务逻辑的. 参考下常用拷贝方法的 性能对比 , 自配梯子. 截图如下:
- JSON.parse(JSON.stringify(obj))
其中性能最优的是 lodash deep clone,采用该库替换,再验证一遍, RT 降为 12.8ms
第二耗性能是的
方法,里面大部分是各个组件的 render 时间,暂时略过,以同样的方式对
- J
方法进行一次优化, RT 降为 10.1ms.
- _eval
以此类推,根据 CPU profile 找出性能消耗的点,逐个去优化.
来源: http://www.tuicool.com/articles/jEJZziA