Locust 性能测试相关

01、认识Locust

Locust是一个比较容易上手的分布式用户负载测试工具。它旨在对网站(或其他系统)进行负载测试,并确定系统可以处理多少个并发用户,Locust 在英文中是 蝗虫 的意思:作者的想法是在测试期间,放一大群 蝗虫 攻击您的网站。当然事先是可以用 Locust 定义每个蝗虫(或测试用户)的行为,并且通过 Web UI 实时监视围攻过程。

  • locust运行原理
    Locust 的运行原理是完全基于事件运行的,因此可以在一台计算机上支持数千个并发用户。与许多其他基于事件的应用程序相比,它不使用回调(比如 Nodejs 就是属于回调,Locust 不使用这种的逻辑)。相反,它通过 gevent 使用轻量级进程。测试您站点的每个蝗虫实际上都在其自己的进程中运行

  • Locust的特点
    1、用Python编写测试方案 不需要在UI界面上点击,只需要正常编写代码即可,灵活性比较强
    2、分布式&可扩展 Locust 支持分布在多台计算机上的运行负载测试(可以多台机器并行开搞)。
    3、统计结果基于Web界面 Locust 有一个简单的用户界面,可实时显示相关的测试详细信息,并且统计结果界面是基于网页的,而网页是天生跨平台的,所以 Locust 是跨平台且易于扩展的
    4、可以测试任何网页/应用/系统 只需用 python 编写想要测试的方案,然后放”蝗虫”去怼需要测试的项目就可以了,非常简单!

02、测试工具哪个好

  • LoadRunner
    是非常有名的商业性能测试工具,功能非常强大。使用也比较复杂,但收费贼贵

  • Jmeter
    同样是非常有名的开源性能测试工具,功能也很完善。可以当做接口测试工具来测试接口,但同时它也是一个标准的性能测试工具

  • Locust
    功能上虽然不如LoadRunner及Jmeter丰富,但其也有不少优点。Locust 完全基本 Python 编程语言并且 HTTP 请求完全基于 Requests 库。

LoadRunner 和 Jmeter 这类采用进程和线程的测试工具,都很难在单机上模拟出较高的并发压力。Locust 的并发机制摒弃了进程和线程,采用协程(gevent)的机制。协程避免了系统级资源调度,由此可以大幅提高单机的并发能力。

03、环境安装

Python环境配置
(1)首先去Python官网下载Python3.9+版本解释器
(2)安装解释器并配置环境变量(将python的根目录以及Scripts路径配置到环境变量Path下面)
(3)打开cmd窗口,分别输入python、pip命令并回车,如果没有报错,则说明Python环境配置成功

Locust环境配置
(1)打开cmd窗口,输入pip install locust ,此时系统会自动下载locust库以及部分依赖库
(2)安装成功后验证:在cmd窗口中,输入python,进入python开发环境,然后输入import locust,如果没有报错,则说明locust安装成功

04、如何使用

参考Locust官网文档 , 以下python代码供参考

from locust import HttpUser, between, task, TaskSet, run_single_user, tag, constant, events
from locust.exception import RescheduleTask
from json import JSONDecodeError


class MyTask(TaskSet):  # 定义任务集

    @events.test_start.add_listener  # 执行任务前运行事件
    def on_test_start(environment, **kwargs):
        print("开始新的测试")

    def on_start(self):   # 1个user仅执行1次,常用于登录请求
        url = "/ecshop/user.php"
        data = {"username": "admin", "password": "123456", "act": "act_login", "back_act": ".%2Findex.php"}
        response = self.client.post(url, data=data, name="登录1")
        # print("Response status code:", response.status_code)
        # print("Response text:", response.text)
        assert "登录成功" in response.text, "报告中不包含预期内容"
        pass

    # @tag('tag1')  # 如果你在命令行中执行 locust --host=http://example.com --tags tag1,那么只有带有 tag1 标签的任务会被执行
    @task         # 被选中任务才会被执行,@task(3)设置权重越高,被执行的概率越大
    def profile(self):
        url = "/ecshop/user.php"
        response = self.client.get(url, name="配置2")
        assert "您的账户" in response.text, "报告中不包含预期内容"

       self.client.get("/ecshop/category.php?id=16", name="配置3")  # 按接口顺序执行,写在同一个方法里,先执行配置2再执行配置3
        pass

    # @tag('tag2')
    @task
    def flow(self):
        url = "/ecshop/flow.php"
        response = self.client.get(url, name="购物车3")
        assert "商品列表" in response.text, "报告中不包含预期内容"
        pass

    # @tag('tag2')
    @task
    def category(self):
        # url = "/ecshop/category.php?id=16"
        # response = self.client.get(url, name="服装4")
        # assert "极简都市双肩包" in response.text, "报告中不包含预期内容"
        with self.client.get("/ecshop/category.php?id=16", catch_response=True) as response:

            # 断言方法
            print("Response status code:", response.status_code)
            if response.status_code != 200:
                response.failure(f"返回错误码:{response.status_code}")  # response.failure() 上报错误至locust
            elif response.elapsed.total_seconds() > 0.5:
                response.failure("请求时间太长")

            if response.status_code == 404:
                raise RescheduleTask()   # 忽略异常

            try:
                if response.json()["greeting"] != "hello":
                    response.failure("取值不正确")
            except JSONDecodeError:
                response.failure("解码JSON失败")
            except KeyError:
                response.failure("响应密钥错误")
        pass

    # def on_stop(self):
    #     # 在这里执行清理代码,例如发送测试结束通知
    #     print("User has finished all tasks.")


# HttpUser类 继承了Locust类,表示将要生成的每一个虚拟的HTTP用户,用来发送请求到进行负载测试的系统
class MyUser(HttpUser):           # HttpUser发出HTTP请求的client属性,就像requests.Session一样,它在请求之间保留cookie,因此可以轻松地用于登录网站
    host = "http://127.0.0.1:80"  # 被测系统URL
    # wait_time = constant(1)     # 每次请求停顿时间 (思考时间)
    wait_time = between(2, 3)
    tasks = [MyTask]              # tasks属性是一个Tasks列表,或者是一个Task:int dict


if __name__ == "__main__":
    run_single_user(MyUser)  # 调试

Locust类

  • HttpLocust类 继承了Locust类,表示将要生成的每一个虚拟的HTTP用户,用来发送请求到进行负载测试的系统。
  • task_set属性 该 task_set 属性指向定义的用户行为的类
  • host属性 host属性是要加载的域名(URL 前缀,例如http://xxxxxx
  • wait_time属性 用于发送Http请求时,虚拟用户需要等待的时间,等待时间是一个区间范围。单位为毫秒,等待时间在min_wait和max_wait之间随机选择

TaskSequence 类
TaskSequence 类是 TaskSet,但其任务将按顺序执行。

@task装饰器
用于标识测试任务,并且可以通过task装饰器设置权重用于执行任务的执行率

@seq_task装饰器
用于指定接口的执行顺序。可以把@task装饰器和@seq_task装饰器一起组合使用

初始化方法
1、setup 和 teardown方法 setup 和 teardown 都是只能运行一次的方法。在任务开始运行之前运行setup,而在所有任务完成并且蝗虫退出后运行 teardown;这使您能够在任务开始运行之前做一些准备工作(比如创建数据库,或者打印日志 等等),并在蝗虫退出之前进行清理。
2、on_start 和 on_stop 方法 每个虚拟用户执行操作时运行on_start方法,退出时执行on_stop方法
3、初始化方法的执行顺序 setup > on_start > on_stop > teardown

常用3种启动方式

直接启动

locust -f stock_center.py
(stock_center.py为执行脚本,可在编译器中直接运行该脚本)

无web页面启动

locust -f stock_center.py --no-web -c 200 -r 20 -t 1m
(–no-web 代表不需要启动UI页面
-c 代表需要并发的用户数
-r 代表每秒并发的用户数
 -t 代表需要运行的时间)

分布式启动

locust -f stock_center.py --master # 指定当前机器为master主机
locust -f stock_center.py --slave --master-host=10.xxx.xxx.xxx # 指定当前机器为从机并指向对应master主机

启动页面

image.png

image.png

Number of total users simulate: 设置需要并发的总人数
Hatch rate(users spawned/second): 每秒启动的虚拟用户数
Start swarming: 执行locust脚本

image.png

Type: 请求类型,即接口的请求方法
Name: 接口请求路径
Requests: 当前已完成的请求数量
Fails: 当前失败的数量
Median: 响应时间的中间值,即50%的响应时间在这个数值范围内,单位为毫秒
Average: 平均响应时间,单位为毫秒
Min: 最小响应时间,单位为毫秒
Max: 最大响应时间,单位为毫秒
Average Size: 平均请求的数据量, 单位为字节
Current RPS: 每秒能处理的请求数目

image.png

New test:点击该按钮可对模拟的总虚拟用户数和每秒启动的虚拟用户数进行编辑;
Statistics:类似于jmeter中Listen的聚合报告;
Charts:测试结果变化趋势的曲线展示图,分别为每秒完成的请求数(RPS)、响应时间、 不同时间的虚拟用户数;
Failures:失败请求的展示界面;
Exceptions:异常请求的展示界面;
Download Data:测试数据下载模块, 提供四种类型的CSV格式的下载, 分别是:Statistics、responsetime、failures、exceptions;

05、Locust的总结

  • 局限:
    locust的局限性在于:目前其本身对测试过程的监控和测试结果展示,不如jmeter全面和详细,需要进行二次开发才能满足需求越来越复杂的性能测试需要。

  • 优势:
    纯脚本形式,并且HTTP请求完全基于Requests库。用过Requests的都知道,这个库非常简洁易用,但功能十分强。另外一点就是并发机制了。Locust的并发机制摒弃了进程和线程,采用协程(gevent)的机制。避免了系统级资源调度,由此大幅提高了性能。正常情况下,单台普通配置的测试机可以生产数千并发压力,这是LoadRunner和Jmeter都无法实现的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容