在用Vue做服务端渲染时,大家对Vue服务端渲染的性能持怀疑态度,业界也有一些尝试,不过完整的产品项目和数据分析比较少。结合超级游戏中心,我们对Vue和Nunjucks进行模板渲染,针对Rer时间,CPU占用,内存占用进行全面的对比测试。
渲染性能对比通过实现相同的模板功能,分别针对无缓存和有缓存进行了对比测试.测试方法,通过ab压测工具对页面进行测试,Node层收集页面rer渲染时间,然后进行汇总统计分析。
Nunjucks测试模板divdivh2h5GameList/h2ul{%%}liahref="{{}}"{{}}-{{}}/a/li{%for%}/ul/divdivh2recommList/h2{%%}divahref="{{}}"{{}}/ap{{}}/p/div{%for%}/divdivh2bestList/h2{%%}divahref="{{}}"{{}}/ap{{}}/p/div{%for%}/divdivh2bookingList/h2{%%}divahref="{{}}"{{}}-{{}}/ap{{}}/p/div{%for%}/div/divVue测试模板templatedivdivh2h5GameList/h2ulliv-for=""av-bind:href=""{{}}-{{}}/a/li/ul/divdivh2recommList/h2divv-for=""av-bind:href=""{{}}/ap{{}}/p/div/divdivh2bestList/h2divv-for=""av-bind:href=""{{}}/ap{{}}/p/div/divdivh2bookingList/h2divv-for=""av-bind:href=""{{}}-{{}}/ap{{}}/p/div/div/div/template测试脚本一:ab-c50-n1000http://ip:port/perf/nunjucks/ab-c50-n1000http://ip:port/perf/vue/其中-n表示请求数,-c表示并发数
测试脚本二:ab-c50-n5000http://ip:port/perf/nunjucks/ab-c50-n5000http://ip:port/perf/vue/
从上面统计来看可以得出如下结论:
无缓存情况:nunjucks平均时间比vue渲染要快1ms,差距没想象的大。
有缓存情况:nunjucks平均时间是vue的3倍左右,但也都是毫秒级别的差异。在整理数据时,nunjucks的rer时间都是0-1ms,而vue则要1-3ms。分析一下可知道,nunjucks是基于字符串正则编译的,可以做到预编译缓存,而vue目前的实现方式是通过webpack构建的jsbundle文件(查看构建文件可以看到每个元素和组件都是通过javascript动态创建组合的),然后整个script丢给原生vm模块(独立的沙箱运行空间)动态执行script。目前Vue官方提供了基于Webpack构建Vue字符串的方案,宣传性能会有比较大的提升。这种方案前一段时间做个实践,每一个页面都需要独立构建一个manifest和文件,比较适合单页面应用,多页面应用构建有冲突,需要自己实现支持,待实践。从游戏中心实践来看,rer时间在整个耗时链条里面是非常小的,性能问题大头部分在于网络(DNS,网络连接,网络传输),接口耗时两部分。
vm对比测试
=100;constvm=require('vm');constcode='varret=num*num*num;';constsandbox={num:1000};constbenchmark=(msg,fun)={conststart=newDate;for(leti=0;i10000;i++){fun();}const=newDate;(msg+':'+(-start)+'ms');};constctx=(sandbox);//runInThisContext用于创建一个独立的沙箱运行空间,code内的代码可以访问外部的global对象,但是不能访问其他变量benchmark('',()={(code);});//runInContext创建一个独立的沙箱运行空间,sandBox将做为global的变量传入code内,但不存在global变量benchmark('',()={(code,ctx);});//与runInContext一样,这里可以直接传sandboxbenchmark('',()={(code,sandbox);});constscript=(code);benchmark('',()={();});benchmark('',()={(sandbox);});benchmark('',()={(ctx);});benchmark('fn',()={newFunction('num',code)();});/*:15:71:70:7:59:57msfn:9msscript方式都比vm方式快*/线上应用性能数据从整个链路时间来看rt(首屏时间)可以看到,平均首屏时间小于1s,而rer时间平均在30ms,在整个链路上面,==rer的时间可以说是可以忽略的==,至少从上面图来看,==性能问题大头部分在于网络,接口耗时两部分。==
CPU和内存占用前提条件:
Mac环境
Nunjucks和Vue渲染都开启缓存
Vue服务端渲染关闭runInNewContext
为保证测试的统计准确性,只启动一个工作worker,下面分析只统计worker进程CPU和内存,排除了Eggmaster和agent进程。
NunjucksCPU和内存占用采集样本:ab-c100-n50000http://ip:port/perf/nunjucks/
ThisisApacheBench,$Revision:1663405gt;Copyright1996AdamTwiss,ZeusTechnologyLtd,(bepatient)Completed5000requestsCompleted10000requestsCompleted15000requestsCompleted20000requestsCompleted25000requestsCompleted30000requestsCompleted35000requestsCompleted40000requestsCompleted45000requestsCompleted50000requestsFinished50000requestsServerSoftware:ServerHostname:100.84.250.56ServerPort:7001DocumentPath:/perf/nunjucks/DocumentLength:13899bytesConcurrencyLevel:100Timetakenfortests:173.686secondsCompleterequests:50000Failedrequests:48138(Connect:0,Receive:0,Length:48138,Exceptions:0)Totaltransferred:709284995bytesHTMLtransferred:694684887bytesRequestspersecond:287.88[/sec](mean)Timeperrequest:387.048[ms](mean)Timeperrequest:3.870[ms](mean,acrossallconcurrentrequests)Transferrate:3568.35[Kbytes/sec]receivedConnectionTimes(ms)minmean[+/-sd]medianmaxConnect:01027.321384Processing:22377223.92852236Waiting:22373217.72852235Total:42386219.52902239Percentageoftherequestsservedwithinacertaintime(ms)50%29066%33575%40980%48190%69795%84198%103099%1126100%2239(longestrequest)dou
两个图对比发现如下信息:
压测前egg应用启动后,worker进程内存稳定在60MB,cpu使用都小于1%,保证前提条件一致
压测启动后,nunjucks和vueCPU使用迅速飙升到90%,曲线基本保持一样,没有很明显高低之分
压测启动后,nunjucks和vue内存也是迅速上升,整个压测期间,nunjucks平均内存使用为150MB左右,vue平均内存使用为160MB,vue内存占用比较稳定。从这个数据可以看出,Vue服务端渲染内存占用略微比nunjucks高一些。
压测结束好后,nunjucks和vue的CPU使用迅速降为小于1%,内存使用迅速降为60MB,都恢复为压测前的状态,这也表面nunjucks和vue压测期间没有出现内存泄漏的情况。
Nunjucks与Vue对比分析首先我们来看看ab执行结果的几个关键参数含义:
ConcurrencyLevel并发请求数
Timetakenfortests整个测试持续的时间
Completerequests完成的请求数
Failedrequests失败的请求数(指内容大小不一样,其实是成功的)
HTMLtransferredHTML内容传输量
Requestspersecond每秒处理的请求数,mean表示平均值
Timeperrequest用户平均请求等待时间
Timeperrequest(mean,acrossallconcurrentrequests)服务器平均请求处理时间
ab对比数据可以得出以下结论:HTMLtransferred内容传输量数据非常接近,保证了对比测试的客观性。
50000个请求,vue整体处理时间比nunjucks慢20s,平均每个相当于慢0.4ms,这个于上面rer数据对比是吻合的。
nunjucks每秒处理的请求数比vue略微多30个,用户平均请求等待时间少0.4ms
从percentagetime时间我们发现nunjucks和vue每个区间都是非常接近。
总体上,nunjucks和vue在模板渲染,CPU使用,内存占用没有很明显的差异,各指标基本接近。其中nunjucks在模板渲染方面略微快一点点(个位数毫秒级),内存占用方面vue比nunjucks占用略微多一点,但都在可接受范围内。
CPU和内存工具在进行CPU和内存监控统计分析时,也没有找到简单好用的火焰图工具。Alinode平台统计粒度太大,数据也不是时时可以拿到,也不好使。找到一些成熟的工具比如perf和FlameGraph都比较复杂,而且一些资料都是linux上面的,配置相当繁琐,只好放弃。另外找到Mac的一个小工具iStatMenus能显示电脑磁盘CPU,内存等占用情况不错,图也很小且不适合做具体分析,作为电脑监控工具还不错。最终也没有找到合适简单工具,只好简单撸一个,顺便玩了一把和图表工具。上面CPU和内存统计是通过和egg-schedule插件,current-processes,以及图片库IgniteUI实现的。
EggNode端和egg-schedulecurrent-processes结合
'usestrict';constps=require('current-processes');constos=require('os');consttotalMem=();//=app={={interval:'3s',type:'worker'};=function*(ctx){((err,processes)={constproArr=(pro={==='node';}).sort((a,b)={;});();();constcpu_mem_info=(pro={return{pid:,cpuPercent:,totalMemory:totalMem,usedMemory:,//RSS实际内存占用大小memoryPercent:*100,//进程占用内存百分比virtualMemory:,//虚拟内存占用大小};});('monitor-memory-cpu',cpu_mem_info);});};returnexports;};客户端实现socket监听monitor-memory-cpu事件,每3s中获取到一次Node数据,然后绘制图表。图片绘制请参考例子:
varsocket=("http://localhost:7001");("monitor-memory-cpu",function(data){(info={=;=;=newDate().toLocaleTimeString();(info);$("memoryChart").igDataChart("notifyInsertItem",cpuData,,info);});});
作者:hubcarl
转载链接:





