new docs added
This commit is contained in:
@@ -0,0 +1,295 @@
|
||||
<img src="https://r2cdn.perplexity.ai/pplx-full-logo-primary-dark%402x.png" style="height:64px;margin-right:32px"/>
|
||||
|
||||
# Я делаю программу для записи в автосервис. Программа (серверная часть) позволяет записаться на ремонт и купить запчасти во внутреннем магазине. Какие микро сервисы у меня должны быть реализованы? Я планирую среднюю-большую нагрузку, пропускная способность должны быть большой. Если тебе нужно больше подробностей про саму программу - так и скажи, я добавлю.
|
||||
|
||||
Да — для такой системы микросервисы подходят, но **не стоит** дробить всё слишком рано. Для записи в автосервис + внутреннего магазина я бы закладывал 8–12 основных сервисов, а не 20+, потому что booking и inventory создают самые неприятные распределённые сценарии, и их лучше выделять осознанно, а не “по таблице = сервис”.[^1_1][^1_2]
|
||||
|
||||
## Базовые сервисы
|
||||
|
||||
Ниже — разумный стартовый набор для средней/большой нагрузки:
|
||||
|
||||
|
||||
| Сервис | Что делает | Почему выделять |
|
||||
| :-- | :-- | :-- |
|
||||
| Auth / IAM | логин, роли, JWT/OAuth2, сотрудники/клиенты | безопасность и отдельный lifecycle [^1_1] |
|
||||
| Customer Service | профили клиентов, контакты, история машин | независимый домен, много чтения [^1_1] |
|
||||
| Vehicle Service | автомобили клиента: VIN, госномер, марка, пробег | нужен и для записи, и для истории ремонта |
|
||||
| Booking Service | создание/перенос/отмена записи | это центральный high-load домен для записи [^1_2] |
|
||||
| Workshop Capacity Service | расписание боксов, мастеров, длительности работ, слоты | лучше отделить от “просто заявки”, чтобы масштабировать расчёт доступности отдельно [^1_3][^1_4] |
|
||||
| Order Service | заказ на услуги и/или запчасти, статус заказа | связывает бизнес-процесс целиком [^1_5][^1_6] |
|
||||
| Catalog Service | каталог запчастей, категории, бренды, совместимость | много чтения, хорошо кэшируется [^1_5] |
|
||||
| Inventory Service | остатки, резервы, списание, приход | отдельная критичная зона консистентности [^1_6][^1_1] |
|
||||
| Pricing Service | расчёт цены работ, запчастей, скидок, промокодов | удобно менять правила без перелома остального |
|
||||
| Payment Service | оплата, возвраты, холдирование | финансовый контур лучше изолировать [^1_7] |
|
||||
| Notification Service | email/SMS/push/Telegram-уведомления | типичный отдельный асинхронный сервис [^1_7] |
|
||||
| Admin/Backoffice Service | операции менеджера, статусы, ручные корректировки | UI/операционный контур часто меняется быстрее core-логики |
|
||||
|
||||
Если магазин внутри автосервиса небольшой, то на первом этапе Catalog + Inventory + Pricing можно временно держать ближе друг к другу, но Booking и Capacity я бы всё равно разделял отдельно.[^1_4]
|
||||
|
||||
## Что критично для high-load
|
||||
|
||||
Для большой пропускной способности у тебя основная проблема будет не в “много сервисов”, а в горячих сценариях: поиск свободного слота, создание записи, резервирование запчастей и смена статусов заказов. Для таких систем обычно рекомендуют event-driven взаимодействие, Saga для распределённых бизнес-процессов и Transactional Outbox, чтобы не терять события между БД и брокером.[^1_6][^1_2][^1_8]
|
||||
|
||||
Я бы закладывал такие инфраструктурные компоненты:
|
||||
|
||||
- API Gateway — единая точка входа, rate limiting, auth, routing.
|
||||
- Message broker — Kafka или RabbitMQ; для бизнес-событий и развязки нагрузки.[^1_8][^1_7]
|
||||
- Redis — кэш каталога, доступных слотов, сессий, rate limiting.[^1_9]
|
||||
- Service discovery / config / observability — метрики, трассировка, централизованные логи; без этого microservices быстро становятся неуправляемыми.[^1_9][^1_4]
|
||||
|
||||
Особенно важны resilience-паттерны: circuit breaker, retry с backoff, bulkhead, queue-based leveling и fallback на чтение из кэша там, где допустима eventual consistency. Это напрямую помогает переживать всплески нагрузки без деградации всего контура.[^1_9]
|
||||
|
||||
## Границы доменов
|
||||
|
||||
Я бы разложил твой бизнес-процесс так:
|
||||
|
||||
1. Клиент ищет слот: этим занимается Booking + Capacity.
|
||||
2. Клиент выбирает услуги и запчасти: Catalog + Pricing.
|
||||
3. Система резервирует слот и запчасти: Booking/Order + Inventory через Saga.[^1_2][^1_6]
|
||||
4. После подтверждения создаётся заказ-наряд: Order Service.
|
||||
5. Уведомления и оплата идут асинхронно через Notification и Payment.[^1_7]
|
||||
|
||||
Ключевая идея: **запись в сервис** и **резерв товара** не надо склеивать в одну сильную ACID-транзакцию между сервисами. Для этого как раз и используют Saga/компенсации: если резерв запчастей не удался, запись откатывается; если слот заняли, но платёж не прошёл, освобождается бронь.[^1_6][^1_2]
|
||||
|
||||
## Практичная стартовая схема
|
||||
|
||||
Если хочешь не переусложнить MVP, но оставить путь к росту, я бы советовал такой старт:
|
||||
|
||||
- Auth Service
|
||||
- Customer/Vehicle Service
|
||||
- Booking Service
|
||||
- Capacity Service
|
||||
- Order Service
|
||||
- Catalog Service
|
||||
- Inventory Service
|
||||
- Payment Service
|
||||
- Notification Service
|
||||
- API Gateway
|
||||
|
||||
Это уже хорошая промышленная декомпозиция под твою задачу и под твой стек Java/Kotlin + PostgreSQL + Redis + Docker. С твоим опытом по PostgreSQL и контейнеризации тебе особенно важно сразу продумать ownership данных: у каждого сервиса своя БД/схема, никакого общего “одного PostgreSQL с прямыми JOIN между сервисами” на уровне бизнес-логики.[^1_1]
|
||||
|
||||
## Что ещё нужно уточнить
|
||||
|
||||
Чтобы сказать уже **точную** схему, мне не хватает предметных деталей по домену. Ответь коротко на 7 пунктов:
|
||||
|
||||
- Запись идёт на конкретный бокс, мастера или просто на время?
|
||||
- Запчасти покупаются отдельно от записи или только внутри заказа на ремонт?
|
||||
- Нужна ли онлайн-оплата, предоплата, возвраты?
|
||||
- Есть ли несколько филиалов/СТО?
|
||||
- Нужен ли складской учёт по филиалам?
|
||||
- Нужны ли статусы ремонта в реальном времени для клиента?
|
||||
- Это B2C-сервис для клиентов, внутренний CRM для сотрудников, или оба режима?
|
||||
|
||||
После этого я смогу предложить тебе:
|
||||
|
||||
1. точный список микросервисов,
|
||||
2. границы БД для каждого,
|
||||
3. какие сервисы синхронные, а какие через broker,
|
||||
4. и пример production-архитектуры под high-load на Kotlin/Spring/Ktor.
|
||||
<span style="display:none">[^1_10][^1_11][^1_12][^1_13][^1_14][^1_15]</span>
|
||||
|
||||
<div align="center">⁂</div>
|
||||
|
||||
[^1_1]: https://microservices.io/patterns/microservices.html
|
||||
|
||||
[^1_2]: https://dev.to/airtruffle/event-driven-microservices-for-booking-systems-managing-distributed-transactions-at-scale-4pai
|
||||
|
||||
[^1_3]: https://medium.com/@abhirbkulkarni/designing-scalable-booking-system-with-microservice-architecture-26a4a5b7337e
|
||||
|
||||
[^1_4]: https://gridsandguides.com/case-studies/modernization
|
||||
|
||||
[^1_5]: https://ijsdr.org/papers/IJSDR2501128.pdf
|
||||
|
||||
[^1_6]: https://dev.to/haydencordeiro/ensuring-data-consistency-across-microservices-herding-cats-with-saga-outbox-3mhe
|
||||
|
||||
[^1_7]: https://github.com/vincenzocorso/car-sharing
|
||||
|
||||
[^1_8]: https://medium.com/@mahmoudsallam2111/inbox-outbox-patterns-and-saga-pattern-in-microservices-df65b66bf41d
|
||||
|
||||
[^1_9]: https://medium.com/techno101/resiliency-patterns-in-microservice-architecture-e776977a1283
|
||||
|
||||
[^1_10]: https://www.youtube.com/watch?v=hmUzeYk2cDc
|
||||
|
||||
[^1_11]: https://publica-rest.fraunhofer.de/server/api/core/bitstreams/2bc3d5e5-17ca-4514-95a5-17801cc794d9/content
|
||||
|
||||
[^1_12]: https://medium.com/@ruchiraprasad/handling-distributed-transactions-in-microservices-with-saga-orchestration-vs-801840016848
|
||||
|
||||
[^1_13]: https://www.scribd.com/document/934320220/Introduction-to-Microservices
|
||||
|
||||
[^1_14]: https://theamericanjournals.com/index.php/tajet/article/download/6156/5690/7602
|
||||
|
||||
[^1_15]: https://www.techinterview.org/post/3233474197/system-design-microservices-data-patterns-saga-outbox-pattern-event-sourcing-cqrs-dual-write-problem-transactional-messaging/
|
||||
|
||||
|
||||
---
|
||||
|
||||
# 1. Запись идет на время бокса. Если есть свободный мастер, с квалификацией на требуемую услугу, бокс и время.
|
||||
|
||||
2. Запчасти на запись автоматически добавляются к записи, но пользователь может их изменить (либо убрать все, если со своими запчастями). Также может просто купить запчасти, без записи - один в один как в интернет магазине, только с самовывозом.
|
||||
3. Да, онлайн оплата, предоплата, возвраты - это всё обязательно.
|
||||
4. Нет, одно СТО.
|
||||
5. Филиалов нет, складской учет только для одного филиала.
|
||||
6. Да, было бы неплохо.
|
||||
7. Оба режима.
|
||||
|
||||
Под твои уточнения уже можно собрать довольно точную схему: ядро должно крутиться вокруг **Booking/Capacity**, **Order**, **Inventory**, **Payment** и **Realtime Status**, потому что именно здесь у тебя и высокая нагрузка, и риск гонок, и самые неприятные rollback-сценарии. Для твоего кейса я бы делал не “микросервис на каждую сущность”, а доменно-ориентированный набор из 10–12 сервисов с жёсткими границами данных и асинхронной оркестрацией записи/резерва/оплаты.[^2_1][^2_2]
|
||||
|
||||
## Рекомендуемый набор
|
||||
|
||||
Я бы предложил такой состав сервисов:
|
||||
|
||||
|
||||
| Сервис | Основная ответственность | Комментарий |
|
||||
| :-- | :-- | :-- |
|
||||
| API Gateway / BFF | входная точка для web/admin/mobile, auth propagation, rate limit | нужен почти обязательно при большом трафике |
|
||||
| Auth / IAM | пользователи, роли, сотрудники, клиенты, токены, права | общий security-контур [^2_3] |
|
||||
| Customer Service | клиент, контакты, история обращений | B2C и backoffice оба его используют |
|
||||
| Vehicle Service | машины клиента, VIN, номер, модель, пробег | лучше отдельно от клиента, потому что логика самостоятельная |
|
||||
| Service Catalog | виды работ, длительность, требования к квалификации, базовые цены | это не каталог запчастей, а каталог услуг |
|
||||
| Staff \& Qualification Service | мастера, графики, компетенции, доступность | у тебя запись зависит от квалификации мастера, это отдельный домен |
|
||||
| Capacity / Slot Service | расчёт и удержание слотов по времени бокса с проверкой “есть ли свободный мастер нужной квалификации” | один из самых критичных сервисов [^2_1][^2_4] |
|
||||
| Booking Service | создание/отмена/перенос записи, lifecycle брони | orchestration вокруг слота и заказа [^2_2] |
|
||||
| Parts Catalog Service | каталог запчастей, совместимость, карточки товара, поиск | ecommerce-like read-heavy сервис [^2_5] |
|
||||
| Inventory Service | остатки, резервы, списание, возврат на склад | отдельно из-за консистентности и гонок [^2_6] |
|
||||
| Order Service | заказ целиком: услуги + запчасти + суммы + статусы | объединяет сервисную запись и магазинный сценарий [^2_5][^2_7] |
|
||||
| Payment Service | предоплата, полная оплата, возвраты, webhook-обработка, ledger | финансовый контур обязательно отдельно [^2_8] |
|
||||
| Notification Service | email/SMS/push/Telegram, напоминания, чеки, уведомления | асинхронный outbound-контур [^2_9] |
|
||||
| Realtime Status Service | WebSocket/SSE подписки на изменения статуса заказа/ремонта | для live-статусов клиенту и админам [^2_10][^2_9] |
|
||||
|
||||
Если хочешь чуть упростить первую версию, можно временно слить Customer + Vehicle, а Service Catalog + Parts Catalog оставить раздельно, потому что это реально разные бизнес-модели.[^2_3][^2_5]
|
||||
|
||||
## Как разложить домены
|
||||
|
||||
У тебя по сути есть три главных бизнес-потока:
|
||||
|
||||
1. Запись на ремонт: подбор слота, проверка мастера нужной квалификации, создание брони, добавление услуг и дефолтных запчастей.[^2_4][^2_1]
|
||||
2. Заказ запчастей без записи: обычный ecommerce flow с самовывозом, резервом и оплатой.[^2_5]
|
||||
3. Постобработка: изменение статусов ремонта, допродажа/удаление запчастей, возвраты, уведомления, live-обновления.[^2_10][^2_9]
|
||||
|
||||
Из-за этого я бы не делал отдельный “Repair Service” как ядро, а держал `Order Service` как агрегат бизнес-заказа, у которого есть тип:
|
||||
|
||||
- `SERVICE_ORDER`
|
||||
- `PARTS_ORDER`
|
||||
- `HYBRID_ORDER`
|
||||
|
||||
Это сильно упростит аналитику, оплату, возвраты и статус-машину, потому что payment и notification будут работать с одним типом агрегата, а не с двумя параллельными мирами.[^2_7][^2_5]
|
||||
|
||||
## Ключевые сценарии
|
||||
|
||||
### Запись на ремонт
|
||||
|
||||
Нормальный flow будет таким:
|
||||
|
||||
1. Клиент выбирает машину, услугу и желаемое время.
|
||||
2. `Capacity Service` проверяет: свободен ли бокс, есть ли мастер с нужной квалификацией, не нарушает ли это ограничения по времени.[^2_1][^2_4]
|
||||
3. `Booking Service` создаёт временный hold слота на короткий TTL.
|
||||
4. `Order Service` собирает заказ: услуги + автоматически подобранные запчасти.
|
||||
5. `Inventory Service` резервирует нужные запчасти, если клиент не отметил “со своими”.[^2_6]
|
||||
6. `Payment Service` создаёт intent на предоплату.
|
||||
7. После подтверждения оплаты бронь становится подтверждённой, заказ активируется, уведомления уходят клиенту.[^2_8][^2_2]
|
||||
|
||||
Это должен быть не набор синхронных REST-вызовов “в лоб”, а Saga-процесс с компенсациями: не удалось зарезервировать запчасти — освобождаем hold слота; не прошла предоплата — отменяем бронь; истёк TTL — возвращаем всё назад.[^2_2][^2_8][^2_6]
|
||||
|
||||
### Магазин без записи
|
||||
|
||||
Этот сценарий проще:
|
||||
|
||||
1. Клиент добавляет запчасти в корзину.
|
||||
2. `Order Service` создаёт `PARTS_ORDER`.
|
||||
3. `Inventory Service` делает резерв под самовывоз.
|
||||
4. `Payment Service` проводит оплату.
|
||||
5. После оплаты заказ получает статус “готовится к выдаче”, а `Realtime Status` и `Notification Service` пушат обновления.[^2_10][^2_7][^2_5]
|
||||
|
||||
Тут главное — не смешивать складской резерв “для записи на ремонт” и “для самовывоза” без явного типа резерва. Иначе потом будет боль с возвратами, доукомплектацией и ручными правками менеджера.[^2_6]
|
||||
|
||||
## Что особенно важно для high-load
|
||||
|
||||
У тебя горячие точки будут такие:
|
||||
|
||||
- поиск доступных слотов;
|
||||
- массовое чтение каталога услуг и запчастей;
|
||||
- резерв остатков;
|
||||
- обработка webhook’ов платежки;
|
||||
- real-time обновления статусов для клиентов и менеджеров.
|
||||
|
||||
Поэтому я бы закладывал такую технику:
|
||||
|
||||
- Redis для кэша слотов, каталога и короткоживущих hold-объектов; при атомарных резервах можно использовать Lua/atomic ops для борьбы с гонками.[^2_8]
|
||||
- Kafka или RabbitMQ для событий `booking-held`, `inventory-reserved`, `payment-succeeded`, `booking-confirmed`, `repair-status-changed`.[^2_11][^2_7]
|
||||
- Transactional Outbox + идемпотентные consumers, потому что у тебя есть и брокер, и платежные webhook’и, и критичные изменения статусов.[^2_11][^2_6]
|
||||
- WebSocket или SSE для live-статусов; при росте нагрузки можно вынести realtime delivery в отдельный сервис с Redis Pub/Sub или брокером под fan-out.[^2_12][^2_9][^2_10]
|
||||
|
||||
Для поиска слотов я бы вообще советовал не рассчитывать всё on-demand из десятка таблиц на каждый запрос. Лучше иметь специализированную модель доступности в `Capacity Service`, которую можно быстро пересчитывать при изменении расписания, занятости мастера или отмене записи. Это стандартная мысль для booking-систем: availability — отдельный hot path, а не побочный SQL-join.[^2_4][^2_1]
|
||||
|
||||
## Где нельзя ошибиться
|
||||
|
||||
Есть несколько мест, где архитектура чаще всего ломается:
|
||||
|
||||
- Общая база на все сервисы. Это убьёт автономность и быстро превратит микросервисы в “распиленный монолит”.[^2_3]
|
||||
- Синхронная цепочка `Booking -> Inventory -> Payment -> Notification` без брокера и компенсаций. Под нагрузкой это начнёт валиться каскадом.[^2_13][^2_2]
|
||||
- Отсутствие идемпотентности у webhook’ов оплаты и команд на резерв/возврат. Платёжные провайдеры почти всегда могут прислать повтор.[^2_8]
|
||||
- Попытка держать “абсолютно строгую” консистентность между всеми сервисами одной транзакцией. Для твоего домена нужна управляемая eventual consistency через Saga.[^2_2][^2_6]
|
||||
|
||||
|
||||
## Практичная production-схема
|
||||
|
||||
Для твоего проекта я бы рекомендовал такой минимально-зрелый production baseline:
|
||||
|
||||
- Kotlin/Spring Boot для core-сервисов, где много enterprise-интеграции и security.
|
||||
- Ktor можно оставить для узких high-throughput edge/realtime компонентов, если тебе так удобнее по стеку.
|
||||
- PostgreSQL на сервис, отдельная БД или хотя бы отдельная schema ownership-only на старте.
|
||||
- Redis для cache/holds/rate limiting.
|
||||
- Kafka для доменных событий; RabbitMQ тоже возможен, но если планируешь много аналитики, ретраев и переигрывания событий, Kafka обычно удобнее.[^2_7][^2_11]
|
||||
- API Gateway + Keycloak/аналог для auth.
|
||||
- WebSocket gateway для live-статусов ремонта и заказов.[^2_9][^2_10]
|
||||
- OpenTelemetry, Prometheus, Grafana, centralized logs — без этого такой парк сервисов поддерживать тяжело.[^2_13]
|
||||
|
||||
Я бы ещё разделил клиентские и внутренние API на уровне BFF или gateway policies: B2C-клиенту не нужны те же endpoint’ы и payload’ы, что оператору сервиса. У тебя “оба режима”, и это обычно быстро начинает расходиться по требованиям и SLA.
|
||||
|
||||
Могу следующим сообщением нарисовать тебе уже **конкретную схему взаимодействия сервисов**: кто кому звонит синхронно, какие события летят через broker, какие БД у каждого сервиса и как выглядит Saga для “запись + резерв запчастей + предоплата”.
|
||||
<span style="display:none">[^2_14][^2_15][^2_16][^2_17][^2_18][^2_19][^2_20][^2_21]</span>
|
||||
|
||||
<div align="center">⁂</div>
|
||||
|
||||
[^2_1]: https://hackernoon.com/building-appointa-part-1-how-to-design-booking-software-that-doesnt-lie-about-availability
|
||||
|
||||
[^2_2]: https://dev.to/airtruffle/event-driven-microservices-for-booking-systems-managing-distributed-transactions-at-scale-4pai
|
||||
|
||||
[^2_3]: https://microservices.io/patterns/microservices.html
|
||||
|
||||
[^2_4]: https://codelit.io/blog/hotel-booking-system-design
|
||||
|
||||
[^2_5]: https://ijsdr.org/papers/IJSDR2501128.pdf
|
||||
|
||||
[^2_6]: https://dev.to/haydencordeiro/ensuring-data-consistency-across-microservices-herding-cats-with-saga-outbox-3mhe
|
||||
|
||||
[^2_7]: https://medium.com/@ogounaya/real-time-order-processing-in-e-commerce-with-kafka-react-and-node-js-b20ec816cc3c
|
||||
|
||||
[^2_8]: https://www.linkedin.com/posts/sahil-miyani-56995315a_systemdesign-softwareengineering-backend-activity-7420377830083108864-uPkP
|
||||
|
||||
[^2_9]: https://github.com/18-RAJAT/Real-Time-Notifications-Springboot-Websocket
|
||||
|
||||
[^2_10]: https://medium.com/@myjob.rajesh/real-time-order-tracking-system-architecture-70a98e660906
|
||||
|
||||
[^2_11]: https://medium.com/@mahmoudsallam2111/inbox-outbox-patterns-and-saga-pattern-in-microservices-df65b66bf41d
|
||||
|
||||
[^2_12]: https://www.linkedin.com/posts/prem-s-bharti_how-to-build-a-real-time-order-tracker-using-activity-7333047115893415936-qH75
|
||||
|
||||
[^2_13]: https://medium.com/techno101/resiliency-patterns-in-microservice-architecture-e776977a1283
|
||||
|
||||
[^2_14]: https://medium.com/@rahul.lnmiit/designing-a-scalable-hotel-booking-system-an-in-depth-technical-guide-6e9c6e7340d9
|
||||
|
||||
[^2_15]: https://www.youtube.com/watch?v=4Td1ViGU5LA
|
||||
|
||||
[^2_16]: https://www.scribd.com/document/854283874/Order-Status-Feed-WS-API-Doc-V1-1-1
|
||||
|
||||
[^2_17]: https://www.linkedin.com/posts/sai-kiran-m-b719992b3_springboot-java-microservices-activity-7360807508849897473-D_y8
|
||||
|
||||
[^2_18]: https://arjonline.org/papers/arjcsit/v8-i1/5.pdf
|
||||
|
||||
[^2_19]: https://github.com/swaminathanvetri/reactor-copilot-handson-series-demo/issues/2
|
||||
|
||||
[^2_20]: https://medium.com/@jamala.zawia/designing-a-layered-websocket-architecture-for-scalable-real-time-systems-1ba3591e3ffb
|
||||
|
||||
[^2_21]: https://www.youtube.com/watch?v=2WYjtfRyHzQ
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
The fuck do we need:
|
||||
|
||||
Other things:
|
||||
|
||||
1. API gateway
|
||||
1. Identity provider (separete service btw)
|
||||
2. Service registry & discovery (also separate)
|
||||
2. Notifications
|
||||
3. Payment
|
||||
4. User profile
|
||||
5. Vehicle service
|
||||
6. Admin service
|
||||
7. Real-time status service (web-socket)
|
||||
8. Order service
|
||||
|
||||
Shop:
|
||||
|
||||
1. Shoping cart
|
||||
2. Goods (Catalog)
|
||||
3. Inventory
|
||||
|
||||
Service:
|
||||
|
||||
1. Appoitment (booking)
|
||||
2. Workshop (Capacity, etc.)
|
||||
3. Service catalog
|
||||
4. Staff service
|
||||
Reference in New Issue
Block a user