Проєкт Flash Ticket — це мікросервісна система для продажу квитків на події. Архітектура спроєктована таким чином, щоб витримувати високе навантаження (High Load), наприклад, коли тисячі користувачів одночасно намагаються придбати обмежену кількість квитків.
Система складається з таких компонентів (усі розгорнуті через Docker):
- API Gateway (NestJS) — приймає всі HTTP-запити від клієнтів. Замість важкої обробки, він лише ставить задачі в чергу.
- Ticket Worker (NestJS) — фоновий мікросервіс, який розгрібає чергу повідомлень і виконує бізнес-логіку.
- RabbitMQ — брокер повідомлень для зв'язку між Gateway та Worker. Захищає систему від перенавантаження.
- PostgreSQL — основна реляційна база даних (використовується через Prisma ORM).
- Redis — in-memory сховище. Використовується для атомарних операцій (перевірка доступності квитків), щоб уникнути race conditions під час великого напливу людей.
- Встановіть залежності та згенеруйте Prisma клієнт (якщо запускаєте локально):
bun install
- Підніміть усю інфраструктуру через Docker:
docker-compose up -d
- API Gateway буде доступний за адресою:
http://localhost:3000.
Ми створили окремий додаток monolith (порт 3001), який симулює класичний підхід: пряме збереження в PostgreSQL без Redis та черг.
Ось результати порівняльного навантажувального тестування (Load Testing) за допомогою autocannon (200 одночасних з'єднань протягом 10 секунд):
┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼────────┤
│ Latency │ 14 ms │ 20 ms │ 40 ms │ 57 ms │ 21.59 ms │ 9.27 ms │ 169 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴────────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬──────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤
│ Req/Sec │ 5,727 │ 5,727 │ 9,071 │ 10,215 │ 9,049.28 │ 1,151.52 │ 5,726 │
└───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴──────────┴─────────┘
100k requests in 11.03s, 25.5 MB read
Результат у БД: Продано рівно стільки квитків, скільки було на балансі. Жодного овербукінгу.
┌─────────┬───────┬───────┬────────┬────────┬─────────┬──────────┬────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼───────┼────────┼────────┼─────────┼──────────┼────────┤
│ Latency │ 48 ms │ 59 ms │ 197 ms │ 326 ms │ 85.7 ms │ 51.87 ms │ 423 ms │
└─────────┴───────┴───────┴────────┴────────┴─────────┴──────────┴────────┘
┌───────────┬────────┬────────┬────────┬────────┬─────────┬─────────┬────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼────────┼────────┼────────┼────────┼─────────┼─────────┼────────┤
│ Req/Sec │ 957 │ 957 │ 1,600 │ 3,739 │ 2,316.5 │ 1,037.3 │ 957 │
└───────────┴────────┴────────┴────────┴────────┴─────────┴─────────┴────────┘
23k requests in 10.03s, 7.79 MB read
Результат у БД: Катастрофічний овербукінг. Через Race Conditions база даних продала в рази більше квитків, ніж існувало в природі.
- Продуктивність (Req/Sec): Мікросервіси витримали 9 049 запитів за секунду, тоді як моноліт "захлинувся" на 2 316. Різниця майже у 4 рази!
- Затримка (Latency): У мікросервісів середня затримка 21 мс, у моноліту — 85 мс (максимальна стрибала до 423 мс). API Gateway миттєво віддає відповідь користувачу, не змушуючи його чекати на базу даних.
- Цілісність даних: Моноліт без блокувань БД або Redis призвів до продажу неіснуючих квитків (Race Condition), оскільки тисячі паралельних запитів одночасно прочитали, що квитки ще є. Мікросервіс з атомарним
DECRу Redis ідеально захистив систему від овербукінгу, дозволивши зберегти лише валідні замовлення.