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

Locust单机多核压测,以及主从节点的数据通信处理!

一、背景

这还是2个月前做的一次接口性能测试,关于locust脚本的单机多核运行,以及主从节点之间的数据通信。

先简单交代下背景,在APP上线之前,需要对登录接口进行性能测试。经过评估,我还是优先选择了locust来进行脚本开发,本次用到了locust的单机多核运行能力,只不过这里还涉及到主从节点之间数据通信。现成的可参考的有效文档甚少,所以还是自己摸着官方文档过河比较靠谱。

顺带提一下,学习框架这种东西最好的教程其实还得是官方文档以及框架源码了,这里贴上locust官方文档链接,需要的可以自行学习:https://docs.locust.io/en/stable/what-is-locust.html

二、代码编写

其实脚本代码的编写一大重点就是如何处理测试数据,不同的测试需求对于测试数据的处理是不同的。比如这次的需求,手机号不能重复。另外考虑到长时间的负载压力,数据量还得足够。

现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:110685036【暗号:csdn999】

最后测试数据还需要处理,那么我使用的测试号段是非真实号码段,测试结束后可以查询对应号段内的手机号,进行相关业务数据的清理。

1. 代码概览

还是老样子,先附上全部代码,然后对其结构进行拆分讲解。

import random
import time
from collections import dequefrom locust import HttpUser, task, run_single_user, TaskSet, events
from locust.runners import WorkerRunner, MasterRunnerCURRENT_TIMESTAMP = str(round(time.time() * 1000))
RANDOM = str(random.randint(10000000, 99999999))
MOBILE_HEADER = {"skip-request-expired": "true","skip-auth": "true","skip-sign": "true","os": "IOS","device-id": "198EA6A4677649018708B400F3DF69FB","nonce": RANDOM,"sign": "12333","version": "1.2.0","timestamp": CURRENT_TIMESTAMP,"Content-Type": "application/json"
}last_mobile = ""
worker_mobile_deque = deque()# 13300120000, 13300160000 新用户注册号段@events.test_start.add_listener
def on_test_start(environment, **_kwargs):if not isinstance(environment.runner, WorkerRunner):mobile_list = []for i in range(13300120000, 13300160000):mobile_list.append(i)mobile_list_length = len(mobile_list)print("列表已生成,总计数量:", mobile_list_length)worker_count = environment.runner.worker_countchunk_size = int(mobile_list_length / worker_count)print(f"平均每个worker分得的手机号数量:{chunk_size}")for i, worker in enumerate(environment.runner.clients):start_index = i * chunk_sizeif i + 1 < worker_count:end_index = start_index + chunk_sizeelse:end_index = len(mobile_list)data = mobile_list[start_index:end_index]environment.runner.send_message("mobile_list", data, worker)def setup_mobile_list(environment, msg, **kwargs):len_msg_data = len(msg.data)print(f"worker收到的master传来的数据号段:{msg.data[0]} ~ {msg.data[len_msg_data-1]}")global worker_mobile_dequeworker_mobile_deque = deque(msg.data)@events.init.add_listener
def on_locust_init(environment, **_kwargs):if not isinstance(environment.runner, MasterRunner):environment.runner.register_message('mobile_list', setup_mobile_list)class VcodeLoginUser(TaskSet):# wait_time = between(5, 5)@taskdef vcode_login(self):test_mobile = worker_mobile_deque.popleft()print("当前获取的手机号:", test_mobile)# print("当前队列大小:", len(worker_mobile_deque))global last_mobilelast_mobile = test_mobilewith self.client.post("/g/sendMobileVcode",headers=MOBILE_HEADER,json={"busiType": "login", "mobile": str(test_mobile)}) as send_response:try:send_response_json = send_response.json()if send_response_json["message"] == "success":params = {"mobile": str(test_mobile), "vcode": "111111"}# print(test_mobile, "登录请求参数:", params)with self.client.post("/g/vcodeLogin",json=params,headers=MOBILE_HEADER,catch_response=True) as login_response:# print(login_response.json)login_response_json = login_response.json()if login_response_json["message"] != "success":login_response.failure("message not equal success")elif login_response_json["code"] != 0:login_response.failure("code not equal 0")elif login_response_json["data"]["rId"] == "":login_response.failure("rid is null")elif login_response_json["data"]["mobile"] != str(test_mobile):login_response.failure("mobile is error,入参手机号{},返回的手机号{}".format(test_mobile, login_response.json()["data"]["mobile"]))# print(test_mobile, "请求结果:", login_response.json())else:send_response.failure("{} send code fail".format(test_mobile))except Exception as e:send_response.failure("send code fail {}".format(e))@events.test_stop.add_listenerdef on_test_stop(environment, **kwargs):print("脚本结束")print("当前队列大小:", len(worker_mobile_deque))print("最后的手机号:", last_mobile)class LocustLogin(HttpUser):tasks = [VcodeLoginUser]host = "https://qa.test.com"if __name__ == '__main__':run_single_user(LocustLogin)

2. 代码拆解-要加必要的断言

首先是基于locust开发的http请求的脚本大结构是不变的,依旧是两大块:HttpUserTaskSet,这里不再对其讲解了,大伙看下官方文档就明白了。

接下来就是类VcodeLoginUser,可以看到在这里面是定义了单个用户的详细动作。注意这里要加上必要的断言。否则仅靠框架的非200外的错误断言还是不够的。

比如我这里关注登录成功后的几个必要字段:coderIdmobile,这些一定是要符合断言的才可以。

果不其然,压测过程中就发现了并发情况下会出现的问题:入参手机号是a,接口返回的手机号是b。并发量越大错误越多。如果我只断言code=0,那么这个问题就不容易发现了,虽然接口返回的code都是成功的,但是业务上已经存在错误了。

...with self.client.post("/g/sendMobileVcode",headers=MOBILE_HEADER,json={"busiType": "login", "mobile": str(test_mobile)}) as send_response:try:send_response_json = send_response.json()if send_response_json["message"] == "success":params = {"mobile": str(test_mobile), "vcode": "111111"}# print(test_mobile, "登录请求参数:", params)with self.client.post("/g/vcodeLogin",json=params,headers=MOBILE_HEADER,catch_response=True) as login_response:# print(login_response.json)login_response_json = login_response.json()if login_response_json["message"] != "success":login_response.failure("message not equal success")elif login_response_json["code"] != 0:login_response.failure("code not equal 0")elif login_response_json["data"]["rId"] == "":login_response.failure("rid is null")elif login_response_json["data"]["mobile"] != str(test_mobile):login_response.failure("mobile is error,入参手机号{},返回的手机号{}".format(test_mobile, login_response.json()["data"]["mobile"]))# print(test_mobile, "请求结果:", login_response.json())else:send_response.failure("{} send code fail".format(test_mobile))except Exception as e:send_response.failure("send code fail {}".format(e))
...

3. 代码拆解-单机多核处理

接下来就是重点了,如何在单台机器上用到多cpu。最开始的时候我忽略了这点,后来发现负载上不去,一打开资源监视器才发现只有1个cpu在满负载运行。

这里示意图仅供参考,我的win笔记本是12c的。

因为Locust是单进程的,不能充分利用多核CPU,于是需要我们压力机上开启一个master进程,然后再开启多个slave进程,组成一个单机分布式系统即可。

开启的方式也很简单:

# 开启 master 
locust -f locustfile.py --master# 开启 slave
locust -f locustfile.py --slave

这里我们开启 slave 节点的时候可以开启对应多个命令行窗口,当时没截图,借用网上的图片示意一下:

开启后,你的web界面就可以实时看到当前启动的节点数了。

4. 代码拆解-处理主从节点数据通信

开启主从节点倒是很容易,测试数据就需要针对性进行处理了。

因为我的测试登录用的手机号不可以重复,所以要保证不同 slave 节点上同时运行的代码产生的手机号都不可以重复。

继续扒了下官方文档,发现可以通过增加事件监听器来实现我的需求。

这里我加了三个监听器分别来处理不同的事情:

  • @events.init.add_listener:在locust运行初始化的时候执行
  • @events.test_start.add_listener: 在测试代码开始运行的时候执行
  • @events.test_stop.add_listener: 在测试代码结束运行的时候执行

@events.test_start.add_listener 首先,在@events.test_start.add_listener里,我主要处理全量数据的生成,以及把这些手机号平均分配给生成的 slave 节点。

@events.test_start.add_listener
def on_test_start(environment, **_kwargs):if not isinstance(environment.runner, WorkerRunner):mobile_list = []for i in range(13300120000, 13300160000):mobile_list.append(i)mobile_list_length = len(mobile_list)print("列表已生成,总计数量:", mobile_list_length)worker_count = environment.runner.worker_countchunk_size = int(mobile_list_length / worker_count)print(f"平均每个worker分得的手机号数量:{chunk_size}")for i, worker in enumerate(environment.runner.clients):start_index = i * chunk_sizeif i + 1 < worker_count:end_index = start_index + chunk_sizeelse:end_index = len(mobile_list)data = mobile_list[start_index:end_index]environment.runner.send_message("mobile_list", data, worker)

注意这里最后一行中定义的mobile_list,需要定义一个对应函数来接收这个数据。

def setup_mobile_list(environment, msg, **kwargs):len_msg_data = len(msg.data)print(f"worker收到的master传来的数据号段:{msg.data[0]} ~ {msg.data[len_msg_data-1]}")global worker_mobile_dequeworker_mobile_deque = deque(msg.data)

这样,不同的 slave 节点脚步分配到的手机号段就是不同的了,解决测试数据重复的问题。

另外,我定义另一个全局变量worker_mobile_deque,这样不同的 slave 节点接收的数据就可以放到队列里,运行的时候从队列里面取,用一个少一个,直到队列里的数据用完。

@events.init.add_listener 接着就是在@events.init.add_listener里要注册上面定义的数据字段和处理函数。

@events.init.add_listener
def on_locust_init(environment, **_kwargs):if not isinstance(environment.runner, MasterRunner):environment.runner.register_message('mobile_list', setup_mobile_list)

@events.test_stop.add_listener 最后,在@events.test_stop.add_listener这里可以做一些后置处理,我是简单起见,只是记录输出了本次测试用到了哪个号码段,这样我下次运行脚本的时候可以从后面的数据开始,最大化测试数据的使用,不浪费。

    @events.test_stop.add_listenerdef on_test_stop(environment, **kwargs):print("脚本结束")print("当前队列大小:", len(worker_mobile_deque))print("最后的手机号:", last_mobile)

三、小结

脚本调试完后可以稳定运行,接下来就是测试的过程了,进行了服务器单节点、多节点负载能力的测试,水平拓展能力的测试,以及服务动态扩容、长时间高负载测试。测试的角度观察测试报告,服务各项指标的情况。只不过涉及到开发端,调优分析的工作并未能参与很多。不过大概还是那些常见问题,后续有机会可以再单独分享了。

从使用角度来看,locust深得我爱,比起 jemter真的太轻便了,代码灵活度也非常高,单机负载能力也是响当当的,这点比jemeter强太多了。我这个项目不需要非常高的量,所以单机只用了8c就够了。如果有小伙伴需要非常高的并发,locust 也支持多机器分布式,进一步扩大并发能力。

END今天的分享就到此结束了!点赞关注不迷路~

相关文章:

Locust单机多核压测,以及主从节点的数据通信处理!

一、背景 这还是2个月前做的一次接口性能测试&#xff0c;关于locust脚本的单机多核运行&#xff0c;以及主从节点之间的数据通信。 先简单交代下背景&#xff0c;在APP上线之前&#xff0c;需要对登录接口进行性能测试。经过评估&#xff0c;我还是优先选择了locust来进行脚…...

ERROR: [pool www] please specify user and group other than root

根据提供的日志信息&#xff0c;PHP-FPM 服务未能启动的原因是配置文件中的一个错误。错误消息明确指出了问题所在&#xff1a; [29-Nov-2023 14:28:26] ERROR: [pool www] please specify user and group other than root [29-Nov-2023 14:28:26] ERROR: FPM initialization …...

京东商品详情接口在电商行业中的重要性及实时数据获取实现

一、引言 随着电子商务的快速发展&#xff0c;商品信息的准确性和实时性对于电商行业的运营至关重要。京东作为中国最大的电商平台之一&#xff0c;其商品详情接口在电商行业中扮演着重要的角色。本文将深入探讨京东商品详情接口的重要性&#xff0c;并介绍如何通过API实现实时…...

WT2003H MP3语音芯片方案:强大、灵活且易于集成的音频解决方案

在当今的数字化时代&#xff0c;音频技术的普遍性已不容忽视。从简单的音乐播放&#xff0c;到复杂的语音交互&#xff0c;音频技术的身影无处不在。在这个背景下&#xff0c;WT2003H MP3语音芯片方案应运而生&#xff0c;它提供了一种强大、灵活且易于集成的音频解决方案。 1…...

机器学习深度学学习分类模型中常用的评价指标总结记录与代码实现说明

在机器学习深度学习算法模型大开发过程中&#xff0c;免不了要对算法模型进行对应的评测分析&#xff0c;这里主要是总结记录分类任务中经常使用到的一些评价指标&#xff0c;并针对性地给出对应的代码实现&#xff0c;方便读者直接移植到自己的项目中。 【混淆矩阵】 混淆矩阵…...

fastapi 后端项目目录结构 mysql fastapi 数据库操作

原文&#xff1a;fastapi 后端项目目录结构 mysql fastapi 数据库操作_mob6454cc786d85的技术博客_51CTO博客 一、安装sqlalchemy、pymysql模块 pip install sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple pip install pymysql -i https://pypi.tuna.tsinghua.edu.…...

研习代码 day47 | 动态规划——子序列问题3

一、判断子序列 1.1 题目 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是"abcde&…...

L1-017:到底有多二

题目描述 一个整数“犯二的程度”定义为该数字中包含2的个数与其位数的比值。如果这个数是负数&#xff0c;则程度增加0.5倍&#xff1b;如果还是个偶数&#xff0c;则再增加1倍。例如数字-13142223336是个11位数&#xff0c;其中有3个2&#xff0c;并且是负数&#xff0c;也是…...

Python多线程使用(二)

使用多个线程的时候容易遇到一个场景&#xff1a;多个线程处理一份数据 使用多线程的时候同时处理一份数据&#xff0c;在threading中提供了一个方法&#xff1a;线程锁 Demo&#xff1a;下订单 现在有多笔订单下单&#xff0c;库存减少 from threading import Thread from t…...

记录一次docker搭建tomcat容器的网页不能访问的问题

tomcat Tomcat是Apache软件基金会的Jakarta项目中的一个重要子项目&#xff0c;是一个Web服务器&#xff0c;也是Java应用服务器&#xff0c;是开源免费的软件。它是一个兼容Java Servlet和JavaServer Pages&#xff08;JSP&#xff09;的Web服务器&#xff0c;可以作为独立的W…...

GPT3年终总结

User You 程序员年度绩效总结 ChatGPT ChatGPT 程序员年度绩效总结通常包括以下几个方面&#xff1a; 目标达成情况&#xff1a; 回顾年初设定的目标&#xff0c;评估在项目完成、技能提升等方面的达成情况。 工作贡献&#xff1a; 强调在项目中的个人贡献&#xff0c;包括…...

Kafka生产者发送消息的流程

Kafka 生产者发送消息的流程涉及多个步骤&#xff0c;从消息的创建到成功存储在 Kafka 集群中。以下是 Kafka 生产者发送消息的主要步骤&#xff1a; 1. 创建消息 生产者首先创建一个消息&#xff0c;消息通常包含一个键&#xff08;可选&#xff09;和一个值&#xff0c;以及…...

基于SSM的数学竞赛网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…...

01-使用Git操作本地库,如初始化本地库,提交工作区文件到暂存区和本地库,查看版本信息,版本切换命令等

Git的使用 概述 Git是一个分布式版本控制工具, 通常用来管理项目中的源代码文件(Java类、xml文件、html页面等)进行管理,在软件开发过程中被广泛使用 Git可以记录文件修改的历史记录并形成备份从而实现代码回溯, 版本切换, 多人协作, 远程备份的功能Git具有廉价的本地库,方便…...

排序算法介绍(二)冒泡排序

0. 简介 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法。它重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排…...

搜索引擎高级用法总结: 谷歌、百度、必应

搜索引擎高级用法总结: 谷歌、百度、必应 google search 基本搜索 逻辑与:and逻辑或: or逻辑非: -完整匹配:“关键词”通配符:* ?高级搜索 intext:后台登录 将只返回正文中包含 后台登录 的网页 intitle intitle:后台登录 将只返回标题中包含 后台登录 的网页,intitle…...

com.intellij.openapi.application.ApplicationListener使用

一般监听期通过如下代码生效 <applicationListeners> <!-- <listener class"com.itheima.taunt.MyApplicationListener"--> <!-- topic"com.intellij.openapi.application.ApplicationListener"…...

常见js hook脚本

一.js hook 过无限debugger var _constructor constructor; Function.prototype.constructor function(s) {if (s "debugger") {console.log(s);return null;}return _constructor(s); }//去除无限debugger Function.prototype.__constructor_back Function.pro…...

Java——SpringLayout弹簧布局

import java.awt.*;import javax.swing.*;public class a {public static void main(String[] args) {new a();}public a() {JFrame JF new JFrame("弹簧布局");// 创建JFrame窗口//设置JPanel的布局管理器为SpringLayoutJPanel JP new JPanel(new SpringLayout())…...

正则表达式及文本三剑客grep sed awk

目录 正则表达式 1.元字符 2.表示次数 3.位置锚定 4.分组或其他 grep sed 语法&#xff1a; 常用选项 脚本格式 例&#xff1a; 查找11点56到12点10的日志 修改文件&#xff0c;找到文件并给其后缀加上er 提取IP地址 提取版本号 提取文件权限 awk 工作原理&…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解

文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...