РазработкаПроизводительность

Производительность и нагрузка (черновик)

Актуально на: 2026-02-13

Цель: выдержать сценарий “до 10 000 одновременных пользователей”, которые редактируют бизнес‑планы (workspace) и периодически сохраняют изменения.

Обновлено: 2026-02-13 (см. CHANGELOG.md).

Самые дорогие операции (что убивает БД при 10k)

  1. Автосейв workspace state
    Ранее сохранение вызывало транзакцию с deleteMany → createMany для продуктов и календаря при каждом автосейве. При частом автосейве (≤ 1–2 сек) это быстро превращается в тысячи тяжёлых write-транзакций/сек.

  2. Проверка доступа на каждый save/load
    Если на каждый save делать project.findFirst(...) по membership, это добавляет лишние read-запросы, которые “съедают” пропускную способность.

  3. Частые сохранения UI-настроек
    saveUserUiSettings делает findUnique + upsert. При маленьком дебаунсе создаёт лишнюю write-нагрузку.

Что уже сделано в коде (для защиты от нагрузки)

  • app/workspace-client-legacy.tsx: автосейв замедлён до 5 секунд и не инициирует revalidate.
  • lib/project-workspace-store.ts: добавлен режим сохранения normalize: "light" | "full" | "none".
    • light сохраняет только ProjectInfo, ProjectSettings и JSON‑снапшот (ProjectWorkspaceState) без массовых delete/create.
    • full оставлен для редких операций (шаблоны/миграции/явное “финальное сохранение”).
  • lib/project-workspace-store.ts: при загрузке workspace приоритет отдаётся самому свежему источнику (если JSON‑снапшот новее нормализованных таблиц — возвращается снапшот).
  • app/(workspace)/projects/[projectId]/actions.ts: добавлен короткий TTL‑кэш проверки доступа и троттлинг обновления Project.name.
  • app/workspace-client-legacy.tsx: сохранение UI‑настроек замедлено до 2.5 секунд.

Рекомендации для продакшена (обязательно при 10k)

База данных

  • Использовать пулер (например, PgBouncer) и ограничить коннекты от приложений.
  • Включить pg_stat_statements, смотреть топ запросов по времени/кол-ву.
  • Следить за размером JSON (ProjectWorkspaceState.state) и частотой UPDATE.

Приложение

  • Разделить “черновой автосейв” (snapshot-only) и “публикацию/финальное сохранение” (full normalize) на уровне UI/UX.
  • Вынести тяжёлые операции (нормализацию, расчёты, генерацию документов) в фоновые задачи (очередь).
  • Добавить rate-limit на сохранения (на уровне API/ingress) по userId+projectId.

План нагрузочного теста (что измеряем)

Метрики:

  • RPS / p95 / p99 для: открытие workspace, автосейв, список проектов.
  • Кол-во запросов к БД на одно действие пользователя (цель: минимизировать).
  • Кол-во write-транзакций/сек и среднее время транзакции.

Сценарии:

  1. 10k пользователей открывают /projects/[id] (read-heavy).
  2. 10k пользователей редактируют и делают автосейв раз в 5–10 сек (write-heavy).
  3. 1–5% пользователей создают проект/шаблон (burst writes).