写点什么

5. 堪比 JMeter 的.Net 压测工具 - Crank 实战篇 - 接口以及场景压测

  • 2022 年 4 月 15 日
  • 本文字数:4621 字

    阅读完需:约 15 分钟

1. 前言

通过之前的学习,我们已经掌握了 crank 的配置以及对应 http 基准工具 bombardier、wrk、wrk2 的用法,本篇文章介绍一下如何将其用于实战,在实际的项目中我们如何使用 crank 来完成压测任务。


2. 项目背景

目前有一个项目,我们希望通过压测来了解其 QPS、吞吐量、以及临界值,并通过压测来分析出其瓶颈在哪里?并通过解决瓶颈问题以提高 QPS、吞吐量等指标


先看下我们手头掌握了什么:


  • 项目信息

  • 项目中的接口基本都需要登录

  • 通过与开发沟通可以得到每个页面的接口信息以及参数信息

  • 环境信息

  • 压测项目有单独的环境部署应用、Redis、数据库等基础配置


此处项目名我们暂定为 ProjectA。

3. 如何开展

首先我们先回顾一下 Agent、Controller 的职责以及特点


  • Controller

  • 做任务调度以及结果输出

  • 无需单独服务器,可以在本机执行发送命令,需要与 Agent 相通

  • Agent

  • 任务的实际执行者

  • 单任务执行,不能做到接收到多个任务并同时执行,先收到哪个任务,哪个任务会先执行

  • 相同一个任务可以被多个 Agent 同时执行,最终指标结果会自动累加,可以通过提升 Agent 来模拟更高的并发能力

3.1. 思路

  • 先做好单独接口的压测,大概掌握每个接口的指标情况

  • 同时压测多个接口,完成对场景的压测

  • 通过压测观察应用服务器、基础服务器的 CPU、带宽、内存等指标,观察 Redis、数据库、消息队列等基础组件情况,根据压测的返回结果得到每个场景的基础指标

  • 通过分析发现瓶颈、然后再考虑如何突破瓶颈,提升 QPS、吞吐量等

3.2. 如何做?

了解到单个 Agent 同时执行多个任务会进行排队,无法做到多任务同时执行,那么我们可以通过多个 Agent 同时执行不同的任务来模拟用户访问页面。

3.2.1. 构建 Agent

之前与开发沟通得到每个页面最多可发送的请求是 6 个,那么我们准备 6 个 Agent,分别为 Agent1、Agent2、Agent3、Agent4、Agent5、Agent6


我们这里使用 Docker 来启动 Agent、Agent 对内开放端口: 5010、对外端口随机,镜像使用我们自建的: doddgu/crankagent:net5.0


并新建 load.yml 为之后压测使用:


profiles:  crankAgent1:    jobs:      load:        endpoints:          - http://localhost:5010  crankAgent2:    jobs:      load:        endpoints:          - http://localhost:5011  crankAgent3:    jobs:      load:        endpoints:          - http://localhost:5012  crankAgent4:    jobs:      load:        endpoints:          - http://localhost:5013  crankAgent5:    jobs:      load:        endpoints:          - http://localhost:5014  crankAgent6:    jobs:      load:        endpoints:          - http://localhost:5015
复制代码


load.yml 中记录了所有的压测机信息,其信息一般不做修改,我们可以作为公共的配置来使用无需每个项目都单独维护一份新的

3.2.2. 构建压测脚本

在这里我们选择 wrk2 作为本次基准测试工具,选择 wrk2 的原因是:


  • 支持随机参数

  • 可支持设置恒定的吞吐量负载

  • 具备 wrk 的所有功能


此时我们针对 ProjectA 项目新建配置:project.profiles.yml,作为本次压测的环境配置来使用,其配置如下


imports:  - https://raw.githubusercontent.com/doddgu/crank/sample/samples/wrk2/common/load.profiles.yml # 这边建议使用远程load.profiles.yml地址。(如果输入的是本地路径、则需输入与当前命令所在路径的相对路径)
profiles:
local: # 本地环境 variables: serverAddress: localhost # 应用服务域 serverPort: 80 # 应用服务端口 connections: 256 # 每个线程处理时保持打开的 HTTP 连接总数 N = 连接数/线程数 threads: 32 # 线程数 warmup: 3 # 预热时间: 3s duration: 180 # 测试时长: 3分钟 rate: # 吞吐量参数(每秒总请求数)
复制代码


project.profiles.yml 中记录了指定项目的各环境的配置,项目自己独立维护即可


除了项目信息、压测机配置之外,我们还需要有地方维护我们压测的接口信息,这边我的做法是将 api 独立拆分出来,每个 yml 只配置一个接口的压测信息,至于为什么不放到一块,而要单独拆分开呢?


这块考虑到我们压测的最小单元是 API 接口,如果把 API 接口独立拆分开,那么可以对单接口压测,而如果我们需要场景压测,也可以通过组合接口完成多接口同时压测,并且一旦我们完成了某个接口的压测编写,后续不需要再改动这个配置,如果我们按照场景拆分成不同的 yml,在 yml 中再根据定义不同的 scenario 来做,那么后续场景新增加接口,还需要再更改这个场景的 yml,并且 scenario 中的场景实际上也是根据接口维度区分的,目前 crank 并不能完成单个场景任务同时处理,基于以上原因,这边我们新调整好的配置格式为:


新增 load.benchmarks.yml


imports:  - https://raw.githubusercontent.com/doddgu/crank/sample/src/Microsoft.Crank.Jobs.Wrk2/wrk2.yml  - https://raw.githubusercontent.com/doddgu/crank/sample/samples/wrk2/common/project.profiles.yml
jobs: server: source: repository: https://github.com/doddgu/crank branchOrCommit: sample project: samples/hello/hello.csproj readyStateText: Application started.
scenarios: api: application: # 实际压测项目时可移除此节点,此处是为模拟应用服务启动 job: server variables: duration: 1 load: job: wrk2 variables: serverPath: /user/get script: request.lua duration: 1
profiles: defaultParamLocal: # 本地环境的参数信息 variables: serverQueryString: ?id={1} serverQueryParameter: 1||2 # 随机请求/get?id=1、/get?id=2
复制代码


按照此格式保存,后续新增接口也可以快速复制,简单修改即可快速完成压测工作的编写,这样一来,如果我们希望对 localhost:5000/user/get 这个接口做压测,仅需要在 crank 控制端输入:


crank --config load.benchmarks.yml --scenario api --load.framework net5.0 --application.framework net5.0 --profile local --profile crankAgent1 --description "获取用户详情" --profile defaultParamLocal
复制代码

3.2.3. 构建批处理命令

但作为一个开发人员,总是希望事情能更简单一点,每次输入命令太麻烦了,所以就想到了通过批处理快速完成任务的发送,最终的项目结构就变成了


benchmarks├─ defaultTitle              接口名称( Description )└─ load.bat                  最终执行的脚本,其中指定了要指定的yml配置、场景、以及任务环境是.net 5.0└─ load.benchmarks.yml       yml配置└─ load.local.bat            测试本地环境时要执行的脚本、格式:load.{环境}.bat└─ README.md                 帮助文档
复制代码


每次通过双击 load.{环境}.bat 就完成了对当前接口的压力测试,然后就是等待结果输出……


| application           |                || --------------------- | -------------- || CPU Usage (%)         | 1              || Cores usage (%)       | 10             || Working Set (MB)      | 85             || Private Memory (MB)   | 278            || Build Time (ms)       | 3,469          || Start Time (ms)       | 352            || Published Size (KB)   | 93,323         || .NET Core SDK Version | 5.0.404        || ASP.NET Core Version  | 5.0.13+55738ff || .NET Runtime Version  | 5.0.13+b3afe99 |

| load | || --------------------- | -------------- || Build Time (ms) | 3,281 || Start Time (ms) | 0 || Published Size (KB) | 74,276 || .NET Core SDK Version | 5.0.404 || ASP.NET Core Version | 5.0.13+55738ff || .NET Runtime Version | 5.0.13+b3afe99 || First Request (ms) | 86 || Requests/sec | 2 || Requests | 2 || Mean latency (ms) | 2.68 || Max latency (ms) | 2.68 || Bad responses | 0 || Socket errors | 0 || Latency 50th (ms) | 2.68 || Latency 75th (ms) | 2.68 || Latency 90th (ms) | 2.68 || Latency 99th (ms) | 2.68 || Latency 99.9th (ms) | 2.68 || Latency 99.99th (ms) | 2.68 || Latency 99.999th (ms) | 2.68 |
复制代码

3.2.4. 构建场景压测批处理命令

通过上面的一番操作,我们已经可以很容易的对单接口进行压测,但目前想模拟完成多接口同时压测,还需要再改造一下,之前我们想到,crank 目前只能完成单独压测任务,那是不是有多个 Agent,每个 Agent 单独压测一个接口,并同时启动多个 Agent 同时压测是不是可以模拟出来场景压测,那我通过批处理任务多点几次不同的接口压测不就可以了,基于以上考虑,又做了一个批处理脚本,用于调用多个接口的压测任务启动,最后的结构如下所示:


Crank├─ benchmarks                压测脚本│  ├─ api                   接口压测脚本               │  │  ├─ add               │  │  └─ get                  │  ├─ scipts               lua脚本             │  │  ├─ common            lua公共脚本│  │  │  ├─ oauth.lua     认证lua脚本│  │  │  ├─ util.lua      lua工具类脚本│  │  ├─ request.lua       封装请求lua脚本   │  ├─ scripts.tar           lua脚本压缩包├─ common                            │  ├─ load.profiles.yml     agent 负载机配置│  ├─ project.profiles.yml  项目配置│  ├─ scripts.profiles      crank 执行script配置,用于对输出结果的二次处理│  ├─ project.profiles.yml  项目配置├─ scripts                   场景压测脚本│  ├─ 用户.bat              用户压测     └─ env                       环境配置,标记当前需要压测的环境在哪个配置文件中存储└─ env.local                 本地环境,存储本地环境的配置信息└─ README.md                 帮助文档
复制代码

4. 结尾

通过上面的操作我们已经完成了对单接口以及单场景的压测,通过控制台可以清晰的看到每个接口的压测结果,我们只需要耐心等待压测任务结束,并整理压测结果数据,最后进行汇总我们的任务就完成了,但压测结果的收集也是一个费事费力的工作,作为一个开发,是不想把时间花费到这些整理表格的事情上,那我们如何做可以把整理表格数据的工作节省下来让我们可以歇会儿呢……


源码地址:https://github.com/doddgu/crank/tree/sample/samples/wrk2


参考链接:


  • https://www.cnblogs.com/xinzhao/p/6233009.html

开源地址

MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks


MASA.Contrib:https://github.com/masastack/MASA.Contrib


MASA.Utils:https://github.com/masastack/MASA.Utils


MASA.EShop:https://github.com/masalabs/MASA.EShop


MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor


如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们



发布于: 刚刚阅读数: 2
用户头像

还未添加个人签名 2021.10.26 加入

还未添加个人简介

评论

发布
暂无评论
5. 堪比JMeter的.Net压测工具 - Crank 实战篇 - 接口以及场景压测_C#_MASA技术团队_InfoQ写作平台