使用Grafana K6来测测你的系统负载能力
背景
近期我们有个号称会有很高很高并发的系统要上线,为了测试一下自己开发的系统的负载能力,准备了点海克斯科技,来看看抗不抗的住。
之前笔者写过用Apache JMeter进行压力测试的文章(传送门👉:https://xie.infoq.cn/article/9c156894b7374e1bd9bc6271f),这次换成了K6,实在不是因为爱折腾,而因为我们是小团队,没那么多工种,很多事儿基本都是开发自己来,K6在配置上比Jmeter更加简单,而且支持JavaScript脚本,更适合我们的测试场景。
部署环境
安装K6
这部分,其实没什么可多说的,参照官网的手册即可(传送门👉:https://grafana.com/docs/k6/latest/),我是在Ubuntu 22.04系统进行的安装。

*安装vscode
这一步其实可有可无,只是写脚本的话,Linux自带的vi,或者安装一下vim,nano等都完全足够,但我个人还是比较推荐结合vscode的remote-ssh插件,来编写远程服务器上的文件。
尤其是K6的测试脚本是JavaScript脚本,搭配vscode来写的话会更方便一些。
这里安装步骤也不细说了,在vscode插件市场搜索remote-ssh安装即可

如果使用的是wsl2,那会更加方便,进入编写k6脚本的路径下,直接输入
code .
即可在宿主机编写脚本。

测试条件
我这里要测试的对象,是一个在线考试系统,为了尽可能真实的模拟考试行为,我这里准备了几个接口,分别模拟了考试信息加载,身份验证,保存试卷草稿3个使用频率高的接口。
这里我就放一个最主要的,模拟用户保存草稿的接口
/// <summary>
/// 模拟保存草稿
/// </summary>
/// <param name="answer">提交一个长字符传</param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> SaveDraft(SimulateSaveDto dto)
{//模拟验证header的耗时await Task.Delay(new Random().Next(10, 300));int rd = new Random().Next(0, 100);var randomOne = (await _simulation1Repo.getListAsync(u => u.Id > 0))[rd];dto.sid=randomOne.Id;dto.answer = Utils.GenerateRandomCodeFast(new Random().Next(2, 8000));if (dto.answer.Length > CapConsts.CapMsgMaxLength){await _redisCachingProvider.StringSetAsync("tmpSimulate" + dto.sid, dto.answer, TimeSpan.FromMinutes(1));dto.answer = "";}await _capPublisher.PublishAsync(CapConsts.ClientPrefix + "SimulateSaveDraft", dto);Logger.Warning($"{DateTime.Now}:发布事务---模拟提交答案");return Json(_resp.success(dto.sid));
}
简单解释下这段代码,前半部分就是模拟构造了一个包含大字段的参数,因为用户提交的草稿可能会很大,我们目前的业务,光单选题就有100道,题目的id类型都是雪花算法生成的id,所以拼接完也是一个很大的字符,如果包含主观题,就更大了。
这里其实可以增量保存,但因为有其他业务关联,而且增量提交也有问题,比如用户第一份草稿提交的1-10题,到第三份草稿提交的25-30题,第四份又回去改动了第1题或者前面的题,这样又引入了新的复杂逻辑,所以这部分不多说,暂时就是这样全量保存草稿的场景。
后半部分是我使用消息队列的方式,把保存草稿的动作提交到队列里,这里在提交队列的时候做了一个前置处理,就是当答案的字符过长,就把答案暂存到Redis里,保证队列里传输的消息都不大。
一个小坑
之所以这样做,也是压测环节中发现的,因为我是使用PostgreSql来持久化存储的队列消息,EventBus组件用的CAP,当CAP在Pg里创建对列表的时候,会创建对应的索引,而当队列传输的消息过大,会报一个索引超长的错误,当然存储改为SQL Server或者手动把索引删掉就不会有这个问题,但为了确保更高的可用性,还是选择了规避。
事实上,正式接口里这里是采用的分段保存,思路就是分解答案,当字符串长度超过设定的最大长度,我们可以把字符串转成char数组,然后利用linq里对操作数组的chunk方法,分段保存用户答案,就可以避免这个问题了,也不用担心大字段临时存在Redis造成的性能问题,这篇的要点不在这里,就不细聊了。
测试脚本
测试脚本其实写完了回去看,还是挺简单的,但磨人的地方主要是在调整参数的过程,我们要根据系统的实际情况,编写压测的递进参数,尽可能的贴近实际情况,该快的时候快,该慢的时候慢,请求密度要尽可能的大,等等。
好了,直接看下这个脚本吧
import http from 'k6/http';
import { check, sleep } from 'k6';export const options = {thresholds: {checks: ['rate>0.95'], // 至少 95% 的请求必须成功http_req_duration: ['p(95)<500'] // 95% 的请求响应时间小于 500 毫秒}// 设置并发用户数,stages: [{ duration: '10s', target: 10 }, // 起始阶段,10个线程运行30秒{ duration: '30s', target: 100 }, // 在接下来的30秒内将线程数增加到100{ duration: '30s', target: 300 }, // 再接下来的30秒内将线程数增加到300{ duration: '30s', target: 500 }, // 再接下来的30秒内将线程数增加到500{ duration: '30s', target: 800 }, // 再接下来的30秒内将线程数增加到800{ duration: '60s', target: 1000 }, // 再接下来的60秒内将线程数增加到1000{ duration: '120s', target: 1000 } // 保持1000个程运行120秒],
}export default function () {const url = '压测接口';let params = {headers: {'Content-Type': 'application/json'}};let payLoad ={answer:"[]",}let res = http.post(url,payLoad, params);// 解析响应体let response = JSON.parse(res.body);// 定义检查点let checks = {'status code is 200': (r) => r.status === 200,'API code is 0': (r) => response.code === 0};// 执行检查点check(res, checks);// 记录非成功的响应if (response.code !== 0) {console.log(response);//console.log(`Error: code=${response.code}, msg=${response.msg}, data=${JSON.stringify(response.data)}`);}sleep(2)}
控制台打印出来的结果

事实上,控制台打印的这些数据已经足够我们分析问题了,如果我们想更直观的观看压测过程的数据情况,可以开启webdashboard
K6_WEB_DASHBOARD=true k6 run simulatescript.js
压测时,被测系统打印的日志

这样最后生成的报告会像这样👇

最后,其实不论是任何一种压测工具给出的报告,大家其实都不用有什么心智负担,因为现在是AI的时代,当我们想深入了解报告中所有参数的含义时,可以把报告直接扔给大模型,让大模型帮我们解读,这样我们也不用担心我们辛苦写的报告领导看不懂,当然我们自己也能起到促进作用,毕竟谁也不想完全被大模型替代,还是要有自己的见解才好。
好了,基本就这些内容了,下篇再细聊聊系统性能优化过程遇到的问题。
相关文章:
使用Grafana K6来测测你的系统负载能力
背景 近期我们有个号称会有很高很高并发的系统要上线,为了测试一下自己开发的系统的负载能力,准备了点海克斯科技,来看看抗不抗的住。 之前笔者写过用Apache JMeter进行压力测试的文章(传送门👉:https://…...
【论文复现】基于BERT的语义分析实现
📝个人主页🌹:Eternity._ 🌹🌹期待您的关注 🌹🌹 ❀ WRN: 宽度残差网络 概述语义分类文本分类情感分类 实现原理 核心逻辑pre_deal.pytrain.pytest_demo.py 实现方式&演示效果训练阶段测试阶…...
CTF-RE: STL逆向 [NewStarCTF 2023 公开赛道 STL] WP
多看看STL题就会了,很简单 int __fastcall main(int argc, const char **argv, const char **envp) {__int64 v3; // rbx__int64 v4; // raxchar v5; // bl_BYTE *v6; // rax_QWORD *v7; // rax__int64 v8; // rax__int64 v9; // raxint i; // [rsp0h] [rbp-250h]int j; // [r…...
实习冲刺第三十六天
46.全排列 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2: 输入&#…...
【Zemax光学设计实训三】---激光缩束镜的设计优化
前言与目录 技术设计要求: 设计一个激光扩束镜,使用的波长为1064nm,输入光束直径为10mm,输出光束的直径为2mm,且输入光束和输出光束平行(即平行光入射,平行光出射)。要求只使用两片…...
TCP/IP协议簇自学笔记
摘抄于大学期间记录在QQ空间的一篇自学笔记,当前清理空间,本来想直接删除掉的,但是感觉有些舍不得,因此先搬移过来。 曾经,我只知道socket函数能进行网络间数据的通信,知道tcp/ip协议也是用来进行网络数据…...
Spring Boot教程之十一:获取Request 请求 和 Put请求
如何在 Spring Boot 中获取Request Body? Java 语言是所有编程语言中最流行的语言之一。使用 Java 编程语言有几个优点,无论是出于安全目的还是构建大型分发项目。使用 Java 的优点之一是 Java 试图借助类、继承、多态等概念将语言中的每个概念与现实世…...
计算机网络(二)
ip地址:11010010:01011110:00100100:00010100 子网掩码:11111111:11111111:11111111:11000000 and :11010010:01011110:00100100:00000000 210.94.36.0的下一站为R1 因为255为11111111 192为ÿ…...
如何在Python中进行数学建模?
数学建模是数据科学中使用的强大工具,通过数学方程和算法来表示真实世界的系统和现象。Python拥有丰富的库生态系统,为开发和实现数学模型提供了一个很好的平台。本文将指导您完成Python中的数学建模过程,重点关注数据科学中的应用。 数学建…...
JavaSE——类与对象(5)
一、抽象类 1.1为什么需要抽象类 父类的某些方法,不确定怎么实现,也不需要实现。 class Animal{public String name;public Animal(String name){this.name name;}public void eat()//这里实现了也没有意义{System.out.println("这是一个动物&am…...
Istio笔记01--快速体验Istio
Istio笔记01--快速体验Istio 介绍部署与测试部署k8s安装istio测试istio 注意事项说明 介绍 Istio是当前最热门的服务网格产品,已经被广泛应用于各个云厂商和IT互联网公司。企业可以基于Istio轻松构建服务网格,在接入过程中应用代码无需更改,…...
面试小札:Java如何实现并发编程
多线程基础 继承Thread类 定义一个类继承自 Thread 类,重写 run 方法。在 run 方法中编写线程要执行的任务逻辑。例如: java class MyThread extends Thread { Override public void run() { System.out.println("线程执行的任务…...
java-a+b 开启java语法学习
代码 (ab) import java.util.Scanner; //导入 java.util包中的Scanner 类,允许读取键盘输入数据public class Main { // 创建一个公共类 Mainpublic static void main(String[] args) {//程序入口点,main方法Scanner scanner new Scanner(…...
RNN模型文本预处理--数据增强方法
数据增强方法 数据增强是自然语言处理(NLP)中常用的一种技术,通过生成新的训练样本来扩充数据集,从而提高模型的泛化能力和性能。回译数据增强法是一种常见的数据增强方法,特别适用于文本数据。 回译数据增强法 定义…...
maven 中<packaging>pom</packaging>配置使用
在 Maven 项目的 pom.xml 文件中, 元素用于指定项目的打包类型。默认情况下,如果 元素没有被显式定义,Maven 会假设其值为 jar。但是,当您设置 pom 时,这意味着该项目是一个 POM(Project Object Model&…...
【Python中while循环】
一、深拷贝、浅拷贝 1、需求 1)拷贝原列表产生一个新列表 2)想让两个列表完全独立开(针对改操作,读的操作不改变) 要满足上述的条件,只能使用深拷贝 2、如何拷贝列表 1)直接赋值 # 定义一个…...
【深度学习】服务器常见命令
1、虚拟环境的安装位置 先进入虚拟环境 which python2、升序查看文件内容 ls -ltr3、查看服务器主机空间使用情况 df -hdf -h .4、查看本地空间使用情况 du -sh ./*du -sh * | sort -nr5、查找并删除进程 # 查找 ps aux# 删除 kill -KILL pid6、查看服务器配置 lscpuuna…...
技术分析模板
文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示:这里可以添加技术概要 例如: openAI 的 GPT 大模型的发展历程。 整体架构流程 提示:这里可以添加技术整体架构 例如: 在语言模型中,编码器和解码器…...
python:文件操作
一、文件路径 在Windows系统中,每个磁盘都有自己的根目录,用分区名加反斜杠来表示。我们定位文件的位置有两种方法,一种是绝对路径,另一种是相对路径。绝对路径是从根目录出发的路径,路径中的每个路径之间用反斜杠来分…...
Nginx和Apache有什么异同?
Nginx和Apache都是广泛使用的Web服务器软件,它们各自具有独特的特点和优势,适用于不同的应用场景。以下是关于Nginx和Apache的不同、相同以及使用区别的详细分析: 一、不同点 资源占用与并发处理能力: Nginx使用更少的内存和CPU资…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
