当前位置: 首页 > news >正文

使用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来测测你的系统负载能力

背景 近期我们有个号称会有很高很高并发的系统要上线&#xff0c;为了测试一下自己开发的系统的负载能力&#xff0c;准备了点海克斯科技&#xff0c;来看看抗不抗的住。 之前笔者写过用Apache JMeter进行压力测试的文章&#xff08;传送门&#x1f449;&#xff1a;https://…...

【论文复现】基于BERT的语义分析实现

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 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 &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&#xff1a; 输入&#…...

【Zemax光学设计实训三】---激光缩束镜的设计优化

前言与目录 技术设计要求&#xff1a; 设计一个激光扩束镜&#xff0c;使用的波长为1064nm&#xff0c;输入光束直径为10mm&#xff0c;输出光束的直径为2mm&#xff0c;且输入光束和输出光束平行&#xff08;即平行光入射&#xff0c;平行光出射&#xff09;。要求只使用两片…...

TCP/IP协议簇自学笔记

摘抄于大学期间记录在QQ空间的一篇自学笔记&#xff0c;当前清理空间&#xff0c;本来想直接删除掉的&#xff0c;但是感觉有些舍不得&#xff0c;因此先搬移过来。 曾经&#xff0c;我只知道socket函数能进行网络间数据的通信&#xff0c;知道tcp/ip协议也是用来进行网络数据…...

Spring Boot教程之十一:获取Request 请求 和 Put请求

如何在 Spring Boot 中获取Request Body&#xff1f; Java 语言是所有编程语言中最流行的语言之一。使用 Java 编程语言有几个优点&#xff0c;无论是出于安全目的还是构建大型分发项目。使用 Java 的优点之一是 Java 试图借助类、继承、多态等概念将语言中的每个概念与现实世…...

计算机网络(二)

ip地址&#xff1a;11010010&#xff1a;01011110:00100100:00010100 子网掩码:11111111:11111111:11111111:11000000 and &#xff1a;11010010&#xff1a;01011110&#xff1a;00100100&#xff1a;00000000 210.94.36.0的下一站为R1 因为255为11111111 192为&#xff…...

如何在Python中进行数学建模?

数学建模是数据科学中使用的强大工具&#xff0c;通过数学方程和算法来表示真实世界的系统和现象。Python拥有丰富的库生态系统&#xff0c;为开发和实现数学模型提供了一个很好的平台。本文将指导您完成Python中的数学建模过程&#xff0c;重点关注数据科学中的应用。 数学建…...

JavaSE——类与对象(5)

一、抽象类 1.1为什么需要抽象类 父类的某些方法&#xff0c;不确定怎么实现&#xff0c;也不需要实现。 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是当前最热门的服务网格产品&#xff0c;已经被广泛应用于各个云厂商和IT互联网公司。企业可以基于Istio轻松构建服务网格&#xff0c;在接入过程中应用代码无需更改&#xff0c;…...

面试小札:Java如何实现并发编程

多线程基础 继承Thread类 定义一个类继承自 Thread 类&#xff0c;重写 run 方法。在 run 方法中编写线程要执行的任务逻辑。例如&#xff1a; java class MyThread extends Thread { Override public void run() { System.out.println("线程执行的任务…...

java-a+b 开启java语法学习

代码 &#xff08;ab) import java.util.Scanner; //导入 java.util包中的Scanner 类&#xff0c;允许读取键盘输入数据public class Main { // 创建一个公共类 Mainpublic static void main(String[] args) {//程序入口点&#xff0c;main方法Scanner scanner new Scanner(…...

RNN模型文本预处理--数据增强方法

数据增强方法 数据增强是自然语言处理&#xff08;NLP&#xff09;中常用的一种技术&#xff0c;通过生成新的训练样本来扩充数据集&#xff0c;从而提高模型的泛化能力和性能。回译数据增强法是一种常见的数据增强方法&#xff0c;特别适用于文本数据。 回译数据增强法 定义…...

maven 中<packaging>pom</packaging>配置使用

在 Maven 项目的 pom.xml 文件中&#xff0c; 元素用于指定项目的打包类型。默认情况下&#xff0c;如果 元素没有被显式定义&#xff0c;Maven 会假设其值为 jar。但是&#xff0c;当您设置 pom 时&#xff0c;这意味着该项目是一个 POM&#xff08;Project Object Model&…...

【Python中while循环】

一、深拷贝、浅拷贝 1、需求 1&#xff09;拷贝原列表产生一个新列表 2&#xff09;想让两个列表完全独立开&#xff08;针对改操作&#xff0c;读的操作不改变&#xff09; 要满足上述的条件&#xff0c;只能使用深拷贝 2、如何拷贝列表 1&#xff09;直接赋值 # 定义一个…...

【深度学习】服务器常见命令

1、虚拟环境的安装位置 先进入虚拟环境 which python2、升序查看文件内容 ls -ltr3、查看服务器主机空间使用情况 df -hdf -h .4、查看本地空间使用情况 du -sh ./*du -sh * | sort -nr5、查找并删除进程 # 查找 ps aux# 删除 kill -KILL pid6、查看服务器配置 lscpuuna…...

技术分析模板

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; openAI 的 GPT 大模型的发展历程。 整体架构流程 提示&#xff1a;这里可以添加技术整体架构 例如&#xff1a; 在语言模型中&#xff0c;编码器和解码器…...

python:文件操作

一、文件路径 在Windows系统中&#xff0c;每个磁盘都有自己的根目录&#xff0c;用分区名加反斜杠来表示。我们定位文件的位置有两种方法&#xff0c;一种是绝对路径&#xff0c;另一种是相对路径。绝对路径是从根目录出发的路径&#xff0c;路径中的每个路径之间用反斜杠来分…...

Nginx和Apache有什么异同?

Nginx和Apache都是广泛使用的Web服务器软件&#xff0c;它们各自具有独特的特点和优势&#xff0c;适用于不同的应用场景。以下是关于Nginx和Apache的不同、相同以及使用区别的详细分析&#xff1a; 一、不同点 资源占用与并发处理能力&#xff1a; Nginx使用更少的内存和CPU资…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...