
作者 | 镜逸
这是性能测试篇的第二篇,主要分析上篇文章中我们的优化为啥不起作用的原因。
回顾
上篇文章Node.js调试之性能测试篇(一) ,我们通过一个简单的例子使用v8-profiler和Chrome开发者工具中的JavaScript Profiler分析Node应用的CPU性能。虽然我们分析出性能瓶颈,但我们的优化 似乎没有效果,2000个请求的处理时间为93秒,每秒处理请求平均为21.48。

消耗的主要时间在于gc,占据15.34%:

GC分析
为什么GC会占据这么多时间呢?原因很简单,2000次请求都是通过相同的用户名”breath.wl“请求的,每次都会生成salt和hash,并通过username保存在users对象中,导致每次请求都会覆盖上一次请求产生的数据,被覆盖的数据会被v8回收。2000次请求中有1999次产生的数据需要被回收,所以GC会占据这么高的时间也是很合理的。这里比较遗憾的事情是,我没有找到可视化GC的node工具,所以没有办法给大家展示GC的过程,后面我会写一个工具用来展示该过程。

虽然GC的时间会消耗15.34%*93=14.2662秒,其他的时间都消耗到什么地方去了呢?
火焰图
没办法,只能看一下火焰图了:

好密集,缩小一下范围,好像发现了点什么,处理请求的时间很少,大量时间处于idle状态,也就是说服务器大部分是处于空闲状态的,这是为什么呢?

现在又进入了困境,没有其他信息,为什么node大部分时间处于idle状态呢?没有办法只能靠直觉去猜了
,没有办法我也很无奈
,在定位问题中有时猜也是很好的方法。
猜测
在使用ab进行请求时,并发数量设置成了20,ab会等待这20个并发请求处理完毕之后,才会发出新的请求。这样就导致2000个请求,并不是并发的,而是按照20个一组串行请求的。
为了验证猜想,就做一下实验吧,在原先的代码中,我们引入了变量inputCount和outputCount,inputCount表示目前介绍的请求数量,outputCount表示请求已经处理完毕的数量。


看结果可以确定我们的猜测是对的,模拟并发请求时,每组20个变成了串行请求,哇好兴奋,那把2000个请求并发看一下结果,下面第一张图是调用同步pbkdf2Sync方法的结果,第二张图是调用异步pbkdf2的结果。从图中可以看出调用同步pbkdf2Sync方法处理2000次请求一共消耗了91秒,每秒处理21.96个请求;调用异步pbkdf2方法一共消耗52秒,每秒处理38.28个请求。


所以从结论上来看,其实我们之前的优化是有效果的,之所以上篇文章中看似没有效果的原因是我们测试的姿势不对,好尴尬
。
继续分析
最后让我们再次看一下这次测试的火焰图吧:


从图可以看到前10s已经接受到了所有2000个请求,10s后大部分时间仍是idle状态,这是为什么呀。其实很简单,Chrome Devtools只能分析JavaScript,对于原生的C++代码是无法分析的。由于有2000个pbkdf2函数同时在处理,我们的CPU几乎已经满负荷运行了,所以这2000个计算也是需要排队的。

总结
到目前为止,Node调试相关的内容基本结束了,后面会零零散散的写一些,当然承诺的可视化Node GC过程我们肯定会写。下个阶段我们会集中精力在Service Worker这块, 如果您对此感兴趣,欢迎 通过下面的二维码关注一下我们阿里巴巴新零售CBU技术部前端的公众号 。
