Нагружаем веб-сокеты без боли
Обо мне
- SDET с 2018
- Senior SDET @b2broker
- Certified node.js application developer (JSNAD 2023)
- автор TG канала @haradkou_sdet
- Консультирую кампании
- Ментор
Telegram: haradkou_sdet
План
-
контекст проекта
-
наша цель
-
подготовка к нагрузке
-
сценарий
-
итоги и выводы
Контекст проекта
- Trading terminal
- Работа с финансовыми инструментами
Трейдинг терминал

Фото взято с официального сайта b2broker.com/b2trader
Контекст Запуска
- .NET signalR in server + транспорты
- WebSocket
- SSE
- Long Polling
- Forever Frame (IE)
- 1 инстанс каждого сервиса без автоскейлинга
- Автоскейлинг WebSocket довольно сложная задача
WebSocket

SignalR
(картинка с negotiate)
Negotiate -> Transports + access token -> WSS://
Сценарии
- Получения цен в реальном времени - market data
- Создание CFD сделки
Цель нагрузки
Узнать о просадке системы в оптимальном режиме (5 открытых позиции для пользователя)
Боль 1
Sticky sessions & масштабирование
Sticky Sessions
"Прилипшие сессии" - запросы от одного и того же клиента всегда попадали на один и тот же сервер
Sticky Sessions

Решение. Sticky Sessions
Не тестируем (пока что)
Решение. Sticky Sessions

Решение. Sticky Sessions

Боль 2
Business. CFD
Что такое CFD сделка?
CFD - Contract For Difference («контракт на разницу») - это финансовый дериватив. При его открытии ты не покупаешь актив, а заключаешь договор на изменение его цены.
Путь сделки
- Указывается актив — акция, индекс, криптовалюта и т.д.
-
Указывается направление — покупка или продажа.
-
Указывается объём (лот) — сколько единиц актива.
-
Брокер фиксирует цену открытия — например, цена биткоина $60,000.
-
Создаётся запись у брокера — в их базе данных или системе, что ты открыл позицию.
📉 При закрытии сделки считается разница между ценой открытия и закрытия, и эта разница — твоя прибыль или убыток.
Причем здесь WebSocket
После создания позиции, ее (позицию) нужно "слушать" на изменение цены. Если слишком большая "просадка" цены, то вызывается margin call.
Ограничения
- Реальный трейдер не работает одновременно больше чем 3-5 открытых позициях
- Нагрузочные тесты работают с VUS (витруальными пользователями)
- Нагрузочные тесты только создают CFD сделку, но не закрывают позицию
- 1 VUS может создать несколько CFD сделок за несколько итераций
Боль 3
K6
- 30-40k VUS - Limit per k6 instance
- Лимит памяти 1 контейнера внутри паиплаина - DND. Infrastructure
- Сделки нужно держать в пределах 3-5 для пользователя
K6 Ограничение
- 30-40k VUS - Limit per k6 instance
- Лимит памяти 1 контейнера внутри паиплаина - DND. Infrastructure
- Сделки нужно держать в пределах 3-5 для пользователя
Сам сценарий
export const options: Options = {
vus: VUS,
iterations: ITERATIONS
duration: DURATION,
tags: {
PROMETHEUS_ID: K6_PROMETHEUS_ID,
},
}
export default function (){
for (let i = 0; i < CFD_ORDERS_COUNT; i++) {
apiV4CfdOrders.order({
marketId: K6_CFD_MARKET_ID,
orderType: 'Market',
})
}
}Helper. JS
function processRowInfinite(row){
const socket = new WebSocket(`${serverUrl}/?token=${row.token}`)
socket.send('GetOpenPositions', row.accountId)
socket.onMessage = (msg) => {
const deserialized = JSON.parse(msg)
if(deserialized.length > K6_HELPER_OPEN_POSITION_COUNT) {
const firstPos = deserialized.items[0]
fetch(`${serverUrl}/positions/${firstPos.id}/close`, {
method: 'POST',
})
}
}
}
while(true){
csvParsed.map(row => {
processRowInfinite(row)
})
}Боль 4
Инфраструкрура
- DND (Docker in Docker)
- Victoria Metrics хранит срезы до 2-3 недели
- Грамотно упаковать паиплаин
- Поднятие чистого окружения, записи в DNS, очистка окружения
Пайплайн
Init env -> k6 tests -> metrics -> destroy env
Решение
- Отчеты
- Отчеты со срезами основных метрик в confluence
- Отчеты в слак для автоматики
- Увеличенные лимиты для паиплаина и стенда в целом
- Разделение задач для K6 и helper
- Окружение
- Уничтожение старого окружения при запуске нового
- Отдельное окружение для запуска по расписанию
- Удлинение время жизни токенов пользователей
Пайплайн

Отчеты
| Start Time | Duration | RT CFD | RPS CFD | ... |
|---|---|---|---|---|
| 2025-05-12 | 600 | 12 | 500 | ... |
| 2025-05-15 | 600 | 10 | 550 | ... |
| 2025-05-22 | 600 | 15 | 520 | ... |
Confluence для автоматических запусков 2 раза в неделю
Выводы
- система отвечает примерному представлению нашего CTO
- Созданы баги и эпики на улучшение производительности
- Созданы доп. задачи для проверки автоскейлинга и их производительности
Спасибо за площадку
Источники
PerfConf11. Mocow. Нагружаем веб-сокеты без боли
By vitalic gorodkov
PerfConf11. Mocow. Нагружаем веб-сокеты без боли
- 77