首页
学习
活动
专区
圈层
工具
发布
清单首页Locust文章详情

Locust

1. Locust的特点

(1)基于python开发脚本;

(2)开源免费,可以二次开发;

(3)分布执行。配置master和slave(主从机器),在多要机器上对系统持续发起请求;

(4)基于事件驱动。与其他工具使用进程和线程来模拟用户不同,Locust借助gevent库对协程的支持,可以达到更高数量级的并发;

(5)不支持监控被测机器,需要配合其他工具的辅助;

(6)在Locust类中,具有一个client属性,对应着虚拟用户作为客户端所具备的请求能力,也就是我们常说的请求方法;所以在使用Locust时,需要先继承Locust类,然后在继承子类中的client属性中绑定客户端的实现类;

(7)HttpUser使用到了requests.Session,因此后续所有任务执行过程中就都具有登录态;

(8)版本变动:1.0版本之后的更新重点是将HttpLocust替换为Httpuser,task_set任务集需要数据类型为列表类型,且task_set需要修改为tasks。

2. Locust的指标体系及常用使用流程

(1)响应时间:反应系统处理效率指标,从开始到完成某项工作所需要时间的度量,响应时间通常随着负载的增加而增加;

(2)吞吐量:反应系统处理能力的指标,指单位时间内完成工作的度量,可以从客户端或服务端视角两方面来进行综合评估;

(3)事务处理能力(TPS在locust中为RPS):对一笔业务进行处理时的相应情况,通常包含三个指标,一是处理该业务的响应时间,二是处理该业务的成功率,三是单位时间内(每秒钟,每分钟,每小时等)可以处理的业务数量。

cmd命令执行脚本

web界面操作(web界面不会自动停止,需要手动stop);

进入到项目目录,py文件这一层级;

locust -f test.py 或者

locust -f test.py

--host=http://example.com

打开浏览器进入web界面 添入 模拟的用户总数和每秒启动的虚拟用户数;

http://localhost:8089

测试结果界面:

纯命令运行

locust -f test.py

--no-web -c 100 -r 20 -t 5 或者 locust -f

test.py

--host=http://example.com

--no-web -c 100 -r 20 -t 5;

-c: 用户数量;

-r: 每秒生成数量;

-t: 限制运行时间;

-n: 请求总次数;

3. Locust的语法格式

(1)定义一个任务类,这个类名称自己随便定义;

(2)继承SequentialTaskSet 或 TaskSet类,所以要从locust中,引入SequentialTaskSet或TaskSet;

(3)当类里面的任务请求有先后顺序时继承SequentialTaskSet类;

(4)没有先后顺序,可以使用继承TaskSet类;

代码语言:txt
复制
    import random
代码语言:txt
复制
    from locust import HttpUser, task, between, SequentialTaskSet, tag
代码语言:txt
复制
    class MyTaskCase(SequentialTaskSet):
代码语言:txt
复制
            # 初始化方法,相当于 setup
代码语言:txt
复制
            def on_start(self):
代码语言:txt
复制
                pass
代码语言:txt
复制
        # @task python中的装饰器,告诉下面的方法是一个任务,
代码语言:txt
复制
        # 这个装饰器和下面的方法被复制多次,改动一下,就能写出多个接口
代码语言:txt
复制
        # 装饰器后面带上(数字)代表在所有任务中,执行比例
代码语言:txt
复制
        # 要用这个装饰器,需要头部引入 从locust中,引入 task
代码语言:txt
复制
        @task
代码语言:txt
复制
        @tag("leave_1")
代码语言:txt
复制
        def regist_(self):  # 一个方法, 方法名称可以自己改
代码语言:txt
复制
            url = '/erp/regist'  # 接口请求的URL地址
代码语言:txt
复制
            # 定义请求头为类变量,这样其他任务也可以调用该变量
代码语言:txt
复制
            self.headers = {"Content-Type": "application/json"}
代码语言:txt
复制
            self.username = "locust_" + str(random.randint(10000, 100000))
代码语言:txt
复制
            self.pwd = '1234567890'
代码语言:txt
复制
            # post请求的 请求体
代码语言:txt
复制
            data = {"name": self.username, "pwd": self.pwd}
代码语言:txt
复制
            # 使用self.client发起请求,请求的方法根据接口实际选,
代码语言:txt
复制
            # catch_response 值为True 允许为失败 , 
代码语言:txt
复制
            # name 设置任务标签名称   -----可选参数
代码语言:txt
复制
            with self.client.post(url,
代码语言:txt
复制
                                  json=data,
代码语言:txt
复制
                                  headers=self.headers,
代码语言:txt
复制
                                  catch_response=True) as rsp:
代码语言:txt
复制
                if rsp.status_code > 400:
代码语言:txt
复制
                    print(rsp.text)
代码语言:txt
复制
                    rsp.failure('regist_ 接口失败!')
代码语言:txt
复制
        @task  # 装饰器,说明下面是一个任务
代码语言:txt
复制
        def login_(self):
代码语言:txt
复制
            url = '/erp/loginIn'  # 接口请求的URL地址
代码语言:txt
复制
            data = {"name": self.username, "pwd": self.pwd}
代码语言:txt
复制
            with self.client.post(url,
代码语言:txt
复制
                                  json=data,
代码语言:txt
复制
                                  headers=self.headers,
代码语言:txt
复制
                                  catch_response=True) as rsp:
代码语言:txt
复制
                # 提取响应json 中的信息,定义为 类变量
代码语言:txt
复制
                self.token = rsp.json()['token']
代码语言:txt
复制
                if rsp.status_code < 400 \
代码语言:txt
复制
                        and rsp.json()['code'] == "200":
代码语言:txt
复制
                    rsp.success()
代码语言:txt
复制
                else:
代码语言:txt
复制
                    rsp.failure('login_ 接口失败!')
代码语言:txt
复制
        @task  # 装饰器,说明下面是一个任务
代码语言:txt
复制
        def getuser_(self):
代码语言:txt
复制
            url = '/erp/user'  # 接口请求的URL地址
代码语言:txt
复制
            # 引用上一个任务的 类变量值   实现参数关联
代码语言:txt
复制
            headers = {"Token": self.token}  
代码语言:txt
复制
           # 使用self.client发起请求,请求的方法 选择 get
代码语言:txt
复制
            with self.client.get(url, 
代码语言:txt
复制
                                 headers=headers, 
代码语言:txt
复制
                                 catch_response=True) as rsp: 
代码语言:txt
复制
                if rsp.status_code < 400:
代码语言:txt
复制
                    rsp.success()
代码语言:txt
复制
                else:
代码语言:txt
复制
                    rsp.failure('getuser_ 接口失败!')
代码语言:txt
复制
        # 结束方法, 相当于teardown
代码语言:txt
复制
        def on_stop(self):
代码语言:txt
复制
            pass
代码语言:txt
复制
    # 定义一个运行类 继承HttpUser类, 所以要从locust中引入 HttpUser类
代码语言:txt
复制
    class UserRun(HttpUser):
代码语言:txt
复制
        tasks = [MyTaskCase]
代码语言:txt
复制
        # 设置运行过程中间隔时间 需要从locust中 引入 between
代码语言:txt
复制
        wait_time = between(0.1, 3)  

4. 单接口压测示例

代码语言:txt
复制
     #!/usr/bin/env python
代码语言:txt
复制
    # -*- coding: utf-8 -*-
代码语言:txt
复制
    from locust import task,TaskSet,HttpUser
代码语言:txt
复制
    class UserTasks(TaskSet):
代码语言:txt
复制
        # 声明下面是一个任务
代码语言:txt
复制
        @task
代码语言:txt
复制
        def getIndex(self):
代码语言:txt
复制
            # self.client是TaskSet的成员,相当于一个request对象
代码语言:txt
复制
            self.client.get("/path")
代码语言:txt
复制
            print("here")
代码语言:txt
复制
    class WebUser(HttpUser):
代码语言:txt
复制
        # 声明执行的任务集是哪个类
代码语言:txt
复制
        tasks = [UserTasks]
代码语言:txt
复制
        # 最小等待时间和最大等待时间   请求间的间隔时间
代码语言:txt
复制
        min_wait = 1000
代码语言:txt
复制
        max_wait = 2000

运行:

在终端中输入:locust -f 被执行的locust文件.py --host=http://被测服务器域名或ip端口地址,也可以不指定host,如

"locust -f

locust_test.py

--host=http://localhost:8082";

当命令执行成功,会提示服务端口,如:*:8089。此时,则可通过浏览器访问机器ip:8089,看到任务测试页面。

Number of total users to simulate 模拟的用户数

Spawn rate (users spawned/second) 每秒产生的用户数

5. 业务用例压测示例

下面以一个登录接口和获取id的接口为例

代码语言:txt
复制
   # #!/usr/bin/env python
代码语言:txt
复制
   # # -*- coding: utf-8 -*-
代码语言:txt
复制
   from locust import task,TaskSet,HttpUser,tag
代码语言:txt
复制
   from random import randint
代码语言:txt
复制
   import json
代码语言:txt
复制
   class UserTasks(TaskSet):
代码语言:txt
复制
       def on_start(self):
代码语言:txt
复制
       # 准备测试,请求接受的大多是字典格式
代码语言:txt
复制
           self.loginData = [{"username":"1","paswordword":"1"},
代码语言:txt
复制
                             {"username":"2","paswordword":"2"},
代码语言:txt
复制
                             {"username":"3","paswordword":"3"}]
代码语言:txt
复制
       print("-----------on_start----------------")
代码语言:txt
复制
       # 声明下面是一个登录任务
代码语言:txt
复制
       @task(1)
代码语言:txt
复制
       def doLogin(self):
代码语言:txt
复制
           ranIndex = randint(1,len(self.loginData))
代码语言:txt
复制
           # 发送请求并响应
代码语言:txt
复制
           response = self.client.post("/path",data = self.loginData[ranIndex],catch_response=True)
代码语言:txt
复制
           if "login-pass" in response.text:
代码语言:txt
复制
               response.success()
代码语言:txt
复制
           else:
代码语言:txt
复制
               response.failure("Can not login!")
代码语言:txt
复制
       # 声明下面是一个获取商品任务
代码语言:txt
复制
       @task
代码语言:txt
复制
       def get_goods(self):
代码语言:txt
复制
           body = {"good_name" :"apple"}
代码语言:txt
复制
           # 发送请求并响应
代码语言:txt
复制
           response = self.client.post("/path2",data = body,catch_response=True)
代码语言:txt
复制
           newText = json.loads(response.txt)
代码语言:txt
复制
           if "game_id" in newText[0].keys():
代码语言:txt
复制
               response.success()
代码语言:txt
复制
           else:
代码语言:txt
复制
               response.failure("Can not get!")
代码语言:txt
复制
       #为任务分配权重
代码语言:txt
复制
       tasks = {doLogin:1, get_goods:2}
代码语言:txt
复制
   #增加 tag 标签,在执行时,可以用 -T \ --tags 指定标签执行、-E \ --exclude-tags 排除指定标签执行
代码语言:txt
复制
   class WebUser(User):
代码语言:txt
复制
       @task
代码语言:txt
复制
       @tag("tag1", "tag2")
代码语言:txt
复制
       def my_task(self):
代码语言:txt
复制
           pass
代码语言:txt
复制
   class WebUser(HttpUser):
代码语言:txt
复制
       # 声明执行的任务集是哪个类,任务集中的任务按已分配的1:2权重执行
代码语言:txt
复制
       tasks = [UserTasks]
代码语言:txt
复制
       # 最小等待时间和最大等待时间   请求间的间隔时间
代码语言:txt
复制
       min_wait = 1000
代码语言:txt
复制
       max_wait = 2000
代码语言:txt
复制
   # locust -f locust_test.py --host=http://localhost:8082
代码语言:txt
复制
   # Number of total users to simulate   模拟的用户数
代码语言:txt
复制
   # Spawn rate (users spawned/second)   每秒产生的用户数

注:如果任务接口的请求值需要其他接口返回值中的参数,这些非任务请求也会在locust的统计面板中显示出来。若想只关注任务接口的统计数据,则依赖的请求需用原生requests库。

6. 数据监测工具推荐

(1)如果公司有搭建监测系统,可请运维协助在平台查看即可,比如Grafana;

(2)linux检测工具Nmon;

(3)windows自带perfmon;

(4)使用python的psuil库自定义检测频率与指标参数,需要对数据单独进行处理;

举报
领券