分布式负载生成
单个 Locust 进程可以模拟相当高的吞吐量。对于简单的测试计划和小负载,它可以每秒发出超过一千个请求,如果使用 FastHttpUser
,甚至可以达到一万多个请求。
但是,如果你的测试计划很复杂,或者你想生成更高的负载,就需要扩展到多个进程,甚至多个机器。幸运的是,Locust 开箱即用支持分布式运行。
为此,你需要启动一个带有 --master
标志的 Locust 实例,并且一个或多个带有 --worker
标志的实例。Master 实例运行 Locust 的 Web 界面,并告诉 worker 何时生成/停止用户。Worker 实例运行用户并将统计信息发送回 Master。Master 实例本身不会运行任何用户。
为了简化启动过程,你可以使用 --processes
标志。它会启动一个 Master 进程和指定数量的 Worker 进程。它也可以与 --worker
配合使用,此时只会启动 Worker。此功能依赖于 fork()
,因此不适用于 Windows 系统。
由于 Python 不能充分利用每个进程的多个核心(见 GIL),你需要为每个处理器核心运行一个 Worker 实例,以便充分利用所有计算能力。 |
每个 Worker 上可以运行的用户数量几乎没有限制。Locust/gevent 可以每个进程运行数千甚至数万个用户,只要它们的总请求速率(RPS)不太高。 如果 Locust 接近耗尽 CPU 资源,它会记录一个警告。如果没有警告,但你仍然无法生成预期的负载,那么问题就出在增加请求速率上。 |
单机模式
启动一个 Master 和四个 Worker 进程非常简单:
locust --processes 4
你甚至可以自动检测机器上的逻辑核心数量,并为每个核心启动一个 Worker:
locust --processes -1
多台机器
在一台机器上启动 Locust 的 Master 模式:
locust -f my_locustfile.py --master
然后,在每个 Worker 机器上运行:
locust -f - --worker --master-host <your master> --processes 4
注意:-f -
参数告诉 Locust 从 Master 获取 locustfile,而不是从本地文件系统获取。这一功能在 Locust 2.23.0 版本中引入。
使用 locust-swarm 进行多台机器部署
当你更改 locustfile 时,你需要重启所有 Locust 进程。locust-swarm
可以为你自动化这个过程。它还解决了从 Worker 到 Master 的防火墙/网络访问问题,使用 SSH 隧道(如果 Master 在你的工作站上而 Worker 在某些数据中心时,通常会遇到此问题)。
安装 locust-swarm
:
pip install locust-swarm
使用命令启动:
swarm -f my_locustfile.py --loadgen-list worker-server1,worker-server2 <any other regular locust parameters>
更多详细信息,请参见 locust-swarm 文档。
分布式负载生成选项
-
--master-host <hostname or ip>
与--worker
一起使用,设置 Master 节点的主机名/IP(默认为 localhost)。 -
--master-port <port number>
与--worker
一起使用,设置 Master 节点的端口号(默认为 5557)。 -
--master-bind-host <ip>
与--master
一起使用,设置 Master 节点绑定的网络接口。默认为*
(所有可用接口)。 -
--master-bind-port <port number>
与--master
一起使用,设置 Master 节点监听的网络端口。默认为 5557。 -
--expect-workers <number of workers>
当以--headless
启动 Master 节点时使用。此时,Master 节点将等待直到 X 个 Worker 节点连接后才开始测试。
节点间通信
当以分布式模式运行 Locust 时,你可能希望在 Master 和 Worker 节点之间进行通信,以协调测试。这可以通过使用内置的消息钩子来轻松实现:
from locust import events
from locust.runners import MasterRunner, WorkerRunner
# Fired when the worker receives a message of type 'test_users'
def setup_test_users(environment, msg, **kwargs):
for user in msg.data:
print(f"User {user['name']} received")
environment.runner.send_message('acknowledge_users', f"Thanks for the {len(msg.data)} users!")
# Fired when the master receives a message of type 'acknowledge_users'
def on_acknowledge(msg, **kwargs):
print(msg.data)
@events.init.add_listener
def on_locust_init(environment, **_kwargs):
if not isinstance(environment.runner, MasterRunner):
environment.runner.register_message('test_users', setup_test_users)
if not isinstance(environment.runner, WorkerRunner):
environment.runner.register_message('acknowledge_users', on_acknowledge)
@events.test_start.add_listener
def on_test_start(environment, **_kwargs):
if not isinstance(environment.runner, WorkerRunner):
users = [
{"name": "User1"},
{"name": "User2"},
{"name": "User3"},
]
environment.runner.send_message('test_users', users)
请注意,在本地运行时(即非分布式),此功能仍然会保留;消息将由发送它们的运行器处理。
注意:使用默认选项注册消息处理程序时,监听器函数将以阻塞方式运行,这会导致心跳和其他消息被延迟。如果你认为消息处理程序需要运行超过一秒钟,可以将其注册为并发的。Locust 会在自己的 greenlet 中运行它。请注意,这些 greenlet 永远不会被 join()
。
environment.runner.register_message('test_users', setup_test_users, concurrent=True)
更多详细信息,请查看完整示例。
使用 Docker 运行分布式
请参阅 [Running in Docker](https://docs.locust.io/en/stable/running-locust-in-docker.html)。
在没有 Web UI 的情况下运行 Locust 分布式
请参阅 [Running Locust distributed without the web UI](https://docs.locust.io/en/stable/running-locust-without-the-web-ui.html)。
提高 Locust 性能
如果你打算运行大规模的负载测试,可能有兴趣使用 Locust 附带的替代 HTTP 客户端。你可以在这里阅读更多内容:[Increase performance with a faster HTTP client](https://docs.locust.io/en/stable/performance.html)。