Pull to refresh
4
Евгений@grokfrog

Живу… хочу в Лос-Анджелес

6
Rating
Send message

Прогнал локальный stress smoke, чтобы не отвечать «на глаз».

Сценарий был довольно жёсткий: большое количество отправок в реальном браузере, не напрямую через API. То есть путь был настоящий:

UI → frontend state/update → штатный send path приложения → backend → API response

Короткий автоматический прогон

На коротком автоматическом прогоне в 130 сообщений картина хорошая:

То есть на обычном сценарии сообщение появляется у отправителя практически мгновенно: p95 до optimistic render — меньше 100 ms.

Ручной stress-тест

Потом отдельно погонял ручной stress-тест: 2009 отправок в реальном браузере.

На этом уровне backend не развалился: все пойманные отправки получили HTTP 200.

Общие метрики ручного stress-теста

Деградация по мере роста количества сообщений

На длинной активной сессии деградация уже видна:

Самое интересное: сильнее всего растёт не только backend response time, а задержка до самого API request. Это указывает, что основной bottleneck появляется на клиенте: длинный список сообщений, React render/DOM, обработчики состояния, возможно IndexedDB/local state и отсутствие полноценной virtualization для длинной истории.

Короткий вывод

Интерфейс на обычном сценарии отзывчивый: десятки миллисекунд до optimistic render.

Backend на stress smoke тоже не развалился: 2009 отправок, 2009 успешных HTTP 200, без network failures.

Но при агрессивном long-chat stress на тысячах сообщений уже видно, где следующий инженерный шаг:

• virtualization списка сообщений;
• изоляция input-компонента от rerender списка;
• batching локальных updates;
• оптимизация обработки статусов/echo/realtime-событий;
• отдельный профайлинг decrypt/render длинной истории.

Важно: это локальный smoke/stress, а не production SLA. Ручной recorder в этом прогоне надёжно мерил send path до API 200; DOM render для длинной ручной сессии я буду мерить отдельным тестом открытия/скролла истории на 1000/5000/10000 сообщений.

Доброй ночи! ответ, на ваш комментарий ниже, мучался с разметкой, не туда написал)

Возможно, местами получилось слишком гладко. Учту, спасибо.

Чем ближе закат империи, тем безумнее её законы.

Дополнительно проверили WebSocket‑часть: на локальном стенде соединения держатся стабильно, а предел дальше упирается уже в ресурсы машины.

Привет! Спасибо за подробный разбор. Такой комментарий действительно полезен: по обычному демо в браузере часть подобных проблем легко не заметить, а при чтении кода они становятся видны сразу.

По нескольким пунктам я с вами согласен.

Замечание про N+1 в уведомлениях при обновлении профиля справедливое. В старом варианте логика действительно могла идти через цепочку “найти чаты пользователя → для каждого чата найти участников → для каждого участника найти пользователя → отправить событие”. Для небольшого демо это незаметно, но как паттерн для роста нагрузки такой подход неудачный.

То же самое с markChatAsRead(). В исходном варианте метод делал слишком много за один вызов: получал список сообщений, проходил по ним в цикле, обновлял receipt/status и отправлял отдельные события. На длинной истории это действительно плохой путь, особенно если чат активно используется.

После вашего комментария я отдельно прошёлся по backend и переработал эти участки.

Что было изменено:

— уведомления при обновлении профиля и обновлении списка чатов переведены на batch-запросы и отправку по уникальным получателям;
mark read / mark delivered переписаны через bulk SQL-операции вместо поштучного прохода по сообщениям;
— вместо множества отдельных status events добавлен bulk status event;
— timeline reactions теперь грузятся пачкой, без N+1 на каждое сообщение;
— список чатов получил пагинацию и сортировку ближе к БД;
— часть логики вынесена из контроллеров в сервисы;
Map<String, Object> в ключевых REST-ответах заменён на typed DTO;
— добавлены индексы под горячие запросы через миграцию V23__performance_indexes.sql;
— после рефакторинга обновлены тесты.

 Что было → стало
Что было → стало

Отдельно прогнал тесты и нагрузочные сценарии по direct-chat path. Backend сейчас проходит 192 теста. По k6 direct-chat battery получилось:

Суммарно по direct-chat battery:
Суммарно по direct-chat battery:

Самым важным результатом для меня было не просто отсутствие ошибок, а то, что mark read / mark delivered не начали деградировать на длинном прогоне. В 30-минутном soak:

При этом я не хочу выдавать эти результаты за полную production-готовность. Это пока проверка именно direct-chat HTTP/API-сценария. Групповые чаты, WebSocket load, сценарии с заранее набитыми 10k+ сообщений, поведение БД на больших объёмах и инфраструктурные лимиты ещё нужно проверять отдельно.

Поэтому я бы сейчас аккуратно сформулировал статус проекта так: это не production-ready мессенджер, но уже рабочий MVP/pet project, который постепенно приводится к более зрелому backend-состоянию.

Ваш комментарий помог подсветить места, которые на обычном демо не бросались в глаза. Спасибо за это. Если будет желание — буду рад продолжить предметно по query patterns, pagination strategy, receipt aggregation и group chat fanout.

█████████████████████████████████▶ 75% начинаю удаление репозитория…

Information

Rating
1,257-th
Location
Россия
Date of birth
Registered
Activity

Specialization

Бэкенд разработчик
Средний
Java