саранча: распределенный стресс-тест 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
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода