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

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:5010crankAgent2:jobs:load:endpoints:- http://localhost:5011crankAgent3:jobs:load:endpoints:- http://localhost:5012crankAgent4:jobs:load:endpoints:- http://localhost:5013crankAgent5:jobs:load:endpoints:- http://localhost:5014crankAgent6: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 # 预热时间: 3sduration: 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.ymljobs:server:source:repository: https://github.com/doddgu/crankbranchOrCommit: sampleproject: samples/hello/hello.csprojreadyStateText: Application started.scenarios:api:application: # 实际压测项目时可移除此节点,此处是为模拟应用服务启动job: servervariables:duration: 1load:job: wrk2variables:serverPath: /user/getscript: request.luaduration: 1profiles: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,欢迎联系我们

5820a4e02f6c90a4156ba434dc500fea.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290382.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Destroying the bus stations

Destroying the bus stationsTime Limit: 1000MS Memory Limit: 65536KTotal Submissions: 1832 Accepted: 595Description Gabiluso is one of the greatest spies in his country. Now hes trying to complete an “impossible” mission - to make it slow for the army of …

Pytorch快速入门笔记

Pytorch 入门笔记1. Pytorch下载与安装2. Pytorch的使用教程2.1 Pytorch设计理念及其基本操作2.2 使用torch.nn搭建神经网络2.3 创建属于自己的Dataset和DataLoader2.3.1 编写Dataset类2.3.2 编写Transform类2.3.3 将Transform融合到Dataset中去2.3.4 编写DataLoader类2.4 使用…

详解用65行javascript代码做Flappy Bird

点击查看特效JavaScript做Flappy Bird游戏,代码仅仅65行资源包括:javascript源码:phaser.min.js;main.js;index.html素材:两张图片!素材PS:素材源码下载来我的前端群570946165&#…

模板使用的一个坑

html模板相信很多人都用过,类似angular中的指令,通过模板对于html中很多相似的片段完全可以借助for循环或者ng-repeat指令来生成,大大提高效率。 最近在使用模板时候碰到一个坑,分享出来,希望对后来者有所帮助。 重构之…

C和指针之数组编程练习5 (矩阵相乘)

1、问题 5.如果A是个x行y列的矩阵,B是个y行z列的矩阵,把A和B相乘,其结果将是另一个x行z列的矩阵C。这个矩阵的每个元素是由下面的公式决定的: 例如: 结果矩阵中14这个值是通过2-2加上-6-3得到的,编写一个函数,用于执行两个矩阵的乘法。函数的原型如下: void matrix_mul…

我的技术回顾因ABP框架触发DevOps云原生之路-2020年

我的技术回顾:2015年:我的技术回顾那些与ABP框架有关的故事-2015年2016年:从ABP框架国内社区发展回顾.NET技术变迁-2016年2017年:我的技术回顾那些与ABP框架有关的故事-2017年2018年:我的技术回顾那些与ABP框架有关的故…

半身头像

画的好丑。。。继续加油 转载于:https://www.cnblogs.com/manlurensheng/p/4102631.html

Swift - 操作SQLite数据库(引用SQLite3库)

SQLite轻量级数据库在移动应用中使用非常普遍,但是目前的库是C编写的,为了方便使用,对SQLite相关的操作用Swift进行了封装。这个封装代码使用了一个开源项目SQLiteDB,地址是:https://github.com/fahimf/sqlitedb 重要事…

最长单调递增子序列

1.问题描述:求一个正整数序列的最长单调自增子序列,子序列不要求是连续的。例如Input:55 2 4 3 1Output:22. 算法复杂度是O(N*N)f[i]是以a[i]为最大值的子序列,那么f[]的最大值就是要的结果。int f[],a[];f[0] 1;for(…

如何在Clion中使用C++调用Python代码

在很多时候,我们需要在一个c工程项目中调用部分Python代码,这就需要我们实现Python和C之间的交互。交互方式有两种:1. 依靠 TCP 建立的网络通信交互;2. 嵌入式混合语言编程(Embedding Code)。这里主要介绍后…

C和指针之数组编程练习8(8皇后问题)

1、问题 *在88格的国际象棋上摆放八个皇后,使其不能互相攻击 *即任意两个皇后都不能处于同一行、同一列或同一斜线上, *问有多少种摆法,并把所有合法的二维数组打印出来 2、代码实现 #include <stdio.h> #include <stdlib.h>/***在88格的国际象棋上摆放…

.NET6之MiniAPI(二十四):用Polly重试

为了保障系统的稳定和安全&#xff0c;在调用三方服务时&#xff0c;可以增加重试和熔断。重试是调用一次失败后再试几试&#xff0c;避免下游服务一次闪断&#xff0c;就把整个链路终止&#xff1b;熔断是为了防止太多的次数的无效访问&#xff0c;导致系统不可知异常。Polly是…

android项目中单实例数据库类

一、数据库操作package com.ping.db;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper;/** * describe <数据库操作> */p…

求职准备

昨天下班回家等车时&#xff0c;我一个知道我年底要离职的同事问我&#xff0c;你有没有开始找工作啊&#xff1f;我说还没有。她就疑惑我怎么那么淡定。事实上&#xff0c;虽然我确实并没有开始注册什么求职网站以及写简历&#xff0c;但是我的准备工作却早已开始。包括在这里…

jQuery-DOM操作之属性、class

1、属性操作 1&#xff09;、attr()--获取和设置属性 <script type"text/javascript">$(function(){var $p $(p);var p_txt $p.attr(title); //获取p元素属性title的值alert(p_txt);$(p).attr(title,love); //设置单个的属性值$(p).attr({class:love,id:fo…

CLion 中使用 C++ 版本的 OpenCV

配置环境&#xff1a; Windows 10CLion 2020OpenCV 3.4.1MinGW-w64 1. 下载 CLion 并配置好 MinGW CLion 下载地址&#xff1a;https://www.jetbrains.com/clion MinGW 安装包下载地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1c00uHbcf_jGeDDrVg99jtA 提取码&…

C和指针之auto和内存栈和register关键字

1、auto 在C代码中每个函数都有其生命周期(也称作用域),在函数生命周期中声明的变量通常叫做局部变量,也叫自动变量。例如: 复制代码代码如下: int chenyu(){ int a = 10; // auto int a = 10; return 0; } 整型变量a在fun函数内声明,其作用域为chenyu函数内…

如何理解 C# 中的 System.Void 类型?

咨询区 ordag我知道方法声明成 void 表示不返回什么东西&#xff0c;但我发现在 C# 中 void 不仅仅是一个关键词&#xff0c;而且还是一个真实的类型。void 是 System.Void 的别名&#xff0c;就像 int 的别名是 System.Int32 一样&#xff0c;但为什么不允许直接使用Void类型呢…

ArrayList 的实现原理

ArrayList 是List接口的可变数组的实现。实现了所有可选列表的操作&#xff0c;并包括null值在内的所有元素。此类还提供了一些方法来操作内部用来存储列表的数组大小。 ArrayList 的是实现&#xff1a; 对于ArrayList而言&#xff0c;他实现List接口、底层使用数组保存所有元…

获得手机的ip

本文转载至 http://blog.csdn.net/showhilllee/article/details/8746114 iosip手机貌似ASI里获取ip地址的链接不可以了。也曾试过whatismyip&#xff0c;在其网站上的截图获取的ip是正确的&#xff0c;单不知道为什么在我这里却是错误的。所以&#xff0c;在这里分享一下获得手…