krusty-krab-project
Overview - Закусочная Красти Краб
- API Gateway – входная точка.
- Маршрутизация запросов
- Балансировка нагрузки *
- Menu Service:
- Resilience4j RateLimiter
- Resilience4j Retry
- Cache SoftReference
- SpringDoc OpenAPI
- Order Service
- ReadWriteLock
- Inventory Service
- Semaphore
- ConcurrentHashMap
- Payment Service
- Resilience4j Circuit Breaker
- JavaNIO
- OffHeap
- Scheduler
- Задачи по расписанию (Spring Scheduler)
- Общие
- JMeter тесты *
- Docker
- Применение паттернов в проектировании и архитектуре микросервисов
Детализация взаимодействий
Более подробно по каждому сервису - service-name/doc/desc.md
- Клиент → API Gateway
Технологии:
Spring Cloud
Все запросы сначала попадают в Gateway (например, http://localhost:8080/api/...).
Gateway маршрутизирует запрос нужному сервису:
Gateway балансирует нагрузку (если сервисов несколько копий).
- Запросы к Menu Service
Технологии:
Кеш – ConcurrentHashMap + WeakReference.
RateLimiter – если запросов > 10/сек → 429 Too Many Requests
Retry - возвращает дефолтное меню
Actuator metrics - метрики для подсчета запросов на определенные ендпоинты
SpringDoc OpenAPI - Автоматически генерируемая документация API
3. Создание заказа (Order Service → Inventory Service)
Технологии:
Semaphore – ограничивает параллельные списания со склада.
ReadWriteLock – защита от race condition при изменении статуса заказа.
4. Оплата (Order Service → Payment Service)
Технологии:
Circuit Breaker – защита при сбоях платежного шлюза
Off-Heap – логи заказов пишутся в файл через ByteBuffer (JavaNIO).
5. Фоновые процессы (Scheduler)
Технологии:
@Scheduled в Spring.
Метрики в Actuator (кол-во отменённых заказов).
6. Все приложение в целом
Технологии:
Паттерны микросервисной архитектуры
| Паттерн | Где применен | Зачем |
|---|---|---|
| API Gateway | Отдельный сервис (api-gateway) | Единая точка входа для клиентов |
| Database per Service | отдельные БД | независимость сервисов |
| Saga | Заказ → Оплата → Списание ингр. | Согласованность без транзакций |
| Circuit Breaker | защита при сбоях платежного шлюза | Защита от каскадных ошибок |
| CQRS | кеширование меню | Защита от каскадных ошибок |
- API Gateway
Где: Отдельный сервис (api-gateway). Зачем:
Единая точка входа для клиентов
Балансировка нагрузки между инстансами сервисов
Возможность добавить аутентификацию/ограничение запросов (RateLimiter)
- Saga Pattern
Где: Обработка заказа → оплата → обновление статуса. Зачем:
Обеспечение согласованности данных без распределенных транзакций
Если оплата не прошла → отмена списания ингредиентов
Как реализовано:
Этапы:
Order Service создает заказ (статус CREATED)
Payment Service принимает оплату
При успехе → Order Service обновляет статус на PAID
При ошибке → Inventory Service возвращает ингредиенты
- CQRS (Read/Write Separation)
Где: Menu Service (кеширование меню). Зачем:
Запись: В БД (админ добавляет новые блюда)
Чтение: Из кеша (клиенты получают меню быстро)
Как реализовано:
ConcurrentHashMap + WeakReference для кеша
Обновление кеша при изменении данных
Пример:
- Circuit Breaker (через Resilience4j)
Где: Вызовы между сервисами (например, Order Service → Payment Service). Зачем:
Если платежный сервис упал → не "завалить" его повторными запросами
Fallback: Сообщить пользователю "Попробуйте оплатить позже"
Пример:
- Database per Service
Где: У каждого сервиса своя схема БД (см. модели данных). Зачем:
Независимое масштабирование
Сценарии работы
Сценарии работы приложения "Закусочная Красти Краб" после его запуска.
-
Запуск системы
Докер поднимает все сервисы:
menu-service (Меню) order-service (Заказы) inventory-service (Склад) payment-service (Касса) scheduler-service (Планировщик) api-gateway (Балансировщик + точка входа)Автоматически запускаются фоновые процессы:
Планировщик – отслеживает PAID заказы. Кеши в menu-service и inventory-service – загружают данные из БД при старте. Actuator – начинает собирать метрики (кол-во запросов, время ответа и т.д.). -
Примеры запросов и что они запускают
- Клиент смотрит меню (menu-service)
Запрос:
Что происходит:
Проверяется RateLimiter (если слишком много запросов – дефолтное меню).
Данные берутся из кеша (ConcurrentHashMap + WeakReference). Если кеш пуст – идёт запрос в БД.
Метрика в Actuator увеличивает счётчик запросов.
Ответ:
🔹 2. Клиент делает заказ (order-service)
Запрос:
Что происходит:
ReadWriteLock блокирует запись, пока заказ создаётся.
Склад (inventory-service) проверяет наличие ингредиентов через Semaphore (ограничение на параллельные списания).
Если ингредиентов хватает:
Игредиенты резервируются
Заказ сохраняется в БД со статусом PENDING
Генерируется payment-code
payment-code сохраняется в БД со статусом PENDING
payment-code возвращается в ответе клиенту
Ответ:
🔹 3. Оплата заказа (payment-service)
Запрос:
Что происходит:
Circuit Breaker защищает при сбоях платежного шлюза - пользователю "Попробуйте оплатить позже"
RateLimiter проверяет, не слишком ли много платежей в секунду.
Если оплата успешна:
order-service меняет статус на PAID.
Scheduler перестаёт считать этот заказ "неоплаченным"- переведет его в COOKING
Ответ:
- Искусственные сценарии (для демонстрации технологий)
🔸 Перегрузка API (RateLimiter)
Если быстро слать запросы: bash
for i in {1..100}; do curl -X GET http://localhost:8080/api/menu;
→ После 3 запросов/секунду начнёт присылать дефолтное меню.
🔸 Race condition (ReadWriteLock)
Если 2 пользователя одновременно попытаются изменить статус заказа:
Только один поток получит доступ на запись.
🔸 Off-Heap тест
При перезапуске order-service – логи заказов восстанавливаются из файла (MappedByteBuffer).
Модели данных
- Menu Service (Меню) Таблицы:
dish (Блюда)
dish_ingredient (Связь блюд и ингредиентов)
Пояснение:
dish – основное меню.
dish_ingredient – многие-ко-многим (показывает, какие ингредиенты входят в блюдо).
- Inventory Service (Склад)
Таблицы:
inventory_stock (Остатки ингредиентов)
Пояснение:
Связана с ingredient из Menu Service через ingredient_id.
quantity обновляется при списании (например, когда делают Krabby Patty, уменьшается количество "булочек" и "котлет").
- Order Service (Заказы)
Таблицы:
order (Заказы)
order_item (Позиции в заказе)
Пояснение:
order_item ссылается на dish из Menu Service, но дублирует цену (чтобы она не менялась после оплаты).
status обновляется через ReadWriteLock.
- Payment Service (Оплата)
Таблицы:
payment (Платежи)
Пояснение:
order_id – ссылка на заказ, но без FOREIGN KEY (чтобы не блокировать таблицы при высокой нагрузке).
- Логи заказов (Off-Heap Storage)
Формат файла orders.log:
Пояснение:
Данные хранятся в MappedByteBuffer для быстрого доступа.
При старте сервис загружает логи в off-heap память.