首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何为蝗虫设定目标?

如何为蝗虫设定目标?
EN

Stack Overflow用户
提问于 2021-09-02 10:05:27
回答 2查看 232关注 0票数 1

我们有一个Locust负载/性能测试运行(在一个码头-合成设置)。它现在运行在我们的构建服务器上。

理想情况下,如果某些需求没有得到满足,我们希望构建作业失败。

例如,需要一定的平均响应时间,或在给定超时内请求的最少数量。

期望值/需求必须与汇总数据进行比较。所以在单独的(python)测试方法中没有。

一种选择是解析生成的报告,但我想locust已经内置了对我正在考虑的特性的支持。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-02 10:10:30

查看蝗虫-插件,特别是自定义命令行选项,如--check-rps--check-fail-ratio--check-avg-response-time

examples.sh

票数 1
EN

Stack Overflow用户

发布于 2021-09-02 13:12:27

为了实现自动的KPI验证,您可以使用locust的事件钩子及其内部统计信息创建一个自定义插件。整个插件设计非常简单:

  1. 注册退出事件
  2. 获取所有统计数据并序列化它们。
  3. 计算丢失的指标(RPS、百分位数、…)
  4. 检查提供的KPI定义
  5. 验证提供的KPI再次进行实际测量

整个KPI插件代码如下所示:

代码语言:javascript
运行
复制
import logging
from enum import Enum
from typing import List

import locust.env
from locust.stats import calculate_response_time_percentile


class Metric(Enum):
    EROR_RATE = 'error_rate'
    PERCENTILE_90 = 'percentile_90'
    RPS = 'rps'

    @staticmethod
    def has_value(item):
        return item in [v.value for v in Metric.__members__.values()]


class KpiPluigin:
    def __init__(
            self,
            env: locust.env.Environment,
            kpis: List,
    ):
        self.env = env
        self.kpis = kpis
        self.errors = []
        self._validate_kpis()

        events = self.env.events
        events.quitting.add_listener(self.quitting)  # pyre-ignore

    def quitting(self, environment):
        serialized_stats = self.serialize_stats(self.env.stats)
        updated_stats = self._update_data(serialized_stats)
        self._kpi_check(updated_stats)
        self._interpret_errors()

    def serialize_stats(self, stats):
        return [stats.entries[key].serialize() for key in stats.entries.keys() if
                not (stats.entries[key].num_requests == 0 and stats.entries[key].num_failures == 0)]

    def _update_data(self, stats):
        for stat in stats:
            stat['error_rate'] = self._calculate_fail_rate(stat)
            stat['percentile_90'] = self._calculate_percentile(stat, 0.90)
            stat['rps'] = self._calculate_rps(stat)
        return stats

    def _calculate_rps(self, stat):
        rps = stat['num_reqs_per_sec']
        num_of_measurements = len(rps)
        return sum(rps.values()) / num_of_measurements

    def _calculate_fail_rate(self, stat):
        num_failures = stat['num_failures']
        num_requests = stat["num_requests"]
        return (num_failures / num_requests) * 100

    def _calculate_percentile(self, stat, percentile):
        response_times = stat['response_times']
        num_requests = stat['num_requests']
        return calculate_response_time_percentile(response_times, num_requests, percentile)

    def _kpi_check(self, stats):
        if len(stats) == 0:
            return

        for kpi in self.kpis:
            name = list(kpi.keys())[0]
            stat = next(stat for stat in stats if stat["name"] == name)
            if stat:
                kpi_settings = kpi[list(kpi.keys())[0]]
                for kpi_setting in kpi_settings:
                    self._metrics_check(kpi_setting, stat)

    def _metrics_check(self, kpi_setting, stat):
        (metric, value) = kpi_setting
        name = stat["name"]
        if metric == Metric.EROR_RATE.value:
            error_rate = stat['error_rate']
            error_rate <= value or self._log_error(error_rate, kpi_setting, name)
        if metric == Metric.PERCENTILE_90.value:
            percentile = stat['percentile_90']
            percentile <= value or self._log_error(percentile, kpi_setting, name)
        if metric == Metric.RPS.value:
            rps = stat['rps']
            rps >= value or self._log_error(rps, kpi_setting, name)

    def _log_error(self, stat_value, kpi_settings, name):
        (metric, value) = kpi_settings
        self.errors.append(
            f"{metric} for '{name}' is {stat_value}, but expected it to be better than {value}")  # noqa: E501

    def _interpret_errors(self):
        if len(self.errors) == 0:
            logging.info('All KPIs are good!')
        else:
            for error in self.errors:
                logging.error(f"SLA failed: \n {error}")
            self.env.process_exit_code = 1

    def _validate_kpis(self):
        for kpi in self.kpis:
            kpi_keys = list(kpi.keys())
            if len(kpi_keys) > 1:
                raise Exception("Every dict must contain definition for only one endpoint")
            kpi_settings = kpi[kpi_keys[0]]
            if len(kpi_settings) == 0:
                raise Exception(f"No KPI defined for endpoint {kpi_keys[0]}")
            for kpi_setting in kpi_settings:
                (metric, value) = kpi_setting
                if not isinstance(value, (int, float)):
                    raise Exception(f"Provide valid value for '{metric}' metric for endpoint {kpi_keys[0]}")
                if not Metric.has_value(metric):
                    raise Exception(f"Metric {metric} not implemented")

现在,您必须在Locust脚本中注册KpiPlugin类,并像这样定义KPI:

代码语言:javascript
运行
复制
events.init.add_listener
def on_locust_init(environment, **_kwargs):
    KPI_SETTINGS = [{'/store/inventory': [('percentile_90', 50), ('rps', 500), ('error_rate', 0)]}]
    KpiPlugin(env=environment, kpis=KPI_SETTINGS)

以上脚本将使您的构建失败,以防/存储/库存端点不符合定义的标准之一-- 90百分位数小于50 is,RPS低于500,错误率高于0%。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69028172

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档