Locust使用笔记

1. Locust是什么

Locust是一种开源性能测试工具,它使用Python语言编写,支持使用简单的代码创建并发用户,并模拟这些用户对Web应用程序的负载进行压力测试。使用Locust,您可以轻松模拟数千个并发用户的操作,并在测试过程中测量Web应用程序的性能。

2. Locust特点

  • 使用Python语言编写,易于学习和使用。
  • 使用Master/Worker结构,支持分布式压力测试。
  • 支持使用脚本编写测试用例,并支持HTTP、WebSockets、TCP等多种协议。
  • 提供可视化的Web界面,可以实时监控测试性能和执行结果。
  • 支持使用Python代码编写测试用例,灵活可控。
  • 支持使用命令行或通过API接口对测试进行控制和管理。

3. Locust实现原理

3.1 核心类

  • HttpUser:HttpUser是Locust中用于编写HTTP请求的用户类。通过继承HttpUser,您可以定义测试用户的行为和操作,例如发送HTTP GET/POST请求、等待时间、测试负载等。
  • User:User是Locust中的用户类,用于模拟网络协议之间的通信,例如 TCP 协议等,支持同时模拟多个用户的并发行为和操作。您可以使用User类的子类来定义多个用户,并在测试执行时模拟并发并发访问。
  • SequentialTaskSet/TaskSequence/TaskSet:TaskSequence是Locust中用于描述测试任务序列的基础类。通过继承TaskSequence,您可以定义一系列测试任务,以模拟用户操作的流程和顺序。TaskSet是TaskSequence的高级实现,支持更复杂的任务解决方案。SequentialTaskSet继承于 TaskSet,多个任务之间是串行执行的,即完成一个任务才会去执行下一个任务。具体区别参照以下样例。
  • Event:有时需要在运行的特定时间执行某些操作。针对这种需求,Locust 提供了事件钩子 (event hooks)。

3.2 常用方法

  • client.get(url, **kwargs):发送HTTP GET请求。
  • client.post(url, data=None, json=None, **kwargs):发送HTTP POST请求。
  • client.put(url, data=None, **kwargs):发送HTTP PUT请求。
  • client.delete(url, **kwargs):发送HTTP DELETE请求。
  • client.head(url, **kwargs):发送HTTP HEAD请求。
  • client.patch(url, data=None, **kwargs):发送HTTP PATCH请求。
  • between(min_wait, max_wait):设置任务之间的等待时间范围,单位S。
  • task(weight=1):装饰测试函数,指定测试函数的权重、优先级,默认:1。

4. Locust常用库

  • Flask:Web框架,用于构建Web界面。
  • gevent:Python协程库,提供高效的并发I/O支持。
  • psutil:跨平台库,用于查询操作系统和进程信息。
  • pygal:Python SVG图表生成库。
  • pyzmq:Python ZeroMQ机制,用于实现分布式测试和消息传递。
  • requests:Python HTTP库,用于发送HTTP请求。

5. Locust安装

5.1 安装Python

在使用Locust之前,您需要先安装Python。Locust需要使用Python3.6或更高版本。

Linux和macOS用户可以通过以下命令安装Python:

$ sudo apt-get install python3

Windows用户可以通过以下链接下载Python安装程序:https://www.python.org/downloads/windows/

5.2 安装Locust

在安装完Python之后,您可以通过使用pip命令来安装Locust。在命令行终端中,运行以下命令即可完成Locust的安装:

$ pip install locust

在安装完成之后,您可以通过运行以下命令来检查Locust的版本:

$ locust -V

5.3 安装pyzmq

如果打算运行Locust 分布在多个进程/机器,需要安装pyzmq:

$ pip install pyzmq

6. Locust基础使用模板

假设我们需要测试一个社交网站,其中,用户可以发布帖子、查看帖子列表等 API,下面是一个实现这些操作的 Locust 测试:

from locust import HttpUser, SequentialTaskSet, task, between, constant

# 定义一个任务集合,包含一组序列任务
class UserBehavior(SequentialTaskSet):
    
    # 用户登录
    def login(self):
        # prepare data
        username = 'testuser'
        password = 'testpass'
        
        # 发送登录请求
        response = self.client.post('/login', json={
            'username': username,
            'password': password
        },catch_response=True)
        
        # 校验登录结果
        if response.status_code == 200:
            self.auth_token = response.json().get('auth_token')
            print("Login successfully, got auth_token:", self.auth_token)
        else:
            print("Failed to login:", response.status_code, response.json())

    # 用户退出登录
    def logout(self):
        # 发送退出登录请求
        response = self.client.post('/logout', headers={
            'Authorization': 'Bearer ' + self.auth_token
        },catch_response=True)

        # 校验退出登录结果
        if response.status_code == 200:
            print("Logout successfully")
            self.interrupt()
        else:
            print("Failed to logout:", response.status_code, response.content)    
    
    # 前置:登录
    def on_start(self):
        self.login()

    # 后置:退出
    def on_start(self):
        self.logout()

    # 任务1: 用户发帖
    @task
    def post_content(self):
        # prepare data
        title = 'title_' + str(randint(1000, 9999))
        content = 'content_' + str(randint(1000, 9999))

        # 发送发帖请求
        response = self.client.post('/posts', json={
            'title': title,
            'content': content
        }, headers={
            'Authorization': 'Bearer ' + self.auth_token
        },catch_response=True)

        # 校验发帖结果
        if response.status_code == 201:
            print("Post successfully:", title)
        else:
            print("Failed to post:", response.status_code, response.content)

    # 任务2: 用户查看帖子列表
    @task
    def view_posts(self):
        # 发送查帖子列表请求
        response = self.client.get('/posts', headers={
            'Authorization': 'Bearer ' + self.auth_token
        },catch_response=True)

        # 校验查帖子列表结果
        if response.status_code == 200:
            post_list = response.json()
            if len(post_list) > 0:
                print("View posts successfully, got post number:", len(post_list))
            else:
                print("No posts found")
        else:
            print("Failed to view posts:", response.status_code, response.content)


# 定义 Locust 测试用户
class WebsiteUser(HttpUser):
    tasks = [UserBehavior]
    wait_time = between(0.5, 1)

在上面的代码中,我们在 SequentialTaskSet 中定义了一个由四个任务组成的序列,分别是:发帖、查看帖子列表。在运行测试时,每个用户将执行这个序列中的任务,依次模拟用户的行为。

同时注意,我们在每个请求中都在 header 中加入了 Authorization,用于传递用户身份认证信息。另外,在每个任务执行完以后,我们需要校验响应的状态码和内容是否满足预期,例如在发帖任务中,只有在收到 HTTP 状态码为 201 时,才定义这个请求已经成功。

样例说明SequentialTaskSet/TaskSequence/TaskSet 主要区别:

  1. SequentialTaskSet

继承于 TaskSet,多个任务之间是串行执行的,即完成一个任务才会去执行下一个任务。

应用场景:

  • 建立会话
  • 踢出其他同名登录
  1. TaskSet

多个任务之间并行执行。

应用场景:

  • 并行执行多个接口
  • 测试多个逻辑代码
  1. TaskSequence
    是一个新的概念,它在 Locust 1.4 版本中引入。在使用上,TaskSequence 类似于组合模式,将多个 TaskSet 按照顺序组合成一个序列,从而实现一个业务流程的测试。

如果需要在任务集合之间加上一些固定的等待时间,可以使用 wait_time 参数指定;如果需要在任务之间加上随机时间间隔,可以使用 between 函数自定义起始和结束等待时间。

下面是一个使用 TaskSet 的样例:

from locust import HttpUser, TaskSet, between, task

class UserBehavior(TaskSet):
    @task
    def task1(self):
        self.client.post("/task1")
    
    @task
    def task2(self):
        self.client.post("/task2")
    
    @task
    def task3(self):
        self.client.post("/task3")

class MyUser(HttpUser):
    tasks = [UserBehavior]
    wait_time = between(1, 2)

下面是一个使用 SequentialTaskSet 的样例:

from locust import HttpUser, TaskSet, SequentialTaskSet, between, task

class UserBehavior(SequentialTaskSet):
    @task
    def task1(self):
        self.client.post("/login")
    
    @task
    def task2(self):
        self.client.post("/post")
    
    @task
    def task3(self):
        self.client.post("/logout")
    
class MyUser(HttpUser):
    tasks = [UserBehavior]
    wait_time = between(1, 2)

在可以预料到的情况下,如果您的任务是顺序执行的,推荐使用 SequentialTaskSet;如果您的任务相互独立且不需要按特定顺序执行,则考虑使用 TaskSet

下面是一个使用 TaskSequence 的样例:

假设我们要对某个社交网站进行压力测试,测试场景如下:

  • 用户登录
  • 用户发帖
  • 用户评论
  • 用户点赞
  • 用户查看帖子列表

我们可以将以上活动分别封装到 TaskSet 中作为独立的任务:

class Login(TaskSet):
  def on_start(self):
      self.client.post('/login', json={'username': 'test', 'password': 'test'})
      

class Post(TaskSet):
  @task
  def post_new(self):
      self.client.post('/post', json={'title': 'newpost', 'content': 'newcontent'})

  
class Comment(TaskSet):
  @task
  def comment(self):
      self.client.post('/comment', json={'post_id': 1, 'content': 'good post!'})
      
  
class Like(TaskSet):
  @task
  def like(self):
      self.client.post('/like', json={'post_id': 1})
      

class ViewPosts(TaskSet):
  @task
  def view_list(self):
      self.client.get('/posts')

接下来,我们可以在测试用户中,通过组合以上活动来模拟用户的真实流程:

class SocialNetworkUser(TaskSequence):
    tasks = [Login, Post, Comment, Like, ViewPosts]
    wait_time = constant(2)

上面的测试用户实现了一个标准的业务流,从用户登录开始,依次完成发帖、评论、点赞和查看帖子等操作,每个任务间隔2秒(wait_time = 2)。

TaskSequence 通过将多个 TaskSet 按顺序连接,来实现业务流的测试,提高测试编写和维护的效率。而 TaskSet 则一般用来定义一组并行的任务,例如同时并发发送多个请求。

7. Locust高级用法:

数据关联

在一些复杂的测试场景中,需要依赖上一请求返回的结果作为下一次请求的参数,这就需要用到数据关联的功能。

示例代码:

from locust import HttpUser, task, between

class MyUser(HttpUser):
    @task
    def get_session(self):
        response = self.client.post("/sessions")
        session_id = response.json()["id"]
        self.user_data = {"session_id": session_id}
    
    @task
    def get_user_profile(self):
        self.client.get(f"/user/{self.user_data['session_id']}/profile")

在上面的例子中,get_user_profile 函数需要依赖 get_session 函数返回的结果,因此,我们在 get_session 函数中用 User 类的属性(self.user_data)保存了所需要的数据,并在下一次请求中引用该数据。

参数化

在测试场景中,我们可能需要使用不同的参数进行多次请求,这就需要用到参数化的功能。

示例代码:

from locust import HttpUser, task, between

class MyUser(HttpUser):
    WAIT_TIME = between(1, 2)
    
    @task
    def search(self):
        self.client.get(f"/search", params={"keyword": self.random_keyword()})
        
    def random_keyword(self):
        keywords = ["apple", "banana", "orange"]
        return random.choice(keywords)

在上面的例子中,关键字 keyword 仅仅是为了演示参数化的例子。我们在 search 函数中,使用 self.random_keyword() 获取随机的一个关键字,并通过 params 参数对搜索接口进行调用。

思考时间

在测试场景中,如果一直让模拟用户间隔同样的时间发起请求,可能会对系统产生不同于实际的负载。因此,可以使用思考时间的功能,让模拟用户在一定时间后再发起请求。

示例代码:

from locust import HttpUser, task, between

class MyUser(HttpUser):
    WAIT_TIME = between(1, 2)
    
    @task
    def search(self):
        self.client.get(f"/search")
        self.think_time()
        
    def think_time(self):
        time.sleep(random.uniform(0.3, 0.5))

在上面的例子中,我们定义了 think_time 函数,用于控制思考时间。在 search 函数中,调用 think_time 函数,让模拟用户在发起两次搜索请求之间休息一段时间。

权重

在某些场景中,有些请求比其他请求更加重要,可以使用权重的功能来控制负载。

示例代码:

from locust import HttpUser, task, between

class MyUser(HttpUser):
    WAIT_TIME = between(1, 2)
    
    @task(3)
    def search(self):
        self.client.get(f"/search")
        
    @task(1)
    def get_user_profile(self):
        self.client.get(f"/profile")

在上面的例子中,我们使用 @task 装饰器来设置请求的权重。在 search 函数中,我们将其权重设置为 3,在 get_user_profile 函数中将其权重设置为 1

集合

在测试场景中,有时候需要组合不止一个请求,可以使用 Locust 集合的功能来实现。

示例代码:

from locust import HttpUser, TaskSet, task, between

class UserBehavior(TaskSet):
    def on_start(self):
        response = self.client.post("/login", {"username":"testuser", "password":"testpass"})
        self.token = response.json()["token"]
    
    @task
    def get_profile(self):
        self.client.get("/user/profile", headers={"Authorization": f"Bearer {self.token}"})
    
    @task
    def get_orders(self):
        self.client.get("/user/orders", headers={"Authorization": f"Bearer {self.token}"})

class MyUser(HttpUser):
    WAIT_TIME = between(1, 2)
    tasks = {UserBehavior: 1}

在上面的例子中,我们使用 Locust 集合的方式,定义了一个 UserBehavior 类来表示一组请求。在该类的 on_start 函数中,先进行用户登录操作,获取 token,然后在后续的请求中,使用 token 做认证。

最后,在 MyUser 类中,使用 tasks 属性来关联 UserBehavior 类,并设置该集合的权重,这里设置为 1。当启动 Locust 后,每次会随机选择一个集合内的请求进行发送。

基础组合样例
这个样例是一个 Web 应用程序的压力测试,其中包含了集合、权重、思考时间、前置和后置等常用知识点。

假设有一个在线音乐平台,我们要对其进行压力测试。这个音乐平台有以下几个功能:

  1. 注册新用户
  2. 用户登录
  3. 搜索音乐
  4. 播放音乐
  5. 查看播放历史

压力测试中,我们需要模拟具有以下特征的用户:

  1. 注册和登录的用户占比为 20% 和 80%,使用权重进行控制
  2. 用户进行搜索和播放音乐的比例为 4:1,即每个用户进行 4 度搜索后才进行一次音乐播放
  3. 用户每进行一个操作后,需要思考 0.5-1.5 秒的时间
  4. 在每次操作前,需要判断用户是否已经登录,如果没有,则先进行登录操作
  5. 在每次操作后,需要查看播放历史

同时,我们需要模拟 1000 个用户,持续 1800 秒的测试时间。其中,注册和登录的用户,用户名和密码为随机生成一个 6 位数。

下面是 Locustfile 中的代码实现:

from locust import HttpUser, task, between, constant_pacing
import random

class MusicUser(HttpUser):
    min_wait = 500
    max_wait = 1500

    @task(1)
    def register_user(self):
        self.client.post("/register", json={"username": str(random.randint(100000, 999999)), "password": str(random.randint(100000, 999999))})

    @task(4)
    def search_music(self):
        if not self.logged_in():
            self.login()
        self.client.get("/search?keyword=Let It Go")
        self.think_time()

    @task(1)
    def play_music(self):
        if not self.logged_in():
            self.login()
        self.client.get("/play?id=123456")
        self.think_time()

    def browse_history(self):
        if not self.logged_in():
            self.login()
        self.client.get("/history")
        self.think_time()

    def logged_in(self):
        response = self.client.get("/profile")
        return response.status_code == 200

    def login(self):
        self.client.post("/login", json={"username": "testuser", "password": "testpassword"})
        self.browse_history()

    def think_time(self):
        self.sleep(random.uniform(0.5, 1.5))

    def on_start(self):
        if random.random() < 0.2:
            self.register_user()
        else:
            self.login()

    def on_stop(self):
        self.browse_history()

在这个样例中,我们定义了一个名为 MusicUser 的 Locust 用户,并设置了最小等待时间为 500 毫秒,最大等待时间为 1500 毫秒。其中 think_time 方法用于模拟用户操作之间的思考时间。logged_in 方法用于判断用户是否已经登录,login 方法用于模拟用户登录操作。 browse_history 方法用于查看播放历史。

on_start 方法中,我们用一个随机数来判断用户进行注册还是登录操作。register_user 方法用于模拟用户注册操作,search_music 方法用于模拟用户进行音乐搜索操作,play_music 方法用于模拟用户进行音乐播放操作。

在这个样例中,我们使用了 task 装饰器来定义不同任务的权重。@task(1) 表示这个任务的权重为 1,而 @task(4) 表示这个任务的权重为 4。这个权重的设置可以用来控制每个任务的负载情况。

同时,在 search_musicplay_music 两个任务中,我们使用了 if not self.logged_in(): 来判断用户是否已经登录。如果没有登录,则先进行登录操作,然后再进行搜索音乐或播放音乐。

此外,在 search在 search_musicplay_music中,我们还使用了self.think_time()来模拟用户操作之间的思考时间。这个思考时间是一个随机数,将在think_time` 方法中生成。

最后,我们使用了 on_starton_stop 方法来模拟用户的起始和终止行为。在 on_start 中,我们用一个随机数来判断用户进行注册还是登录操作;在 on_stop 中,我们调用 browse_history 方法来查看播放历史。

通过这个样例,我们可以看到如何使用 Locust 中的集合、权重、思考时间、前置和后置等常用知识点来进行高并发压力测试。
在 Locust 1.0 版本之后,TaskSet 已经不再是必须的了。您可以直接在 User 类中定义 task 方法,来告诉 Locust 模拟用户行为。本文提供的高并发样例中就是通过定义 @task 装饰器来模拟用户行为的。

当然,如果您想在 User 类中封装不同的测试任务,或者需要使用 setUptearDown 等方法来执行测试前或测试后的准备工作,那么可以继续使用 TaskSet 的方式。但是,如果您只需要简单模拟用户行为,上述的代码已经足够了。

复杂组合样例
以下是一个结合 User 和 TaskSet 的 Locust 高并发测试样例:

from locust import HttpUser, TaskSet, task, between

class LoginPage(TaskSet):
    @task
    def loadLoginPage(self):
        self.client.get("/login")

    @task
    def submitLoginForm(self):
        self.client.post("/submit_login", {
            "username": "testuser",
            "password": "testpass"
        })


class SearchPage(TaskSet):
    @task
    def loadSearchPage(self):
        self.client.get("/search")

    @task
    def performSearch(self):
        self.client.post("/search_query", {
            "query": "test"
        })


class UserBehaviour(HttpUser):
    tasks = [LoginPage, SearchPage]
    wait_time = between(0.5, 2.0)

    def on_start(self):
        self.client.post("/login", {
            "username": "testuser",
            "password": "testpass"
        })

在上述样例中,我们定义了两个 TaskSet:LoginPageSearchPageLoginPage 主要用于加载登录页面和提交登录表单,SearchPage 主要用于加载搜索页面和执行搜索操作。

UserBehaviour 类中,我们通过定义 tasks 属性来指定了要执行的测试任务,即 LoginPageSearchPage。我们还定义了一个 wait_time 属性,用于控制每个用户执行测试任务之间的等待时间。

UserBehaviour 类中还定义了一个 on_start 方法,用于在模拟用户开始测试之前执行一些准备工作,包括登录操作。

使用 TaskSet 的优势在于我们可以将测试任务的逻辑进行更好地组织和拆分,提高代码的可读性和可维护性。对于复杂的测试场景,使用 TaskSet 和 User 的组合可以更好地支持测试任务之间的依赖关系和流程。

8. Locust运行模式

以下是一个结合运行模式的 Locust 测试样例,其中包含了 Standalone、Master/Worker、External 三种运行模式。假设我们要测试一个简单的 Web 应用程序,包含以下几个页面:登录、搜索和购买,假设应用程序运行在地址 http://localhost:8080 上。

from locust import HttpUser, TaskSet, task, between

class LoginPage(TaskSet):
    @task
    def loadLoginPage(self):
        self.client.get("/login")

    @task
    def submitLoginForm(self):
        self.client.post("/submit_login", {
            "username": "testuser",
            "password": "testpass"
        })


class SearchPage(TaskSet):
    @task
    def loadSearchPage(self):
        self.client.get("/search")

    @task
    def performSearch(self):
        self.client.post("/search_query", {
            "query": "test"
        })


class PurchasePage(TaskSet):
    @task
    def loadPurchasePage(self):
        self.client.get("/purchase")

    @task
    def performPurchase(self):
        self.client.post("/submit_purchase", {
            "product_id": "123",
            "quantity": "1"
        })


class UserBehaviour(HttpUser):
    tasks = [LoginPage, SearchPage, PurchasePage]
    wait_time = between(0.5, 2.0)

    def on_start(self):
        self.client.post("/login", {
            "username": "testuser",
            "password": "testpass"
        })

在上述样例中,我们定义了三个 TaskSet,分别用于模拟登录、搜索和购买三个场景。在 UserBehaviour 类中,我们通过定义 tasks 属性来指定要执行的测试任务,即 LoginPageSearchPagePurchasePage。我们还定义了一个 wait_time 属性,用于控制每个用户执行测试任务之间的等待时间。

UserBehaviour 类中还定义了一个 on_start 方法,用于在模拟用户开始测试之前执行一些准备工作,包括登录操作。

接下来,我们来说明一下如何使用不同的运行模式来执行以上的测试样例:

8.1 Standalone(独立运行模式)

在 Standalone 模式下,Locust 在本地生成虚拟用户进行测试。可以使用以下命令来启动 Standalone 模式:

locust -f locustfile.py --host=http://localhost:8080

其中 locustfile.py 是您编写的测试脚本文件名,--host 参数用于指定目标应用程序的地址。

启动后,Locust 会自动启动一个 Web 界面,您可以在其中指定要模拟的用户数和每个用户运行测试任务的频率等参数。Locust 会根据您的指定自动对目标应用程序发起请求,来模拟并不断增加压力。

8.2 Master/Worker(主从运行模式)

在 Master/Worker 模式下,可以使用以下命令来启动 Master 节点:

locust -f locustfile.py --master --expect-workers=2 --host=http://localhost:8080

其中 --expect-workers=2 参数用于指定该 Master 节点期望有 2 个 Worker 节点加入测试。在从节点上,可以使用以下命令来启动 Worker 节点:

locust -f locustfile.py --worker --master-host=<master-host-ip>

其中 --master-host 参数用于指定 Master 节点的 IP 地址。

启动后,Master 节点将自动监控所有 Worker 节点的测试结果,并将汇总结果显示在 Locust 的 Web 界面上。

8.3 External(外部运行模式)

External 模式是一种特殊的运行模式,用于通过其他工具或服务来控制 Locust 的运行。例如,可以将 Locust 集成到 Jenkins 或 Gitlab CI 等工具中,以自动化运行测试。可以使用下面的命令将 Locust 启动到 External 模式:

locust -f locustfile.py --csv=report_file --headless --host=http://localhost:8080 --users=10 --spawn-rate=5

其中:

  • locustfile.py 是您编写的测试脚本文件名;
  • --csv 参数用于指定执行测试过程中需要收集的数据的文件名;
  • --headless 参数用于禁用 Web 界面。在 External 模式下,Locust 会把测试结果以 CSV 格式写入指定文件中,而不会启动 Web 界面;
  • --host 参数用于指定目标应用程序的地址;
  • --users 参数用于指定要模拟的用户数;
  • --spawn-rate 参数用于指定每秒钟要产生的用户数。

除了以上的命令行参数之外,还可以使用一些其他的命令行参数来指定测试场景和其他的参数。例如,可以使用 --tags 参数指定要执行的特定测试场景,可以使用 --run-time 参数指定执行测试的最长时间等。具体的用法可以参考官方文档或者使用locust --help命令查看。

9. Locust运行结果解析

Locust 的运行结果包含了一些关键的指标和图表,用于分析测试场景的性能和稳定性。以下是一些常用的指标和图表以及它们的含义和解释。

9.1 Statistics(统计信息)

Locust 提供了一个叫做 Statistics 的面板,用于展示当前测试状态的重要指标,包括请求数、响应时间、响应失败率、用户数等。该面板将实时更新,并提供了表格、折线图和条形图等多种数据可视化方式。统计信息面板的实际效果如下所示:

Locust 统计信息面板

  • Method 列:指定了当前统计的请求方法,例如 GET、POST、PUT 等。
  • Name 列:指定了 API 的名称,这个值定义在你写的测试脚本中。
  • # requests 列:指定了当前统计时间段内的请求次数(每秒钟)。
  • # fails 列:表示当前统计时间段内的请求失败次数(每秒钟)。
  • Median 列、90% 列和 99% 列:用于显示请求响应时间百分位数。例如,Median 显示了响应时间中位数,即 50% 的请求的响应时间小于这个值,其余 50% 的请求的响应时间大于这个值。90% 显示了响应时间处于前 90% 的请求的响应时间的上界,99% 列也是类似的含义。
  • Avg 列:表示当前统计时间段内的请求响应时间的平均值。
  • Min 列和 Max 列:用于显示当前统计时间段内请求响应时间的最小值和最大值。
  • Req/Sec 列和 Fail/Sec 列:用于显示当前统计时间段内请求的速率和失败率。

9.2 Failures(失败信息)

如果在测试过程中发生了错误或失败,Locust 可以将详细的失败信息记录到文件中,供后续分析。这些信息包括请求的 URL、响应码、响应头、响应主体等。借助这些信息,你可以分析并诊断 API 故障并找到解决方案。

9.3 Graphs(图表)

Locust 还提供了一些可视化的图表,用于帮助开发人员和测试人员更清晰地了解测试结果和进展状态。这些图表包括 Request Distribution(请求分布)、Response Times(响应时间)和 Response Codes(响应代码)等。其中,Request Distribution 图表用于显示请求数量的分布情况,Response Times 图表用于显示请求响应时间分布的情况,Response Codes 图表用于显示请求响应代码的分布情况。图表的实际效果如下所示:

Locust 图表面板

9.4 Ratio Metrics(比例指标)

在 Locust 中,Ratio Metrics(比例指标)用于描述相对于测试总体而言的特定指标的百分比。例如,failure ratio(错误率)指测试中请求失败的百分比。在 Locust Web 界面的统计信息面板中,Fail/SecReq/Sec 就是 Ratio Metrics。

综上所述,通过对以上指标和图表进行综合分析,您可以得到一份详细的测试报告,用于评估测试场景的性能和稳定性。同时,您还可以通过调整测试参数,比如虚拟用户数、请求频率等,来扩展测试范围,进一步提高测试质量。例如,可以增加虚拟用户数以达到更高的并发度,或者调整请求的间隔时间以及请求的大小等,来模拟更加真实的使用场景。

此外,在实际使用 Locust 进行测试时,还可以结合其他工具或者服务,来进一步分析测试结果。例如,可以使用 Grafana 这样的工具,将 Locust 的测试结果可视化,并与其他数据源进行比较、分析。同时,Locust 还支持将测试结果以 CSV 或 JSON 格式导出,以进一步分析和处理。

总的来说,通过仔细分析 Locust 的测试结果,并结合其他工具和服务,可以帮助您深入了解目标系统在各种负载下的性能和稳定性表现,从而为进一步优化系统设计和实现提供有益的反馈和参考。

查看帮助文档,执行: locust --help

参数说明:

  • -h, --help:显示帮助消息并退出。

  • -f LOCUSTFILE, --locustfile LOCUSTFILE:指定要导入的Python模块。可以是Python文件、多个以逗号分隔的Python文件或包目录。默认为'locustfile'。

  • --config CONFIG:指定配置文件路径。

  • -H HOST, --host HOST:指定要进行负载测试的主机,格式为:http://10.21.32.33

  • -u NUM_USERS, --users NUM_USERS:指定并发用户峰值数量。主要与--headless或--autostart一起使用。在测试过程中可以通过键盘输入w、W (生成1或10个用户)和s、S (停止1或10个用户)来进行更改。

  • -r SPAWN_RATE, --spawn-rate SPAWN_RATE:指定每秒生成用户的速率(用户数/秒)。主要与--headless或--autostart一起使用。

  • -t RUN_TIME, --run-time RUN_TIME:指定停止测试的时间,例如(300s,20m,3h,1h30m等)。仅与--headless或--autostart一起使用。默认为永久运行。

  • -l, --list:显示可用的用户类并退出。

  • --web-host WEB_HOST:指定要绑定Web界面的主机,默认为所有接口("*")。

  • --web-port WEB_PORT, -P WEB_PORT:指定Web服务端口号。

  • --headless:禁用Web界面,并立即开始测试。使用-u和-t来控制用户数量和运行时间。

  • --autostart:立即开始测试(类似于--headless,但不会禁用Web UI)。

  • --autoquit AUTOQUIT:在测试结束后X秒钟内完全退出Locust。仅与--autostart一起使用,默认情况下,Locust会一直运行,直到使用CTRL+C结束。

  • --web-auth WEB_AUTH:为Web界面打开基本身份验证。应该使用以下格式提供:username:password。

  • --tls-cert TLS_CERT:指定用于通过HTTPS服务的TLS证书的路径。

  • --tls-key TLS_KEY:指定用于通过HTTPS服务的TLS私钥的路径。

  • --class-picker:在Web界面中启用选择框,以选择所有可用的用户类和形状类。

  • --master:设置Locust以分布式模式运行,该进程作为主节点。用于运行从节点。

  • --master-bind-host MASTER_BIND_HOST:指定Locust主节点绑定到的接口(主机名、IP地址)。只有在使用--master运行时才会被使用。默认为*(所有可用接口)。

  • --master-bind-port MASTER_BIND_PORT:指定Locust主节点绑定的端口号。只有在使用--master运行时才会被使用。默认为5557。

  • --expect-workers EXPECT_WORKERS:设置Locust主节点在开始测试前需要连接的从节点数量(仅在使用--headless/autostart时使用)。

  • --expect-workers-max-wait EXPECT_WORKERS_MAX_WAIT:设置Locust主节点等待从节点连接的最长时间。默认为无限等待。

  • -T [TAG [TAG ...]], --tags [TAG [TAG ...]]:列出要在测试中包含的标签,因此只有具有任何匹配标签的任务才会被执行。

  • -E [TAG [TAG ...]], --exclude-tags [TAG [TAG ...]]:列出要从测试中排除的标签,因此只有没有匹配标签的任务才会被执行。

  • --csv CSV_PREFIX:将当前请求统计信息以CSV格式保存到文件中。设置此选项将生成三个文件:[CSV_PREFIX]_stats.csv,[CSV_PREFIX]_stats_history.csv和[CSV_PREFIX]_failures.csv。

  • --csv-full-history:将每个统计项以CSV格式存储到_stats_history.csv文件中。您还必须指定“--csv”参数以启用此选项。

  • --print-stats:在UI运行中启用请求统计信息的定期打印。

  • --only-summary:在--headless运行期间禁用请求统计信息的定期打印,仅打印摘要信息。

  • --reset-stats:当生成的测试在所有的Locust Worker节点上均已启动后重置统计信息。在分布式模式下运行时,主节点和worker节点均应启用此选项。

  • --html HTML_FILE:将HTML报告存储到指定的文件路径中。

  • --json:将最终的统计信息以JSON格式打印到stdout。对于在其他程序/脚本中解析测试结果非常有用。与--headless和--skip-log一起使用,仅输出json数据。

  • --skip-log-setup:禁用Locust的日志设置。日志设置由Locust测试或Python默认值提供。

  • --loglevel LOGLEVEL, -L LOGLEVEL:选择DEBUG/INFO/WARNING/ERROR/CRITICAL级别。默认为INFO。

  • --logfile LOGFILE:设置日志文件路径。如果未设置,日志将会写入stderr。

  • --show-task-ratio:打印用户类的任务执行比率表格,用于非零用户选项时,如果某些类定义了非零fixed_count属性。

  • --show-task-ratio-json:打印用户类的任务执行比率的json数据,用于非零用户选项时,如果某些类定义了非零fixed_count属性。

  • --version, -V:显示程序的版本号并退出

  • --exit-code-on-error EXIT_CODE_ON_ERROR:设置当测试结果包含任何失败或错误时要使用的进程退出代码。

  • -s STOP_TIMEOUT, --stop-timeout STOP_TIMEOUT:在退出之前等待模拟用户完成所有正在执行的任务的秒数。默认为立即终止。仅在运行Locust分布式时,主进程需要指定此参数。

  • --equal-weights:使用平均分布任务权重,覆盖locustfile中指定的权重。

  • --enable-rebalancing:允许在测试运行期间自动重新平衡用户,如果添加或删除了新的worker节点。

  • UserClass:可选地指定应使用哪些用户类(可使用-l或--list列出可用的用户类)。

posted @ 2023-06-12 11:40  术科术  阅读(378)  评论(0编辑  收藏  举报