- Описание
- Механики
- Архитектура
- Инфраструктура и деплой
- Нагрузочные тесты
- Локальный запуск
Превью-видео - https://www.youtube.com/watch?v=U1h8XT0qHMU Telegram handle for testing - @auction_test_nest_bot
В данный момент редис стоит одной тачкой- через него проходят и очереди и кеш, это потенциальный bottleneck. Желательно как минимум 3 штуки на одной поде
- Стек: NestJS (API/WS/BullMQ), MongoDB replica set (транзакции), Redis (cache/pubsub), Socket.IO, Vite/React фронт.
- Назначение: realtime аукционы с транзакциями, анти‑снайпингом, Telegram-уведомлениями и k6 нагрузочными тестами.
- Пользователь при первом входе получает кошелёк (10 000) и роль SUPERADMIN (для тестов).
- Ставки: резерв средств в Mongo транзакции, топ/last ставки в Redis + fallback в Mongo, баланс инвалидация через WS
wallet:update. - Раунды:
currentRound+roundStartedAt/roundEndsAt; анти‑снайпинг продлевает раунд наantiSnipingSeconds; победители получают призы (prizeName#N) и запись в инвентарь. - Минимальная ставка:
minBid(фикс), топ рассчитывается по сумме ставок за раунд. - Роли: SUPERADMIN/ADMIN могут создавать/финишировать аукцион, запускать нагрузку; обычные только ставят.
- Завершение раунда/аукциона: BullMQ job finalize, атомарная транзакция, списание победителей, возврат проигравших, WS/Telegram события.
- Если победителей меньше, чем
winnersPerRound: оставшиеся призы не раздаются и возвращаются в общий пул; следующий раунд стартует с тем же пулом. - Если в раунде нет участников: раунд завершается, призы остаются в пуле, следующий раунд запускается по таймеру (без ручных таймеров).
- После последнего раунда или исчерпания призов аукцион FINISHED; всем, кто не выиграл, зарезервированные средства возвращаются.
- Stateless API + Worker (BullMQ) с Redis pub/sub; Mongo replica set как источник истины для денег.
- WS только для доставки состояния (wallet, auction events); HTTP только команды (auth, bid, create/finish).
- Telegram через очередь, rate-limit на уровне queue; уведомления WIN/ROUND_FINISHED/AUCTION_FINISHED.
- Кеши: топ/last ставки в Redis с очисткой по раунду; баланс в Redis TTL 60s.
- MongoDB replica set (3 ноды) + Redis: docker-compose для локали; Kubernetes манифесты: api/worker (2/1 реплики), Redis Deployment+Service, Ingress без TLS.
- Backend pods: 3 реплики (пробежит по readiness/liveness /healthz). Очереди через Redis (BullMQ).
- Rate-limit можно обходить токеном
ADMIN_STATIC_TOKEN/RATE_LIMIT_BYPASS_TOKENили заголовкомX-Load-Test:true(для нагрузочных тестов).
-
k6 скрипты:
infra/k6/auction-load.js(аукционная модель, stop за 10s до анти-снайпа и 5s после конца раунда),infra/k6/rps-spike.js(ступени до 10k RPS, шлёт Authorization и X-Load-Test). -
runner (apps/load-test-runner) читает PENDING job из Mongo и ставит FINISHED с summary/error.
-
Админское API
/admin/load-test/startсоздаёт PENDING job (без запуска k6 в проде).
-
В конечном итоге на поде добился ~600 рпс на получение аукционов. При рпс >1000 идет бекпрешер, увеличивается время запроса кратно
Как решить - настроить грамотно балансировщик между двумя подами кубика где развернуты по 3 штуки апи + воркер для тестов и редиска
- deps:
cd apps/backend && npm install
cd ../frontend && npm install- поднять инфру:
echo "127.0.0.1 host.docker.internal" | sudo tee -a /etc/hosts
docker compose -f infra/docker/docker-compose.yml up -d
docker compose -f infra/docker/docker-compose.yml logs -f mongo-setupпроверка:
mongosh "mongodb://localhost:27017,localhost:27018,localhost:27019/auction?replicaSet=rs0&retryWrites=true&w=majority" --eval "rs.status().members.map(m=>({name:m.name,state:m.stateStr}))"
redis-cli -h 127.0.0.1 -p 6379 ping- backend:
cd apps/backend
npm run start:dev
curl http://localhost:3000/healthz- frontend:
cd apps/frontend
npm run devNODE_ENV=production|developmentPORT=3000MONGO_URI=mongodb://localhost:27017,localhost:27018,localhost:27019/auction?replicaSet=rs0&retryWrites=true&w=majorityMONGO_DB=auctionREDIS_HOST=127.0.0.1REDIS_PORT=6379QUEUE_PREFIX=auctionJWT_SECRET=your_jwt_secretADMIN_STATIC_TOKEN=...(для админских нагрузочных скриптов)RATE_LIMIT_BYPASS_TOKEN=...(чтобы обходить rate-limit в k6)ENABLE_TELEGRAM_NOTIFICATIONS=false|trueTELEGRAM_BOT_TOKEN=...(если нотификации включены)ENABLE_LOAD_TESTS=true|false
VITE_BACKEND_URL=http://localhost:3000VITE_BACKEND_WS=http://localhost:3000(если нужен другой хост для ws)