首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

对node工程进行压力测试与性能分析

  • 25-02-16 14:41
  • 2270
  • 7951
blog.csdn.net

在系统上线前,为了看下系统能承受多大的并发和并发下的负载情况,进行了一轮压测。在压测过程中,发现服务器的cpu飚的的非常高,而tps,接口耗时、服务可用等都是正常的,卧槽,这就奇了怪了,自己想了半天也没想出为啥,不得已求助了大佬,大佬说先查看 cpu processor  what?这是啥??虽然听不懂,但可以查嘛╭(╯^╰)╮,可还没等我查出来,大佬直接上手,一顿骚操作,便找出了原因~ 这着实让自己汗颜啊,内功远远不足啊,回来网上找了资料,恶补一把如何分析node工程中的性能问题。

在开发过程中,因为过于只关注了业务逻辑的实现,一些可能出现性能的点被忽略掉,而且这些点只能在量稍微大些的并发场景下才会出现,忘了在哪看到一句话 可能会出问题的点,便一定会出问题  性能问题进行分析必不可少。

样例项目

为了便于演示,写了个简单的小例子:

  1. // app.js

  2.   const crypto = require('crypto')

  3.   const Koa = require('koa')

  4.   const Router = require('koa-router');

  5.   const app = new Koa();

  6.   const router = new Router();

  7.   router.get('/crypto', async(ctx, next) => {

  8.       const salt = crypto.randomBytes(128).toString('base64')

  9.       const hash = crypto.pbkdf2Sync('crypto', salt, 10000, 64, 'sha512').toString('hex')

  10.       ctx.body = { hash: hash }

  11.       console.log(hash)

  12.       ctx.status = 200

  13.       next()

  14.   });

  15.   let reqNum = 0

  16.   router.get('/empty', async(ctx, next) => {

  17.       ctx.body = { hash: 'empty' }

  18.       reqNum++;

  19.       ctx.status = 200

  20.       next()

  21.   });

  22.   app.use(router.routes()).use(router.allowedMethods());

  23.   app.listen(3000, () => {

  24.       console.log("listen 3000")

  25.   })

基于koa2,有两个路由,一个/crypto,其中的业务逻辑是,使用crypto库对字符串加密;一个是 /empty,没有业务逻辑的接口,就是个空接口。

压力测试

压力测试工具市面上有很多种,就不一一列举了,在社区看到有人推荐 autocannon ,就对这个工具做个介绍,官方的简介是 fast HTTP/1.1 benchmarking tool written in Node.js ,使用node编写的压测工具,能比wrk生成更多负载。
install

npm i autocannon -g
  npm i autocannon --save


use

提供两种使用方式:
1. 命令行 autocannon -c 100 -d 5 -p 2 http://127.0.0.1:3000/test 简单快速。
2. api调用 autocannon(opts[, cb]) 便于编写脚本。

关键参数有这么几个:

-c/--connections NUM 并发连接的数量,默认10。

-p/--pipelining NUM 每个连接的流水线请求请求数。默认1。

-d/--duration SEC 执行的时间,单位秒。

-m/--method METHOD 请求类型 默认GET。

-b/--body BODY 请求报文体。

还有很多参数,大家可以查看官网文档。

这个库目前只能支持一个接口压测,我写了个脚本,可以支持批量压测和生成测试报告,具体代码见文末。

report

下图是对 /empty 接口压测 autocannon -c 100 -d 5 -p 1 http://127.0.0.1:3000/empty 结果如下:

可看到,每秒有100个链接,每个链接一个请求,持续5秒,一共产生 31k 次请求。

报告分三部分,第一行表示接口的延迟,第二行表示每秒的请求数(tps),第三行表示每秒返回的字节数。那么,延迟越低,tps越高,就表示接口性能越好,因为empty 是个空接口,所以它的tps=6221还不错,响应时间也很快,我们换成 /crypto 接口在试试。

立马看出差距了,这个接口tps只有77,接口耗时达到了1100ms,说明这个接口有很大的优化空间啊。

生成性能文件与分析

通过压测工具我们找到了有问题的接口,那接下来,就要对接口进行剖析了,可是光看接口代码,不好分析啊,毕竟没有说服力,我们就需要一份性能报告,用数据说话,下面介绍这个两个方法给大家。

V8 Profiler

V8 官方已经为大家考虑到这点了,提供了Profiler工具 使用方式也很快捷,步骤如下。以app.js为例)
 

生成报告

在启动命令中加上 --prof ,如 node --prof app.js ,在项目根目录会生成isolate-xxxxxxx-v8.log格式的文件,用来记录运行期间的调用栈和时间等信息,其中内容如下。(文件较大,就截取最顶端一小截)

  1. v8-version,6,1,534,47,0

  2.   shared-library,"C:\Program Files\nodejs\node.exe",0x7ff7505f0000,0x7ff751c0f000,0

  3.   shared-library,"C:\WINDOWS\SYSTEM32\ntdll.dll",0x7ff8718a0000,0x7ff871a61000,0

  4.   shared-library,"C:\WINDOWS\system32\KERNEL32.DLL",0x7ff870590000,0x7ff87063d000,0

  5.   shared-library,"C:\WINDOWS\system32\KERNELBASE.dll",0x7ff86e830000,0x7ff86ea18000,0

  6.   shared-library,"C:\WINDOWS\system32\WS2_32.dll",0x7ff86ee00000,0x7ff86ee6b000,0

分析报告
  对刚刚生成的log文件分析,还是使用官方提供的工具 node --prof-process isolate-xxxxxxxx-v8.log,生成结果如下。(去掉无用的部分)

  1. Statistical profiling result from isolate-00000209B99A60A0-v8.log, (17704 ticks, 8 unaccounted, 0 excluded).

  2.    [Shared libraries]:

  3.    ticks total nonlib name

  4.    13795 77.9% C:\WINDOWS\SYSTEM32\ntdll.dll

  5.    ...

  6.    [JavaScript]:

  7.    ticks total nonlib name

  8.    12 0.1% 11.3% Builtin: CallFunction_ReceiverIsAny

  9.    ...

  10.    [C++]:

  11.    ticks total nonlib name

  12.    [Summary]:

  13.    ticks total nonlib name

  14.    94 0.5% 88.7% JavaScript

  15.    0 0.0% 0.0% C++

  16.    8 0.0% 7.5% GC

  17.    17598 99.4% Shared libraries

  18.    8 0.0% Unaccounted

  19.    [C++ entry points]:

  20.    ticks cpp total name

  21.    [Bottom up (heavy) profile]:

  22.    Note: percentage shows a share of a particular caller in the total

  23.    amount of its parent calls.

  24.    Callers occupying less than 1.0% are not shown.

  25.    ticks parent name

  26.    13795 77.9% C:\WINDOWS\SYSTEM32\ntdll.dll

  27.    3795 21.4% C:\Program Files\nodejs\node.exe

  28.    3768 99.3% C:\Program Files\nodejs\node.exe

  29.    3287 87.2% Function: ~pbkdf2 crypto.js:633:16

  30.    3287 100.0% Function: ~exports.pbkdf2Sync crypto.js:628:30

  31.    3287 100.0% Function: ~router.get D:\github\webapp\js\usen\app.js:8:23

  32.    3287 100.0% Function: ~dispatch D:\github\webapp\js\usen\node_modules\[email protected]@koa-compose\index.js:37:23

  33.    ...

报告包含六部分:Shared libraries、JavaScript、C++、Summary、C++ entry points 和 Bottom up (heavy) profile,[JavaScript] 部分列出了 JavaScript 代码执行所占用的 CPU ticks(CPU 时钟周期),[C++] 部分列出了 C++ 代码执行所占用的 CPU ticks,[Summary] 列出了各个部分的占比,[Bottom up] 列出了所有 CPU 占用时间从大到小的函数及堆栈信息。

根据 3287 87.2% Function: ~pbkdf2 crypto.js:633:16 可看出这个函数消耗了 87.2% 的cpu。

文件的方式不直观,那我们换个UI界面的,步骤如下:

·先clone v8的仓库下来 git clone GitHub - v8/v8: The official mirror of the V8 Git repository

· 将日志文件转换成 json格式 node --prof-process --preprocess isolate-xxxxxxxxxx-v8.log > v8.json

· 打开 v8/tools/profview/index.html 文件,是个静态界面,在界面中心选择刚生成的 v8.json文件,文件解析成功后,界面如下:

具体的功能就不一一解释啦,我们逐层展开,寻找耗时的点,很快便找到耗cpu的地方,如下图:

node占比是45%,其中 pbkdf2 crypto.js便占用了92%。

v8-profiler

除了官方提供之外,我们还可以选择开源大佬的库,v8-profiler ,这个库的创建的时间比较早,6年前便创建了,最近一次更是在一年半前,社区评价还是不错的。

生成报告

生成方式很简单,不足的是,需要硬编码在项目中,如下:

  1. profiler.startProfiling('', true);

  2.   setTimeout(function() {

  3.    var profile = profiler.stopProfiling('');

  4.    profile.export()

  5.    .pipe(fs.createWriteStream(`cpuprofile-${Date.now()}.cpuprofile`))

  6.    .on('finish', () => profile.delete())

  7.   }, 1000);

解析报告

·Chrome

我们的大Chrome要出马啦,在Chrome的控制台,有一栏 JavaScript Profile 如下图:

点击load,选择刚刚生成的文件,解析后如下:

逐层查看,便了然。

· flamegraph-火焰图

使用 flamegraph 生成酷炫的火焰图,用在报告那是酷炫的一逼,官网图如下:

使用方式就不细说啦。

· v8-analytics

这个是社区大佬们,写的一个开源库 v8-analytics,官方介绍如下

解析v8-profiler和heapdump等工具输出的cpu & heap-memory日志,可以提供:

1)v8引擎逆优化或者优化失败的函数标红展示以及优化失败原因展示;

2)函数执行时长超过预期标红展示;

3)当前项目中可疑的内存泄漏点展示。

对应的命令如下:

va test bailout --only 这个命令可以只把那些v8引擎逆优化的函数列出来展示。

va test timeout 200 --only 这个命令可以只把那些执时长超过200ms的函数列出来展示。

va test leak 可疑展示出测试的heapsnapshot文件中可疑的内存泄漏点。

这个库的好处是,省的我们一个个去点开查找,这样可以更加便于我们筛选问题啦~

批量压力测试及生成报告

autocannon 只能运行一个接口,要想在测试下一个接口,就得修改代码,比如想批量测试多个接口,就需要来回改代码,操作就比较麻烦,所以我基于 autocannon 写了个脚本,可以逐一压测定义好的接口,同时还可以生成测试报告。

  1. 'use strict'

  2.   const autocannon = require('autocannon')

  3.   const reporter = require('autocannon-reporter')

  4.   const path = require('path')

  5.   const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

  6.   /**

  7.    * @description

  8.    * 运行autocannon

  9.    * [url=home.php?mod=space&uid=267564]@Author[/url] lizc

  10.    * @param {*} param

  11.    */

  12.   function makeAutocannon(param) {

  13.    autocannon(param).on('done', handleResults)

  14.   }

  15.   /**

  16.    * @description

  17.    * 处理接口

  18.    * @author lizc

  19.    * @param {*} result

  20.    */

  21.   function handleResults(result) {

  22.    const reportOutputPath = path.join(`./${result.title}_report.html`)

  23.    reporter.writeReport(reporter.buildReport(result), reportOutputPath, (err, res) => {

  24.    if (err) console.err('Error writting report: ', err)

  25.    else console.log('Report written to: ', reportOutputPath)

  26.    })

  27.   }

  28.   // 请求参数

  29.   const autocannonParam = {

  30.    url: 'http://127.0.0.1:6100/',

  31.    connections: 100,

  32.    duration: 10,

  33.    headers: {

  34.    type: 'application/x-www-form-urlencoded'

  35.    }

  36.   }

  37.   // 请求报文参数

  38.   const requestsParam = {

  39.    method: 'POST', // this should be a put for modifying secret details

  40.    headers: { // let submit some json?

  41.    'Content-type': 'application/json; charset=utf-8'

  42.    }

  43.   }

  44.   /**

  45.    * @description

  46.    * 启动批量压测

  47.    * @author lizc

  48.    * @param {*} methodList 接口列表

  49.    */

  50.   async function run(methodList) {

  51.    const autocannonList = methodList.map(val => {

  52.    return {

  53.    ...autocannonParam,

  54.    url: autocannonParam.url + val,

  55.    title: val,

  56.    requests: [

  57.    {

  58.    ...requestsParam,

  59.    }

  60.    ],

  61.    }

  62.    })

  63.    for (let i = 0; i < autocannonList.length; i++) {

  64.    if (i !== 0) {

  65.    await sleep((autocannonList[i - 1].duration + 2) * 1000)

  66.    makeAutocannon(autocannonList[i])

  67.    } else {

  68.    makeAutocannon(autocannonList[i])

  69.    }

  70.    }

  71.   }

  72.   // 启动

  73.   run(['order', 'crypto'])

 感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方蓝色字体或小卡片即可自行领取。软件测试全套资料分享: 耗时2个月整理的软件测试最全资料包

软件测试/自动化测试全套资料分享
QQ群名片
注:本文转载自blog.csdn.net的心软小念的文章"https://blog.csdn.net/2301_79535733/article/details/143779477"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

127
测试
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top