php简易企业网站源码,做电商网站一般要多少钱,html网站开发实验报告,做网站的为什么不给域名和密码背景
近期我们有个号称会有很高很高并发的系统要上线#xff0c;为了测试一下自己开发的系统的负载能力#xff0c;准备了点海克斯科技#xff0c;来看看抗不抗的住。
之前笔者写过用Apache JMeter进行压力测试的文章#xff08;传送门#x1f449;#xff1a;https://…背景
近期我们有个号称会有很高很高并发的系统要上线为了测试一下自己开发的系统的负载能力准备了点海克斯科技来看看抗不抗的住。
之前笔者写过用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或者安装一下vimnano等都完全足够但我个人还是比较推荐结合vscode的remote-ssh插件来编写远程服务器上的文件。
尤其是K6的测试脚本是JavaScript脚本搭配vscode来写的话会更方便一些。
这里安装步骤也不细说了在vscode插件市场搜索remote-ssh安装即可 如果使用的是wsl2那会更加方便进入编写k6脚本的路径下直接输入
code .即可在宿主机编写脚本。 测试条件
我这里要测试的对象是一个在线考试系统为了尽可能真实的模拟考试行为我这里准备了几个接口分别模拟了考试信息加载身份验证保存试卷草稿3个使用频率高的接口。
这里我就放一个最主要的模拟用户保存草稿的接口
/// summary
/// 模拟保存草稿
/// /summary
/// param nameanswer提交一个长字符传/param
/// returns/returns
[HttpPost]
public async TaskIActionResult 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.sidrandomOne.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: [rate0.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_DASHBOARDtrue k6 run simulatescript.js 压测时被测系统打印的日志 这样最后生成的报告会像这样 最后其实不论是任何一种压测工具给出的报告大家其实都不用有什么心智负担因为现在是AI的时代当我们想深入了解报告中所有参数的含义时可以把报告直接扔给大模型让大模型帮我们解读这样我们也不用担心我们辛苦写的报告领导看不懂当然我们自己也能起到促进作用毕竟谁也不想完全被大模型替代还是要有自己的见解才好。
好了基本就这些内容了下篇再细聊聊系统性能优化过程遇到的问题。