1.安装

1
2
3
4
pip3.8 install locust
pip3.8 install pyzmq
locust -V  # 验证是否安装成功
https://docs.locust.io/en/stable/what-is-locust.html   # 测试文档

2 入门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from locust import User, task, HttpUser, between, TaskSet, SequentialTaskSet
from locust.contrib.fasthttp import FastHttpUser
import os
 
 
class FlashSeqTask(SequentialTaskSet):  # 顺序执行
    @task(1)
    def hello_world(self):
        self.client.get("/hello")
 
 
class FlastTask(TaskSet):  # 并行执行
    @task(1)
    def index(self):
        self.client.get("/")
 
 
class Login(FastHttpUser):
    wait_time = between(1, 5)
    def wait_time(self):   # 自己定义等待时间
        self.last_wait_time += 1
        return self.last_wait_time
    host = "https://www.baidu.com"
    tasks = [FlastTask]
 
 
if __name__ == "__main__":
    os.system("locust -f  locust_dome1.py --web-host=192.168.104.161")
 
     
http://localhost:8089  # 可以看打这个网页

help 解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-h, --help    查看帮助
-H HOST, --host=HOST    指定被测试的主机,采用以格式:http://10.21.32.33
--web-host=WEB_HOST    指定运行 Locust Web 页面的主机,默认为空 ''
-P PORT, --port=PORT, --web-port=PORT    指定 --web-host 的端口,默认是8089
-f LOCUSTFILE, --locustfile=LOCUSTFILE    指定运行 Locust 性能测试文件,默认为: locustfile.py
--csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE    以CSV格式存储当前请求测试数据。
--master    Locust 分布式模式使用,当前节点为 master 节点。
--slave    Locust 分布式模式使用,当前节点为 slave 节点。
--master-host=MASTER_HOST    分布式模式运行,设置 master 节点的主机或 IP 地址,只在与 --slave 节点一起运行时使用,默认为:127.0.0.1.
--master-port=MASTER_PORT    分布式模式运行, 设置 master 节点的端口号,只在与 --slave 节点一起运行时使用,默认为:5557。注意,slave 节点也将连接到这个端口+1 上的 master 节点。
--master-bind-host=MASTER_BIND_HOST    Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces).
--master-bind-port=MASTER_BIND_PORT    Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558.
--expect-slaves=EXPECT_SLAVES    How many slaves master should expect to connect before starting the test (only when --no-web used).
--no-web    no-web 模式运行测试,需要 -c 和 -r 配合使用.
-c NUM_CLIENTS, --clients=NUM_CLIENTS    指定并发用户数,作用于 --no-web 模式。
-r HATCH_RATE, --hatch-rate=HATCH_RATE    指定每秒启动的用户数,作用于 --no-web 模式。
-t RUN_TIME, --run-time=RUN_TIME    设置运行时间, 例如: (300s, 20m, 3h, 1h30m). 作用于 --no-web 模式。
-L LOGLEVEL, --loglevel=LOGLEVEL    选择 log 级别(DEBUG/INFO/WARNING/ERROR/CRITICAL). 默认是 INFO.
--logfile=LOGFILE    日志文件路径。如果没有设置,日志将去 stdout/stderr
--print-stats    在控制台中打印数据
--only-summary    只打印摘要统计
--no-reset-stats    Do not reset statistics once hatching has been completed。
-l, --list    显示测试类, 配置 -f 参数使用
--show-task-ratio    打印 locust 测试类的任务执行比例,配合 -f 参数使用.
--show-task-ratio-json    以 json 格式打印 locust 测试类的任务执行比例,配合 -f 参数使用.
-V, --version    查看当前 Locust 工具的版本.

顺序执行,等待时间,@tag标记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import os
 
from locust import task, between, TaskSet, SequentialTaskSet, constant, constant_pacing, tag
from locust.contrib.fasthttp import FastHttpUser
 
 
class FlashSeqTask(SequentialTaskSet):  # 顺序执行
 
    @tag('tag1')
    @task(1# 设置权重
    def hello_world(self):
        self.client.get("/guonei")
 
 
class FlastTask(TaskSet):  # 并行执行
 
    @tag('tag2')
    @task(1# 设置权重
    def index(self):
        self.client.get("/guoji")
 
 
class Login(FastHttpUser):
    wait_time = constant(2# 任务执行完毕等待2秒开始下一任务
    wait_time = between(1, 7# 任务执行完毕等待1-7秒(中间随机取值)开始下一任务
    wait_time = constant_pacing(2# # 设置任务启动总得等待时间,若任务耗时超过该时间,则任务结束后立即执行下一任务;若任务耗时不超过该时间,则等待达到该时间后执行下一任务。
 
    def wait_time(self):  # 自己定义等待时间
        self.last_wait_time += 1
        return self.last_wait_time
 
    host = "http://news.baidu.com"
    tasks = [FlastTask, FlashSeqTask]
 
 
if __name__ == "__main__":
    os.system("locust -f  test.py --web-host=192.168.104.161 --users=1  --spawn-rate=1 --tags=tag2 --exclude-tags=tag1"# --tags:执行  --exclude-tags:不执行

on_start,on_stop 和事件监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import os
 
from locust import events
from locust import task, between, TaskSet, SequentialTaskSet
from locust.contrib.fasthttp import FastHttpUser
from locust.runners import MasterRunner
 
 
@events.test_start.add_listener  # 事假监听
def on_test_start(environment, **kwargs):
    print("A new test is starting")
 
 
@events.test_stop.add_listener  # 事假监听
def on_test_stop(environment, **kwargs):
    print("A new test is ending")
 
 
@events.init.add_listener  # 事假监听
def on_locust_init(environment, **kwargs):
    if isinstance(environment.runner, MasterRunner):
        print("I'm on master node")
    else:
        print("I'm on a worker or standalone node")
 
 
class FlashSeqTask(SequentialTaskSet):  # 顺序执行
 
    def on_start(self):  # 运行前执行
        print("on_start")
 
    @task(1# 设置权重
    def hello_world(self):
        self.client.get("/guonei")
 
    def on_stop(self):  # 结束执行
        print("on_stop")
 
 
class FlastTask(TaskSet):  # 并行执行
 
    def on_start(self):  # 运行前执行
        ...
 
    @task(1# 设置权重
    def index(self):
        self.client.get("/guoji")
 
    def on_stop(self):  # 结束执行
        ...
 
 
class Login(FastHttpUser):
    wait_time = between(1, 7# 任务执行完毕等待1-7秒(中间随机取值)开始下一任务
    host = "http://news.baidu.com"
    tasks = [FlastTask, FlashSeqTask]
 
 
if __name__ == "__main__":
    os.system("locust -f  test.py --web-host=192.168.104.161 --users=1  --spawn-rate=1")

验证响应 请求标注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import os
 
from locust import task, between, SequentialTaskSet
from locust.contrib.fasthttp import FastHttpUser
from locust.exception import RescheduleTask
 
 
class FlashSeqTask(SequentialTaskSet):  # 顺序执行
 
    @task(1# 设置权重
    def hello_world(self):
        with self.client.get("/", catch_response=True) as response:
            if response.text != "Success"# 验证响应 请求标注
                response.failure("Got wrong response")
            elif response.elapsed.total_seconds() > 0.5:
                response.failure("Request took too long")
            elif response.status_code == 404:
                response.success()
            elif response.status_code == 404:
                raise RescheduleTask()
 
 
class Login(FastHttpUser):
    wait_time = between(1, 3)
    host = "http://news.baidu.com"
    tasks = [FlashSeqTask]
 
 
if __name__ == "__main__":
    os.system("locust -f  test.py --web-host=192.168.104.161 --users=1  --spawn-rate=1")

locust.conf配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
locust.conf
locustfile = ./locust_file.py
headless = true
master = true
expect-workers = 5
host = http://target-system
users = 100
spawn-rate = 10
run-time = 10m
 
-f, --locustfile, locustfile  # 要导入的 Python 模块文件,例如“./other.py”
-H, --host, host  # 主机按以下格式进行负载测试:http://10.21.32.33
-u, --users, users  # 并发 Locust 用户的峰值数量。可以在测试期间通过键盘输入 w、W(生成 1、10 个用户)和 s、S(停止 1、10 个用户)进行更改
-r, --spawn-rate, spawn-rate  # 生成用户的速率(每秒用户数)。主要与 –headless 或 –autostart 一起使用
-t, --run-time, run-time  # 在指定的时间后停止,例如(300s、20m、3h、1h30m 等)。仅与 –headless 或 –autostart 一起使用。默认永远运行。
--web-host, web-host  # 将 Web 界面绑定到的主机。默认为“*”(所有接口)
-P, --web-port, web-port  # 运行网络主机的端口
--headless, headless  # 禁用 Web 界面,并立即开始测试。使用 -u 和 -t 来控制用户数量和运行时间
--autostart, autostart  # 立即开始测试(不禁用 Web UI)。使用 -u 和 -t 来控制用户数量和运行时间
--autoquit, autoquit  # 在运行完成 X 秒后完全退出 Locust。仅与–autostart 一起使用。默认是保持 Locust 运行,直到您使用 CTRL+C 将其关闭
--headful,  headful  # ==抑制==
--web-auth, web-auth  # 为 Web 界面启用基本身份验证。应按以下格式提供:用户名:密码
--tls-cert, tls-cert  # 用于通过 HTTPS 提供服务的 TLS 证书的可选路径
--tls-key, tls-key  # 用于通过 HTTPS 提供服务的 TLS 私钥的可选路径
--master, master  # 设置 locust 以分布式模式运行,此进程作为主进程
--master-bind-host, master-bind-host  # locust master 应该绑定的接口(主机名、ip)。仅在使用 –master 运行时使用。默认为 *(所有可用接口)。
--master-bind-port, master-bind-port  # locust master 应该绑定的端口。仅在使用 –master 运行时使用。默认为 5557。
--expect-workers, expect-workers  # 在开始测试之前,master 应该连接多少工人(仅当使用 –headless 时)。
--worker, worker  # 设置 locust 以分布式模式运行,此进程作为工作线程
--master-host, master-host  # 用于分布式负载测试的locust master的主机或IP地址。仅在与 –worker 一起运行时使用。默认为 127.0.0.1。
--master-port, master-port  # locust master 使用的连接端口,用于分布式负载测试。仅在与 –worker 一起运行时使用。默认为 5557。
-T, --tags, tags  # 要包含在测试中的标签列表,因此只会执行具有任何匹配标签的任务
-E, --exclude-tags, exclude-tags  # 要从测试中排除的标签列表,因此只会执行没有匹配标签的任务
--csv, csv  # 将当前请求统计信息以 CSV 格式存储到文件中。设置此选项将生成三个文件:[CSV_PREFIX]_stats.csv、[CSV_PREFIX]_stats_history.csv 和 [CSV_PREFIX]_failures.csv
--csv-full-history, csv-full-history  # 将每个统计条目以 CSV 格式存储到 _stats_history.csv 文件。您还必须指定“–csv”参数以启用此功能。
--print-stats, print-stats  # 在控制台打印统计信息
--only-summary, only-summary  # 只打印汇总统计信息
--reset-stats, reset-stats  # 生成完成后重置统计信息。在分布式模式下运行时,应该在 master 和 worker 上都设置
--html, html  # 存储 HTML 报告文件
--skip-log-setup, skip-log-setup  # 禁用 Locust 的日志记录设置。相反,配置由 Locust 测试或 Python 默认值提供。
--loglevel, -L, loglevel  # 在调试/信息/警告/错误/关键之间进行选择。默认为信息。
--logfile, logfile  # 日志文件的路径。如果未设置,日志将转到 stdout/stderr
--exit-code-on-error, exit-code-on-error  # 设置当测试结果包含任何失败或错误时使用的进程退出代码
-s, --stop-timeout, stop-timeout  # 退出前等待模拟用户完成任何正在执行的任务的秒数。默认是立即终止。该参数只需要在运行 Locust 分布式时为 master 进程指定。

分布式启动和跨节点通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from locust import HttpUser, TaskSet, task, web, between
from locust import events
 
 
class MyTaskSet(TaskSet):
    @task(2)
    def index(self):
        self.client.get("/")
 
    @task(1)
    def stats(self):
        self.client.get("/stats/requests")
 
 
class WebsiteUser(HttpUser):
    host = "http://127.0.0.1:8089"
    wait_time = between(2, 5)
    tasks = [MyTaskSet]
 
 
stats = {"content-length": 0}
 
@events.quitting.add_listener
def _(environment, **kw):
    if environment.stats.total.fail_ratio > 0.01# 超过 1% 的请求失败
        logging.error("Test failed due to failure ratio > 1%")
        environment.process_exit_code = 1
    elif environment.stats.total.avg_response_time > 200# 平均响应时间大于 200 ms
        logging.error("Test failed due to average response time ratio > 200 ms")
        environment.process_exit_code = 1
    elif environment.stats.total.get_response_time_percentile(0.95) > 800# 响应时间的第 95 个百分位数大于 800 毫秒
        logging.error("Test failed due to 95th percentile response time > 800 ms")
        environment.process_exit_code = 1
    else:
        environment.process_exit_code = 0
 
@events.init.add_listener
def locust_init(environment, **kwargs):
    if environment.web_ui:
        @environment.web_ui.app.route("/content-length")
        def total_content_length():
            return "Total content-length received: %i" % stats["content-length"]
 
 
@events.request.add_listener
def on_request(request_type, name, response_time, response_length, exception, context, **kwargs):
    stats["content-length"] += response_length
 
 
@events.report_to_master.add_listener
def on_report_to_master(client_id, data):
    data["content-length"] = stats["content-length"]
    stats["content-length"] = 0
 
 
@events.worker_report.add_listener
def on_worker_report(client_id, data):
    stats["content-length"] += data["content-length"]
         
 
os.system("locust -f  test.py --web-host=192.168.104.161 --users=10  --spawn-rate=1 --web-port=8089 --master --master-host=192.168.104.161 --master-port=5557")
--master  # 将locust设置为主模式
--master-host=192.168.104.161   # 可选地与--worker设置主节点的主机名/IP一起使用(默认为 127.0.0.1)
--master-port=5557  # 可选地与 with--worker一起设置主节点的端口号(默认为 5557)
 
os.system("locust -f  test.py --web-host=192.168.104.161 --users=10  --spawn-rate=1 --web-port=8089 --worker --master-bind-host=192.168.104.161 --master-bind-port=5557")
--worker  # 将locust设置为工人模式
--master-bind-host=192.168.104.161  # 可选择与--master. 确定主节点将绑定到的网络接口。默认为 *(所有可用接口)
--master-bind-port=5557  # 可选择与--master. 确定主节点将侦听的网络端口。默认为 5557