саранча: распределенный стресс-тест Python (с WebUI)
саранча: распределенный стресс-тест Python (с WebUI)

Введение в саранчу

Он реализован на чистом Python и представляет собой инструмент распределенного пользовательского нагрузочного тестирования. Использование клиента на основе библиотеки Requests для инициирования запросов значительно упрощает написание сценариев; он отказывается от процессов и потоков при моделировании параллелизма и полностью управляем по времени, используя неблокирующий ввод-вывод и сопрограммы, предоставляемые сопрограммами (gevent), для реализации параллельных запросов на одном этапе. сетевой слой. Таким образом, одно нажатие может генерировать тысячи одновременных запросов.

Официальный сайт саранчи

Функции:

  1. Скрипты, основанные на Requests и Gevent Python, просты и легко читаются.
  2. Архитектура c/s имеет простой пользовательский интерфейс, который отображает соответствующие результаты в режиме реального времени.
  3. поддерживатьраспределенныйтест, Может быть легко расширен между платформами

Установка и использование

Установить

Поддерживаемые версии Python: 3.6, 3.7, 3.8.

Язык кода:javascript
копировать
pip install -U locust==2.5.1
#pip install -U locust==2.5.1 -i https://pypi.tuna.tsinghua.edu.cn/simple

Быстрый в использовании

  • locust серединапроходить HttpUser Чтобы представить пользователя, нам нужен собственный класс, унаследованный от HttpUser
  • HttpUser из client Свойства могут имитировать запросы и поддержку клиентов. get,post Метод ожидания и автоматическое поддержание сессия. (На самом деле он requests Сумкаиз session объект)
    • client из get,post Ожидание доставки метода url Адрес, не нужно носить с собой http://www.example.com Для этого префикса вам нужно указать только путь
  • wait_time Время ожидания перед следующим заданием изучить,используется для Выдавать себя за пользовательиз время подумать,
    • wait_time = Between(1, 5) Интервал представляет собой случайную величину от 1 до 5 секунд.
    • wait_time = constant(1) Интервал фиксированный и составляет 1 секунду.
  • host Указывает изадрес сервера, например: http://www.baidu.com
  • проходить @task Украсьте метод. Этот метод представляет возможные действия пользователя. Пользователь может иметь несколько действий.
    • Какое конкретное действие пользователь хочет предпринять дальше, является случайным, то есть locust случайным образом выберет одно из списка действий
    • @task Принимает параметр, указывающий вес. Чем больше значение, тем выше вероятность того, что это действие будет выбрано.
  • on_start тест Доосуществлятьиздействовать
  • on_stop тест Заканчиватьосуществлятьиздействовать
Язык кода:javascript
копировать
from locust import HttpUser, task, between

# Эквивалентно моделированию пользователя
class WebUser(HttpUser):
    # Адрес сервера
    host = 'http://localhost:8000'

    # Время ожидания перед следующим заданием. Изучите время обдумывания для пользователя шаблона.
    wait_time = between(3, 5)  # Здесь используется случайный 3,5 секунды

    # Определите тестовую задачу, похожую на сэмплер.
    @task(1)
    def info(self):
        # Получить информацию о пользователе
        self.client.get('/info/')

    @task(10)
    def addresses(self):
        # Получить адрес пользователя
        self.client.get('/addresses/')

    def on_start(self):
        # тест Доосуществлятьиздействовать        print('Вход пользователя')
        auth = {'username': 'root', 'password': 'root1234'}
        self.client.post('/login/', json=auth)

    def on_stop(self):
        # тест Заканчиватьосуществлятьиздействовать        print('Пользователь вышел')
        self.client.delete('/logout/')

Начать саранчу

  • В текущем каталоге Может Запускать напрямуюlocust Он автоматически найдет имя locustfile.py из файла
  • Для подкаталогов или каталогов разных уровней: Можетиспользовать-f начало команды locust -f xxx/locustfile.py
Язык кода:javascript
копировать
# Запускать напрямую
locust

# Укажите файл
locust -f xxx/locustfile.py

Затем откройте браузер, прямойсуществовать Ввод через браузерhttp://localhost:8089ОткрытьUIинтерфейс, Интерфейс выглядит следующим образом:

бесинтерфейсный тест саранчи

locust -f locustfile.py --headless -u 100 -r 10 -t 10s

  • --headless означает не запускать интерфейс
  • -u [число] Установить количество виртуальных пользователей
  • -r [время] Количество виртуальных пользователей, запускаемых в секунду
  • -t [время] Как долго ставить тест ----Секунды, добавьте после числа s ,Например 10s ----Минуты, добавьте после числа m,Например 1m ----Час, добавьте после числа h,Например 1h

базовый пример

Язык кода:javascript
копировать
from locust import User, events, task, between
import random


def success_call(name, recvText, total_time):
    events.request_success.fire(
        request_type="[Success]",
        name=name,
        response_time=total_time,
        response_length=len(recvText)
    )


def fail_call(name, total_time):
    events.request_failure.fire(
        request_type="[Fail]",
        name=name,
        response_time=total_time,
        response_length=0,
        exception=Exception(),
    )


class MyUser(User):
    wait_time = between(1, 5)

    @task(1)
    def job1(self):
        print('This is job 1')
        self.sendMsg("job1", 'This is job 2')

    @task(2)
    def job2(self):
        print('This is job 2')
        self.sendMsg("job2", 'This is job 2')

    def sendMsg(self, methodname, msg):
        num = random.randint(0, 2)
        time = random.randint(10, 50)
        if (num == 0):
            fail_call(methodname, time)
        else:
            success_call(methodname, msg, time);

осуществлять

Язык кода:javascript
копировать
locust -f test4.py --autostart --autoquit 0 -u 1 -r 3 --run-time 10s

в

  • request_typeМетод запроса,Здесь для удобства понимания,прямойиспользоватьиз[Success]и[Fail],отличать успехизпроситьинеудачаизпросить,Только после успеха или неудачи вызывается обратный вызов,саранча засчитает это.

Уведомление:

Все задачи не могут быть методами.

результат:

саранча распространена

Locus запускает несколько процессов, использовать --master Команда запускает основной процесс, использовать --worker Запустить подчиненный процесс

Главный процесс управляет подчиненным процессом и собирает результаты процессизтестирования, а подчиненный процесс отвечает за изучение теста и передает результаты главному процессу.

Запустите основной процесс без интерфейса

Язык кода:javascript
копировать
locust -f locustfile.py --master --headless --master-bind-host=127.0.0.1 --master-bind-port=8090 -t 15s -u 5 -r 1
  • --master Укажите, что текущий хост — процесс
  • --master-bind-host=[ip адрес] Укажите основную привязку процесса и задрес
  • --master-bind-port=[номер порта] Укажите основную привязку процесса по номеру порта

После запуска, если текущего подчиненного устройства из процесса нет, отобразится сообщение «Ожидание подчиненного устройства от процесса». Скрипт изучения доступен при запуске из процесса.

Запустите бесинтерфейсный подчиненный процесс:

Язык кода:javascript
копировать
locust -f locustfile.py --worker --master-host=127.0.0.1 --master-port=8090 --headless
  • --worker Указывает, что текущее местоположение принадлежит процессу.
  • --master-host=[ip адрес] Указывает на необходимость подключения к основному процессизу. ip адрес
  • --master-port=[номер порта] Указывает на необходимость подключения к основному процессизу.порт

После запуска процесса начнется изучениетест и основной процесс подсчитает результаты.

Набор действий Набор задач

для web Для веб-сайтов пользователи обычно могут выполнять несколько действий на одной странице веб-сайта, и эти действия обычно преследуют определенную цель. Например, на странице регистрации пользователи могут выполнять действия: Убедитесь, что имя пользователя и номер мобильного телефона повторяются, обновите графический проверочный код, получите проверочный код мобильного телефона и т. д. Целью этих действий является завершение регистрации пользователя. Мы можем объединить эти действия вместе.

В locust мы используем класс TaskSet для объединения нескольких действий, а затем вводим набор задач в объект HttpUser, добавляя класс набора задач в список атрибутов задач.

Наборы задач также могут быть вложенными. Мы добавляем другие классы набора задач, которые будут вложены в атрибут задач набора задач. Аналогично: Домашняя страница веб-сайта содержит страницу входа пользователя, а страница входа пользователя содержит страницу регистрации пользователя.

  • Уведомление: taskset Эквивалент специального действия, если locust войти в taskset Визуизировать действие, затем locust всегда будетосуществлять taskset из действия, тогда WebUser Действие, определенное в из, не будет изучаться. нужно быть внутри taskset позвонить self.ingterrupt() Для выхода обычно можно определить действие, это действие называется call self.interrupt()
Язык кода:javascript
копировать
import uuid

from locust import HttpUser, task, between, TaskSet

# зарегистрироваться
class RegistTaskSet(TaskSet):
    # Имя пользователя дублируется?
    @task
    def username_count(self):
        username = 'zhangsan'
        self.client.get(f'/usernames/{username}/count/')

    # Дублируется ли номер мобильного телефона?
    @task
    def mobile_count(self):
        mobile = '13712345678'
        self.client.get(f'/mobiles/{mobile}/count/')

    # Получить графический код подтверждения
    @task
    def image_codes(self):
        image_code_id = str(uuid.uuid4())
        self.client.get(f'/image_codes/{image_code_id}/')

    @task
    def stop(self):
        print('Выход из текущего набора действий')
        self.interrupt()

# Авторизоваться
class UserLoginTaskSet(TaskSet):
    # Вложенный пользователь зарегистрироваться
    tasks = [RegistTaskSet]

    @task
    def username_login(self):
        auth = {'username': 'root', 'password': 'root1234'}
        self.client.post('/login/', json=auth)

    @task
    def stop(self):
        print('Выход из текущего набора действий')
        self.interrupt()

# Выдавать себя за пользователя
class WebUser(HttpUser):
    # Сумка Содержит пользователей Авторизоваться
    tasks = [UserLoginTaskSet]
    # Адрес сервера
    host = 'http://localhost:8000'

    # Время ожидания перед следующим заданием. Изучите время обдумывания для пользователя шаблона.
    wait_time = between(3, 5)  # Здесь используется случайный 3,5 секунды

    @task
    def search(self):
        # поиск
        self.client.get('/search/')

Упорядоченный набор действий SequentialTaskSet

мы HttpUser а также TaskSet После определения действия саранча заключается в случайном выборе действия из этих действий для изучения.,Иногда мы хотим, чтобы действия пользователя были упорядоченными,например:

1. Проверьте, не дублируется ли имя пользователя. 2. Проверьте, дублируется ли номер мобильного телефона. 3. Проверьте и получите графический проверочный код. 4. Получите код подтверждения мобильного телефона. 5.Зарегистрируйтесь На этом этапе вам необходимо определить набор действий через SequentialTaskSet, который будет вызываться один раз в том порядке, в котором определены задачи.

  • использоватьизметод TaskSet То же самое, но вес декоратора задачи недействителен.
Язык кода:javascript
копировать
from locust import HttpUser, task, between, SequentialTaskSet

class RegistSeqTaskSet(SequentialTaskSet):
    # Имя пользователя дублируется?
    @task
    def username_count(self):
        print('Проверить имя пользователя')
        username = 'zhangsan'
        self.client.get(f'/usernames/{username}/count/')

    # Дублируется ли номер мобильного телефона?
    @task
    def mobile_count(self):
        print('Подтвердить номер мобильного телефона')
        mobile = '13712345678'
        self.client.get(f'/mobiles/{mobile}/count/')

    # Получить графический код подтверждения
    @task
    def image_codes(self):
        print('Получить графический код подтверждения')
        image_code_id = str(uuid.uuid4())
        self.client.get(f'/image_codes/{image_code_id}/')

# Выдавать себя за пользователя
class WebUser(HttpUser):
    # Сумка Содержит пользователей Авторизоваться
    tasks = [RegistSeqTaskSet]
    # Адрес сервера
    host = 'http://localhost:8000'

    # Время ожидания перед следующим заданием. Изучите время обдумывания для пользователя шаблона.
    wait_time = between(3, 5)  # Здесь используется случайный 3,5 секунды

утверждение

Нам нужно определить, завершился ли запрос неудачно или успешно. Нам нужно добавить catch_response=True в параметры запроса, чтобы метод запроса возвращал диспетчер контекста.

Этот контекстный менеджер возвращает объект ответа. Мы отмечаем этот запрос как неудавшийся, вызывая ошибку (сообщение) объекта ответа.

проходить catch_response=True параметры для продолженияутверждение。

Язык кода:javascript
копировать
from locust import HttpUser, task, between

class WebUser(HttpUser):
    wait_time = between(1, 5)
    host = 'http://localhost:8000'

    @task
    def info(self):
        with self.client.get('/info/', catch_response=True) as resp:
            res = resp.json()
            if res['code'] != 0:
                resp.failure(res['errmsg'])

WebSocket

Прежде чем нагрузить WS, нам нужно сначала посмотреть, как подключиться к WS.

Подключение к библиотеке WSiz имеет поддержку асинхронногоIOiz.,Рекомендуем эту библиотеку в проекте,ноВам все равно придется выбирать библиотеку синхронныйиз при тестировании давления.

асинхронный

Установить

Язык кода:javascript
копировать
pip install websockets

пример кода

Язык кода:javascript
копировать
import asyncio
import websockets
import json
import random

async def mytest():
    async with websockets.connect('wss://sockettest.xhkjedu.com/ws') as websocket:
        num = random.randint(0, 10000000)
        msg = {
            "b": {"num": num},
            "c": 123456,
        }

        msgstr = json.dumps(msg)

        await websocket.send(msgstr)
        print(f"↑: {msgstr}")

        greeting = await websocket.recv()
        print(f"↓: {greeting}")

asyncio.get_event_loop().run_until_complete(mytest())

синхронный

Официальный адрес сайта

https://pypi.org/project/websocket-client/

Установить

Язык кода:javascript
копировать
pip install websocket-client

Пример

Язык кода:javascript
копировать
from websocket import create_connection
import json
import random

ws = create_connection("wss://sockettest.xhkjedu.com/ws")

num = random.randint(0, 10000000)
msg = {
    "b": {"num": num},
    "c": 123456,
}

msgstr = json.dumps(msg)
print("Sending " + msgstr)
ws.send(msgstr)

result = ws.recv()
print("Received '%s'" % result)
ws.close()
Язык кода:javascript
копировать
import websocket

def on_message(ws, message):
    print(ws)
    print(message)

def on_error(ws, error):
    print(ws)
    print(error)

def on_close(ws):
    print(ws)
    print("### closed ###")

websocket.enableTrace(True)
ws = websocket.WebSocketApp("ws://127.0.0.1:8888/track",
                            on_message=on_message,
                            on_error=on_error,
                            on_close=on_close)

ws.run_forever()

Стресс-тест вебсокета

Jmeter хочет интерфейс testwebsocket,Нужно сначала скачать Установитьодинwebsocket samplers by peter doornboschизплагин

Поскольку locust реализован в коде, любой тест можно выполнить, обратившись к соответствующей библиотеке.

Язык кода:javascript
копировать
from locust import User, task, events
import time
from websocket import create_connection
import json
import random

def success_call(name, recvText, total_time):
    events.request_success.fire(
        request_type="[Success]",
        name=name,
        response_time=total_time,
        response_length=len(recvText)
    )

def fail_call(name, total_time, e):
    events.request_failure.fire(
        request_type="[Fail]",
        name=name,
        response_time=total_time,
        response_length=0,
        exception=e,
    )

class WebSocketClient(object):
    def __init__(self, host):
        self.host = host
        self.ws = None

    def connect(self, burl):
        self.ws = create_connection(burl)

    def recv(self):
        return self.ws.recv()

    def send(self, msg):
        self.ws.send(msg)

class WebsocketUser(User):
    abstract = True

    def __init__(self, *args, **kwargs):
        super(WebsocketUser, self).__init__(*args, **kwargs)
        self.client = WebSocketClient(self.host)
        self.client._locust_environment = self.environment

class ApiUser(WebsocketUser):
    host = "wss://sockettest.xhkjedu.com/"

    @task(1)
    def pft(self):
        # wss адрес
        self.url = 'wss://sockettest.xhkjedu.com/ws'
        print("перед подключением")
        start_time = time.time()
        try:
            self.client.connect(self.url)
            print("После подключения")
            # Отправить запрос на подписку
            num = random.randint(0, 10000000)
            msg = {
                "b": {"num": num},
                "c": 123456,
            }

            msgstr = json.dumps(msg)

            self.client.send(msgstr)
            print(f"↑: {msgstr}")

            greeting = self.client.recv()
            print(f"↓: {greeting}")

        except Exception as e:
            total_time = int((time.time() - start_time) * 1000)
            fail_call("Send", total_time, e)
        else:
            total_time = int((time.time() - start_time) * 1000)
            success_call("Send", "success", total_time)

тест

Язык кода:javascript
копировать
locust -f main.py -u 5000 -r 300

Доступ через Интернет

http://localhost:8089/

Или не используйте графический интерфейс

Язык кода:javascript
копировать
locust -f main.py --autostart --autoquit 0 -u 1 -r 3 --run-time 10s

в

  • --autostart Запускать автоматически НетиспользоватьWebUI
  • --autoquit 0 иautostartсоответствоватьиспользовать,Через какое время тест завершается после завершения?,Единицей измерения следующих чисел являются секунды.,Если вы его не установите, выйти можно только по CTRL+C.
  • -u 1 Максимальное количество пользователей
  • -r 3 Количество пользователей, созданных в секунду, количество пользователей, созданных в секунду количество пользователи не будут создаваться снова после того же
  • --run-time 10s Испытание давлением изолировать время
boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose