介绍并使用 Go 的性能测试工具 wrk。
在项目正式上线之前,我们通常需要通过压测来评估当前系统能够支撑的请求量、排查可能存在的隐藏bug;压力测试(压测)是确保系统在高负载情况下仍能稳定运行的重要步骤。通过模拟高并发场景,可以评估系统的性能瓶颈、可靠性和稳定性,进而优化系统架构和资源配置。
文章目录
- 一、压力测试相关术语
- 二、安装wrk
- 2.1 使用Homebrew 安装
- 2.2 编译安装
- 2.3 测试是否安装成功
- 三、wrk 命令基本使用
- 3.1 常用命令参数
- 3.2 执行测试
- 3.3 输出结果
一、压力测试相关术语
-
响应时间 (
RT
):指系统对请求作出响应的时间。 -
吞吐量 (
Throughput
):指系统在单位时间内处理请求的数量。 -
QPS
(每秒查询率,Query Per Second):“每秒查询率”,是一台服务器每秒能够响应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。 -
TPS
(Transaction Per Second):每秒钟系统能够处理的交易或事务的数量。 -
并发连接数:某个时刻服务器所接受的请求总数。
二、安装wrk
2.1 使用Homebrew 安装
brew install wrk
2.2 编译安装
使用Git 下载源码
# 1. 切换到待安装的目录
cd /usr/local/src
# 2. 免提示(-y), 安装 git
yum install git -y
# 3. 下载 wrk 源码
git clone https://github.com/wg/wrk.git
克隆完成后,进入wrk目录并执行make
命令进行编译。这个命令会编译wrk并生成可执行文件:
# 4. 进入安装文件夹
cd wrk
# 5. 下载 gcc 编译器, 并编译
yum -y install gcc
make
编译成功后,你会得到一个名为wrk
的可执行文件。为了能够在任何目录下运行wrk
,你可以将其移动到系统的PATH
环境变量中的某个目录,或者直接将wrk的目录添加到PATH
环境变量中。如果你不确定如何操作,可以查阅相关的操作系统文档。
在Linux系统中,你可以使用以下命令将wrk添加到PATH
环境变量(假设你的当前用户是user
):
# 6. 创建软连接, 方便全局调用
ln -s /usr/local/src/wrk/wrk /usr/local/bin
2.3 测试是否安装成功
在使用 wrk
之前,你可以通过 wrk --help
命令来查看所有可用的命令行选项。这个命令会输出 wrk
的使用说明和所有支持的参数。
三、wrk 命令基本使用
3.1 常用命令参数
-
-c, --connections
: 每个线程建立的连接数(并发数)。默认值为 200。 -
-d, --duration
: 测试持续时间,例如2s
、2m
、2h
。默认值为 10 秒。 -
-t, --threads
: 用于执行测试的线程数。默认值为 2。 -
-s, --script
: 指定一个 Lua 脚本来处理自定义请求或响应。 -
-H, --header
: 添加 HTTP 请求头,可以多次使用此参数来添加多个头部。 -
--latency
: 打印详细的延迟统计信息。 -
--timeout
: 设置请求超时时间,默认为无穷大。 -
--body
: 指定请求体,可以是一个文件路径或直接的数据。 -
--rate
: 限制请求速率(每秒请求数),默认不限速。
3.2 执行测试
执行如下命令:
wrk -t1 -d1s -c2 -s ./scripts/wrk/signup.lua http://localhost:8080/users/signup
这个命令是使用 wrk
这个 HTTP 压力测试工具来对本地主机上的一个用户注册接口进行测试。下面是命令中每个部分的解释:
-
wrk
: 命令的名称,表示执行wrk
工具。 -
-t1
:-t
选项后面跟着的1
表示使用 1 个线程来进行测试。 -
-d1s
:-d
选项后面跟着的1s
表示测试的持续时间是 1 秒。 -
-c2
:-c
选项后面跟着的2
表示每个线程保持 2 个连接打开。 -
-s ./scripts/wrk/signup.lua
:-s
选项后面跟着的路径./scripts/wrk/signup.lua
表示加载一个 Lua 脚本,这个脚本用于自定义请求或处理响应。在这个例子中,脚本可能是用来模拟用户注册的请求。 -
http://localhost:8080/users/signup
: 这是测试的目标 URL,即本地主机上的用户注册接口,监听在 8080 端口。
综合来看,这个命令会使用 1 个线程在 1 秒内对http://localhost:8080/users/signup
接口发起压力测试,每个线程保持 2 个连接,并且使用./scripts/wrk/signup.lua
脚本来自定义请求的内容,可能是模拟用户注册的行为。
3.3 输出结果
输出结果如下:
Running 1s test @ http://localhost:8080/users/signup
1 threads and 2 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 64.63ms 711.72us 67.28ms 90.00%
Req/Sec 29.80 10.76 40.00 80.00%
30 requests in 1.01s, 3.78KB read
Requests/sec: 29.81
Transfer/sec: 3.76KB
这个输出是 wrk
执行完压力测试后的统计结果。下面是对每个部分的解释:
-
Running 1s test @ http://localhost:8080/users/signup
: 这行显示的是测试的配置,包括测试持续时间(1秒)和测试的目标 URL(本地主机的用户注册接口)。 -
1 threads and 2 connections
: 这行显示的是测试使用的线程数(1个线程)和每个线程建立的连接数(2个连接)。 -
Thread Stats
: 这部分显示的是线程级别的统计信息,包括平均延迟、延迟的标准差、最大延迟以及延迟分布在平均值正负一个标准差内的百分比。-
Avg
: 平均延迟,这里是 64.63 毫秒。 -
Stdev
: 延迟的标准差,这里是 711.72 微秒。 -
Max
: 最大延迟,这里是 67.28 毫秒。 -
+/- Stdev
: 延迟分布在平均值正负一个标准差内的百分比,这里是 90.00%。
-
-
Req/Sec
: 这部分显示的是每秒请求数的统计信息,包括平均请求数、请求数的标准差、最大请求数以及请求数分布在平均值正负一个标准差内的百分比。-
Avg
: 平均每秒请求数,这里是 29.80。 -
Stdev
: 每秒请求数的标准差,这里是 10.76。 -
Max
: 最大每秒请求数,这里是 40.00。 -
+/- Stdev
: 每秒请求数分布在平均值正负一个标准差内的百分比,这里是 80.00%。
-
-
30 requests in 1.01s, 3.78KB read
: 这行显示的是在测试期间总共完成了 30 个请求,耗时 1.01 秒,读取了 3.78KB 的数据。 -
Requests/sec
: 这显示的是平均每秒完成的请求数,这里是 29.81。 -
Transfer/sec
: 这显示的是平均每秒读取的数据量,这里是 3.76KB。
总结来说,这个测试在 1 秒内使用 1 个线程和 2 个连接对本地主机的用户注册接口进行了压力测试,平均每秒可以完成大约 29.81 个请求,平均延迟大约为 64.63 毫秒。
推荐阅读
-
35 岁实现财务*,腾讯程序员手握2300万提前退休?-1000万房产、1000万腾讯股票、加上300万的现金,一共2300万的财产。有网友算了一笔账,假设1000万的房产用于自住,剩下1300万资产按照平均税后20-50万不等进行计算,大约花上26-60年左右的时间才能赚到这笔钱。也就是说,普通人可能奋斗一辈子,才能赚到这笔钱。在很多人还在为中年危机而惶惶不可终日的时候,有的人的35岁,就已经安全着陆,试问哪个打工人不羡慕?但问题是有这样财富积累必然有像样的实力做靠山。没有人可以不劳而获。 看到这里,肯定有人说,那么对于普通人来说,卷可能真就成了唯一的出路。但是卷也有轻松的卷,“偷懒”的卷法,对于程序员而言,刨除掉一时无法改掉的开会传统占用的大部分时间,如何把有限的时间和精力放在真正重要的架构设计、需求设计上,而不是重复的造*,编码、改bug、手动测试。因此在科技改变生活的今天,学会使用AI工具成为程序员们的必备技能。 以全栈式全自动的软件开发工具飞算SoFlu软件机器人为例,作为全球首款面向微服务架构设计和最佳实践的软件机器人,SoFlu软件机器人改变了原来手工编码的作业模式,通过可视化拖拽方式以及参数配置就能实现等同于编写复杂代码的业务逻辑,在设计业务逻辑时就完成了微服务应用开发,做到“业务即图,图即代码”,实现“软件开发,十倍提效”。 而作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)具有五大核心能力: ● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。 ● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。 ● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。 ● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。 ● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。 以“将文件流转换为File对象”这个需求为例,以下是FuncGPT(慧函数)秒级生成的代码: / 类名:FileConverter // 函数名:convertStreamToFile // 函数功能:将文件流转换为File对象 // POM依赖包:无 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class FileConverter { /** * 将文件流转换为File对象 * @param inputStream 文件流 * @param filePath 文件路径 * @param fileName 文件名 * @return 转换后的File对象 * @throws IOException 如果发生I/O异常 */ public static File convertStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException { File file = new File(filePath + File.separator + fileName); // 创建File对象 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 创建文件输出流 byte buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { // 从文件流读取数据并写入文件 outputStream.write(buffer, 0, bytesRead); } } return file; // 返回转换后的File对象 } } // 函数示例 // 将文件流转换为File对象示例 // 入参:inputStream,文件流 // 入参:filePath,文件路径 // 入参:fileName,文件名 // 出参:file,转换后的File对象 // 调用示例: // InputStream inputStream = new FileInputStream("example.txt"); // String filePath = "C:\\Users\\User\\Documents"; // String fileName = "example.txt"; // File file = FileConverter.convertStreamToFile(inputStream, filePath, fileName); // System.out.println(file.getAbsolutePath); // 输出结果:例如,将文件流转换为File对象后,文件的绝对路径为:C:\Users\User\Documents\example.txt // 则输出结果为:C:\Users\User\Documents\example.txt 通过分析,不难发现以上代码:
-
openEuler郑州用户组成立!openEuler与hyperfusion携手共建河南地区用户生态 - 开幕致辞 超融合操作系统业务总经理、openEuler委员会成员蒋振华先生为本次活动致辞。 在本次活动的致辞中,他提到,作为openEuler社区早期的成员,超融合见证了openEuler从成立到在各行业商业落地,再到跨越生态拐点的过程,感谢openEuler提供了一个全产业链共同创新的平台,共同推动创新技术的商业落地。 同时,本次活动得到了郑州市郑东新区大数据管理局、郑州中原科技城投资服务局的大力支持。 郑东新区大数据管理局曹光远 在活动致辞中表示,openEuler的应用和*应用设施的深度优化,为郑东新区数字化转型提供了安全、可靠、高性能的技术基础;郑州中原科技城招商服务局王林表示,郑东新区欢迎所有openEuler生态相关企业扎根当地,围绕openEuler社区共同发展,形成合力。 openEuler社区及运维功能介绍 openEuler技术委员会委员胡峰 openEuler技术委员会委员胡峰先生在本次活动中介绍了openEuler社区目前发展的整体情况,并重点从技术层面介绍了openEuler的运维功能。 openEuler 晚会 胡峰先生介绍智能运维工具 A-Ops 和 openEuler gala、 阿波罗 Apollo、智能漏洞管理解决方案等新功能,以及涵盖各种运维场景的精品运维组件。在*交流环节,许多用户就目前使用的 openEuler 在*交流环节,许多用户就自己在使用openEuler过程中遇到的一些问题与胡峰先生进行了进一步的交流。 软硬结合,构建多样化算力操作系统 Hyperfusion 基于 openEuler 的基础上,结合自身软硬件技术积累,推出了富讯服务器操作系统 FusionOS FusionOS. FusionOS 首席架构师张海亮 分享了 FusionOS FusionOS首席架构师张海亮分享了FusionOS的软硬件协同优势、卓越的性能和可靠性,以及FusionOS在金融、运营商、*、互联网等行业的实践案例,引起了众多用户的兴趣,分享结束后,不少参会者就FusionOS的特点向讲师提问并进行了交流。
-
[姿势估计] 实践记录:使用 Dlib 和 mediapipe 进行人脸姿势估计 - 本文重点介绍方法 2):方法 1:基于深度学习的方法:。 基于深度学习的方法:基于深度学习的方法利用深度学习模型,如卷积神经网络(CNN)或递归神经网络(RNN),直接从人脸图像中学习姿势估计。这些方法能够学习更复杂的特征表征,并在大规模数据集上取得优异的性能。方法二:基于二维校准信息估计三维姿态信息(计算机视觉 PnP 问题)。 特征点定位:人脸姿态估计的第一步是通过特征点定位来检测和定位人脸的关键点,如眼睛、鼻子和嘴巴。这些关键点提供了人脸的局部结构信息,可用于后续的姿势估计。 旋转表示:常见的旋转表示方法包括欧拉角和旋转矩阵。欧拉角通过三个旋转角度(通常是俯仰、偏航和滚动)描述头部的旋转姿态。旋转矩阵是一个 3x3 矩阵,表示头部从一个坐标系到另一个坐标系的变换。 三维模型重建:根据特征点的定位结果,三维人脸模型可用于姿势估计。通过将人脸的二维图像映射到三维模型上,可以估算出人脸的旋转和平移信息。这就需要建立人脸的三维模型,然后通过优化方法将模型与特征点对齐,从而获得姿势估计结果。 特征点定位 特征点定位是用于检测人脸关键部位的五官基础部分,还有其他更多的特征点表示方法,大家可以参考我上一篇文章中介绍的特征点检测方案实践:人脸校正二次定位操作来解决人脸校正的问题,客户在检测关键点的代码上略有修改,坐标转换部分客户见上图 def get_face_info(image). img_copy = image.copy image.flags.writeable = False image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results = face_detection.process(image) # 在图像上绘制人脸检测注释。 image.flags.writeable = True image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) box_info, facial = None, None if results.detections: for detection in results. for detection in results.detections: mp_drawing.Drawing.detection = 无 mp_drawing.draw_detection(image, detection) 面部 = detection.location_data.relative_keypoints 返回面部 在上述代码中,返回的数据是五官(6 个关键点的坐标),这是用 mediapipe 库实现的,下面我们可以尝试用另一个库:dlib 来实现。 使用 dlib 使用 Dlib 库在 Python 中实现人脸关键点检测的步骤如下: 确保已安装 Dlib 库,可使用以下命令: pip install dlib 导入必要的库: 加载 Dlib 的人脸检测器和关键点检测器模型: 读取图像并将其灰度化: 使用人脸检测器检测图像中的人脸: 对检测到的人脸进行遍历,并使用关键点检测器检测人脸关键点: 显示绘制了关键点的图像: 以下代码将参数 landmarks_part 添加到要返回的关键点坐标中。
-
介绍并使用 Go 的性能测试工具 wrk。
-
Java 类加载器的作用 - 简介:类加载器是 Java™ 中一个非常重要的概念。类加载器负责将 Java 类的字节码加载到 Java 虚拟机中。本文首先详细介绍了 Java 类加载器的基本概念,包括代理模型、加载类的具体过程和线程上下文类加载器等。然后介绍了如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™ 中的应用。 类加载器是 Java 语言的一项创新,也是 Java 语言广受欢迎的重要原因之一。它允许将 Java 类动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 开始出现,最初是为了满足 Java Applets 的需求而开发的,Java Applets 需要从远程位置下载 Java 类文件并在浏览器中执行。现在,类加载器已广泛应用于网络容器和 OSGi。一般来说,Java 应用程序的开发人员不需要直接与类加载器交互;Java 虚拟机的默认行为足以应对大多数情况。但是,如果遇到需要与类加载器交互的情况,而您又不太了解类加载器的机制,就很容易花费大量时间调试异常,如 ClassNotFoundException 和 NoClassDefFoundError。本文将详细介绍 Java 的类加载器,帮助读者深入理解 Java 语言中的这一重要概念。下面先介绍一些基本概念。 类加载器的基本概念 顾名思义,类加载器用于将 Java 类加载到 Java 虚拟机中。一般来说,Java 虚拟机以如下方式使用 Java 类:Java 源程序(.java 文件)经 Java 编译器编译后转换为 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码并将其转换为 java.lang 实例。每个实例都用来表示一个 Java 类。通过该实例的 newInstance 方法创建该类的对象。实际情况可能更加复杂,例如,Java 字节代码可能是由工具动态生成或通过网络下载的。 基本上,所有类加载器都是 java.lang.ClassLoader 类的实例。下面将详细介绍这个 Java 类。 java.lang.ClassLoader 类简介 java.lang.ClassLoader 类的基本职责是根据给定类的名称为其查找或生成相应的字节码,然后根据这些字节码定义一个 Java 类,即 java.lang.Class 类的实例。除此之外,ClassLoader 还负责加载 Java 应用程序所需的资源,如图像文件和配置文件。不过,本文只讨论它加载类的功能。为了履行加载类的职责,ClassLoader 提供了许多方法,其中比较重要的方法如表 1 所示。下文将详细介绍这些方法。 表 1.与加载类相关的 ClassLoader 方法
-
每日Go语言库推荐第102期:go-wrk - HTTP性能基准测试工具
-
回顾2015年的HPV病毒基因研究:205种类型的发现,通过Python抓取获取了179个约8KB碱基序列。基于GeneBank或类似ID的批量核酸序列下载实用脚本" 该脚本说明: - 介绍了一个在2015年针对HPV病毒基因进行的研究,其中已确认有205种类型的基因,并通过Python编程从GeneBank获取了179个大约8KB的DNA序列片段。 - 提供了一份简单易用的Python脚本,用户只需提供一行一个含有相关ID(如GeneBank ID)的文本文件作为输入。 - 脚本功能包括随机暂停以避免过于频繁的请求,适用于快速、大批量地下载指定ID下的核酸序列信息。 - 还提及了关于HBV病毒提取方法的相关文献背景,同时也揭示了当年作者使用Python编写此类工具的经历。
-
如何在CMAK上部署并使用Kafka可视化管理工具 - 测试Kafka-manager的步骤
-
玩转Java底层:JMX详解 - jconsole与自定义MBean监控工具的实际应用与区别" 在日常JVM调优中,我们熟知的jconsole工具通过JMX包装的bean以图形化形式展示管理数据,而像jstat和jmap这类内建监控工具则由JVM直接支持。本文将以jconsole为例,深入讲解其实质——基于JMX的MBean功能,包括可视化界面上的bean属性查看和操作调用。 MBeans在jconsole中的体现是那些可观察的组件属性和方法,如上图所示,通过名为"Verbose"的属性能看到其值为false,同时还能直接操作该bean的方法,例如"closeJerryMBean"。 尽管jconsole给我们提供了直观的可视化界面,但请注意,这里的MBean并非固定不变,开发者可根据JMX提供的接口将自己的自定义bean展示到jconsole。以下步骤展示了如何创建并注册一个名为"StudyJavaMBean"的自定义MBean: 1. 首先定义接口`StudyJavaMBean`,接口需遵循MBean规范,即后缀为"MBean"且包含getter方法代表属性,如`getApplicationName`,和无返回值的setter方法代表操作,如`closeJerryMBean`。 ```java public interface StudyJavaMBean { String getApplicationName(); void closeJerryMBean(); } ``` 2. 编写接口的实现类`StudyJavaMBeanImpl`,实现接口中的方法: ```java public class StudyJavaMBeanImpl implements StudyJavaMBean { @Override public String getApplicationName() { return "每天学Java"; } @Override public void closeJerryMBean() { System.out.println("关闭Jerry应用"); } } ``` 3. 在代码中注册自定义MBean,涉及的关键步骤包括: - 获取平台MBeanServer - 定义ObjectName,指定唯一的MBean标识符 - 注册MBean到服务器 - 启动RMI连接器服务,以便jconsole能够访问 ```java public void registerMBean() throws Exception { // ... 具体实现省略 ... } ``` 实际运行注册后的MBean,您将在jconsole中发现并查看自定义bean的属性和调用相关方法。然而,这种方式相较于传统的属性/日志查看和HTTP接口,实用性相对有限,可能存在潜在的安全风险。但不可否认的是,JMX及其MBean机制对于获取操作系统信息、内存状态等关键性能指标仍然具有重要价值。例如: 1. **获取操作系统信息**:通过JMX MBean,可以直接获取到诸如CPU使用率、操作系统版本等系统级信息,这对于资源管理和优化工作具有显著帮助。
-
轻松上手!Lighthouse(灯塔)前端性能测试工具的使用指南