Руководства16 июля 2026 г. · 6 мин чтения

Нативное нагрузочное тестирование WebSocket — и в open source

perfscale v0.6.0 приносит шесть встроенных WebSocket-actions: one-shot-сессии, живые соединения между шагами, динамические потоки сообщений и честную метрику message-RTT. Бесплатно для всех, в open-source-движке.

Автор: Команда Perfscale

Нативное нагрузочное тестирование WebSocket — и в open source

Торговые фиды, чаты, состояние мультиплеера, GraphQL-подписки — realtime-половина вашего стека говорит на WebSocket, а perfscale до сих пор заставлял тестировать её через k6-скрипты. Начиная с v0.6.0 WebSocket — полноценный нативный транспорт: шесть actions std/ws* в open-source-движке, рядом со std/http, std/tcp и std/udp.

И в отличие от нашей поддержки FIX, WebSocket бесплатен для всех. Это commodity-транспорт; прятать его за план было бы глупо. Actions, генератор сообщений и метрики живут в open-source-репозитории.

Один шаг — одна сессия

Самый быстрый вход — std/ws@v1: подключиться, обменяться сообщениями, закрыть, всё за один замер:

steps:
  - uses: std/ws@v1
    with:
      url: wss://stream.example.com/feed
      messages:
        - send: '{"op":"subscribe","channel":"trades","id":"sub-${seq}"}'
          until_json: { type: trade }
    check:
      message_matches: { type: trade }

Правило until_json объясняет шагу, что считать ответом: читать из стрима, пока сообщение не совпадёт по JSON с { type: trade }, затем идти дальше. Не совпало за таймаут? Шаг падает — это и есть сигнал нагрузочного теста.

Или держите соединение между шагами

Реальные сценарии редко умещаются в один шаг. std/ws-connect@v1 открывает живое соединение, к которому следующие шаги обращаются по id — WebSocket-трафик чередуется с чем угодно ещё:

steps:
  - uses: std/ws-connect@v1
    with: { url: "wss://stream.example.com/feed" }
    outputs: feed

  - uses: std/ws-send@v1
    with:
      id: "${{ feed.id }}"
      send: '{"op":"order","id":"ord-${seq}","px":${randf(1.05,1.15,5)}}'
      repeat: 100
      interval_ms: 50

  - uses: std/ws-recv@v1
    with: { id: "${{ feed.id }}", until_json: { type: fill } }

  - uses: std/ws-close@v1
    with: { id: "${{ feed.id }}" }

Эта строка send — один шаблон, порождающий 100 уникальных ордеров: токены ${seq}, ${uuid}, ${rand}, ${randf}, ${choice} и ${now_*} раскрываются на каждую отправку. Тот же генератор, что питает наши FIX-actions, теперь живёт в открытом движке — один словарь токенов на все протоколы.

Метрика задержки, которая не врёт

Большинство WebSocket-тестов выдают мутное число: время в цикле приёма, которое в основном измеряет, когда серверу захотелось push'нуть. Мы отказались класть это в гистограмму латенси.

Вместо этого perfscale сообщает три честные вещи:

  • Время handshake и one-shot-сессии попадает в http_req_duration — операции с определённым началом и концом, сравнимые с перцентилями HTTP/TCP/UDP.
  • ws_msg_rtt — время от отправки до первого ответа, совпавшего с вашим until-правилом. Метрика существует, только когда вы объявили, что считать ответом — поэтому её p95 что-то значит.
  • ws_msgs_sent / ws_msgs_received — обычные скорости обмена.
ws_msg_rtt: avg=12.40ms p(50)=11.00ms p(90)=18.20ms p(95)=21.50ms p(99)=30.10ms min=4.10ms max=35.00ms count=400
ws_msgs_sent: 2000 400.00/s
ws_msgs_received: 1200 240.00/s

На платформе WebSocket-прогон распознаётся автоматически, и дашборд переключается на WS-плитки: throughput сообщений, перцентили RTT, латенси handshake.

Ассерты на стримах

Стримы шумные — heartbeat'ы, presence-события, чужие сообщения. Поэтому ассерты сообщений работают в семантике «хотя бы одно совпало» — и на любом протокольном action, который отдаёт список messages (WebSocket и FIX одинаково):

check:
  message_matches: { type: fill, symbol: EURUSD }
  messages_count_gte: 5

Остальное тоже на месте: бинарные фреймы как base64, согласование subprotocol'ов (graphql-ws, STOMP), wss:// со skipTLSVerify для self-signed staging, переиспользуемые connection-профили и транспортный std/ws-ping@v1 для keep-alive-проверок.

Попробуйте

npm install -g @perfscale/exe   # или: perfscale self-update
perfscale run -f examples/websocket.test.yaml

Начните с гайда по WebSocket, документации или готового examples/websocket.test.yaml. Если ваш realtime-стек плавится на пике — лучше узнать об этом из YAML-файла, чем от пользователей.

Комментарии

Ответить в Bluesky