You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何确保Locust主从模式下的请求计数准确无偏差?

问题详情

采用包含4个Worker的Master-Worker模式进行压测,自行实现了任务执行次数的计数逻辑。但在WebUI点击Stop按钮结束测试后,发现Locust统计的请求数与自实现计数存在偏差,且被测目标服务器实际接收的请求数也与Locust统计数不符。

自定义计数的代码实现

import copy
from locust import events, FastHttpUser, task, constant_throughput
from locust.runners import MasterRunner
from src import utils
from src.common import ApiClass
from src.common.msg import ResponseMsg
from src.common.handle import AccountBase

req_count = 0


class CommentTask(FastHttpUser, AccountBase):
    wait_time = constant_throughput(1)

    def __init__(self, environment):
        super().__init__(environment)
        self.header = copy.deepcopy(ApiClass.Header)

    @staticmethod
    def on_count(msg, **_kwargs):
        global req_count
        req_count += msg.data['count']

    @staticmethod
    @events.init.add_listener
    def on_locust_init(environment, **_kwargs):
        AccountBase.on_locust_init(environment, **_kwargs)
        CommentTask.host = ApiClass.Host
        if isinstance(environment.runner, MasterRunner):
            environment.runner.register_message('on_count', CommentTask.on_count)

    @staticmethod
    @events.test_start.add_listener
    def on_test_start(environment, **_kwargs):
        AccountBase.on_test_start(environment, **_kwargs)

    @staticmethod
    @events.test_stop.add_listener
    def on_test_stop(environment):
        if isinstance(environment.runner, MasterRunner):
            global req_count
            utils.Log.info(req_count)

    def on_start(self):
        self.header['Token'] = self.account.get()['token']

    @task
    def do_comment(self):
        self.environment.runner.send_message('on_count', {'count': 1})
        with self.client.post(url=ApiClass.Path.CommentSave, headers=self.header, json={},
                              catch_response=True) as response:
            ResponseMsg.assert_send(self.environment.runner, response)

测试结果对比

  • 自定义计数结果:[INFO]-[2023-08-23 11:16:21]-[Dummy-3:2179754179648]-[comment.py:86] - 1728
  • 被测目标服务器实际接收请求数:1725
  • WebUI统计数据与上述两者均存在偏差

请问无其他请求干扰时,如何确保Locust请求计数准确?


解决方案

1. 对齐请求实际生命周期统计计数

你当前在任务刚执行就发送计数消息,但此时请求可能还没完成(比如网络中断、请求被取消),导致自定义计数比实际请求数多。改用Locust内置的请求事件统计,这些事件在请求实际完成(成功/失败)后才触发,能和服务器接收数对齐:

# 替换自定义计数逻辑,改用内置事件
req_count = 0

@events.request_success.add_listener
def on_request_success(request_type, name, response_time, response_length):
    global req_count
    req_count += 1

@events.request_failure.add_listener
def on_request_failure(request_type, name, response_time, exception):
    global req_count
    req_count += 1

# 删除任务代码里的self.environment.runner.send_message('on_count', {'count': 1})

2. 解决Master节点计数的线程安全问题

全局变量req_count在Master多线程环境下存在竞态条件,多个Worker的计数消息同时到达时可能出现计数丢失。加锁保证计数操作的原子性:

import threading

req_count = 0
count_lock = threading.Lock()

@staticmethod
def on_count(msg, **_kwargs):
    global req_count
    with count_lock:
        req_count += msg.data['count']

3. 停止测试时等待Worker消息同步

点击Stop后,Master可能还没接收完所有Worker的计数消息就输出结果,导致计数不全。在test_stop事件中等待所有Worker完成消息同步:

@staticmethod
@events.test_stop.add_listener
def on_test_stop(environment):
    if isinstance(environment.runner, MasterRunner):
        # 等待所有Worker完成状态同步
        environment.runner.worker_state_machines.wait_all()
        global req_count
        utils.Log.info(req_count)

4. 直接使用Locust内置统计模块

Locust本身提供了完善的统计API,无需自行实现计数逻辑,直接通过内置统计获取准确请求数:

@staticmethod
@events.test_stop.add_listener
def on_test_stop(environment):
    if isinstance(environment.runner, MasterRunner):
        total_requests = environment.runner.stats.total.num_requests
        utils.Log.info(f"Locust内置统计总请求数:{total_requests}")

内容的提问来源于stack exchange,提问作者Strawberry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 22:05:34