План перехода на микросервисную архитектуру¶
Цель: разделить монолитный
hotel_api_v2(135 роутеров) на независимо деплоимые сервисы. Каждый сервис можно пересобрать/перезапустить отдельно, не трогая весь стек.
1. Текущее состояние (моно)¶
┌─────────────────────────────────────────────────────────┐
│ hotel_api_v2 (FastAPI, 135 роутеров) │
│ • auth/sms/oauth • bookings/checkin/payments │
│ • hotels/rooms • tours/instructors/transfers │
│ • chat/support • restaurants/food │
│ • ai (chat/search/voice/widget) │
│ • resort/snow/webcams/weather │
│ • analytics/admin/dashboard │
│ • sos/calls/rtc • stories/forums/reviews │
│ • profiles/users/roles │
└─────────────────────────────────────────────────────────┘
↓ ↓ ↓
Supabase (DB+Auth+Storage) Redis ClickHouse MongoDB
Frontends: tourist-app (SPA), admin-web-v4 (SPA), r2026-preview.
Боль сейчас:
- любая правка одного роутера → пересборка всего образа (~3–5 мин)
- падение PostgREST/Kong → лежит весь API
- нельзя горизонтально масштабировать «горячие» эндпоинты (booking) отдельно от «холодных» (admin)
- катастрофа стартапа: 30+ сек ожидания health-чеков всех зависимостей при docker compose up
2. Целевая декомпозиция (8 сервисов)¶
| # | Сервис | Домены / роутеры | Порт | Зависимости |
|---|---|---|---|---|
| 1 | arkhyz-auth-svc | auth*, sms, users, roles, profiles, wallet, subscriptions |
9101 | Supabase (auth+rest), Redis (rate-limit, sms-codes) |
| 2 | arkhyz-booking-svc | bookings, booking_*, availability, price, attachments (booking docs) |
9102 | Supabase (rest), arkhyz-auth-svc (JWT verify) |
| 3 | arkhyz-catalog-svc (read-heavy, кэшируем агрессивно) | hotels, rooms, tours, restaurants, food, instructor*, transfers, ride, activities, events, expo, companies, references, geo, dadata, favorites, search, ai_search |
9103 | Supabase (rest), Redis (cache) |
| 4 | arkhyz-resort-svc (live данные курорта) | resort, snow, webcams, weather, ski, track, stories |
9104 | внешние (resort-arkhyz.ru, snow-forecast.com), Redis (cache) |
| 5 | arkhyz-chat-svc | chat*, support, ai_chat_widget, ai_support, ai_voice, comments, forums, reviews, review* |
9105 | Supabase (rest+realtime), Redis (pub/sub), MongoDB (история) |
| 6 | arkhyz-rtc-svc (звонки/WS) | calls, rtc, ws, sos, realtime |
9106 | Redis (signaling), TURN/coturn |
| 7 | arkhyz-analytics-svc | analytics, dashboard, admin*, tourist, widgets, widget, health, test, debug, api_testing |
9107 | ClickHouse, Supabase (rest) |
| 8 | arkhyz-platform-svc (системное) | files, attachments (общие), notifications, settings, physical, webhooks, public, supabase, functions, миграции |
9108 | Supabase (всё), MinIO/S3 |
Frontends остаются как есть (tourist-app + admin-web-v4), но nginx будет роутить /api/* на нужный микросервис через path-prefix.
┌──── auth-svc :9101 /api/v1/auth/**
│ users/** roles/**
nginx (tourist-app) ├──── booking-svc :9102 /api/v1/bookings/**
/api/v1/* ────────┼──── catalog-svc :9103 /api/v1/hotels/** tours/**
├──── resort-svc :9104 /api/v1/resort/** webcams/**
├──── chat-svc :9105 /api/v1/chat/** support/**
├──── rtc-svc :9106 /api/v1/calls/** rtc/**
├──── analytics-svc :9107 /api/v1/analytics/** admin/**
└──── platform-svc :9108 /api/v1/files/** notifications/**
3. Общий слой (shared library)¶
Создаём пакет arkhyz_shared (ставится в каждый сервис):
- arkhyz_shared.auth — JWT декодер, dependency current_user()
- arkhyz_shared.db — Supabase/PostgREST клиент с retry
- arkhyz_shared.cache — обёртка над Redis
- arkhyz_shared.events — pub/sub в Redis для inter-service событий
- arkhyz_shared.config — общий pydantic-settings (env)
- arkhyz_shared.logging — структурный JSON-лог
- arkhyz_shared.middleware — CORS, request-id, timing
Хранится в packages/arkhyz-shared/ в этом же репо, ставится в Dockerfile каждого сервиса через pip install -e ../packages/arkhyz-shared.
4. Inter-service коммуникация¶
| Случай | Способ | Пример |
|---|---|---|
| Синхронный вызов (booking → catalog за описанием отеля) | HTTP REST | GET http://catalog-svc:9103/internal/hotels/{id} |
| JWT verify | локально через arkhyz_shared.auth (без сетевых хопов) |
— |
| Асинхронные события (booking создан → notif в chat) | Redis Streams | XADD bookings.created |
| Длинные задачи (генерация PDF чека) | RQ / Dramatiq на Redis | отдельный воркер arkhyz-worker |
Никаких Kong между микросервисами — внутренний трафик идёт по docker network напрямую. Kong/Caddy остаются только на edge для внешнего HTTPS.
5. Структура репо после рефакторинга¶
arkhyz-admin-main/
├── services/
│ ├── auth-svc/
│ │ ├── app/
│ │ ├── Dockerfile
│ │ └── requirements.txt
│ ├── booking-svc/
│ ├── catalog-svc/
│ ├── resort-svc/
│ ├── chat-svc/
│ ├── rtc-svc/
│ ├── analytics-svc/
│ └── platform-svc/
├── packages/
│ └── arkhyz-shared/ # общий код
├── frontends/
│ ├── tourist-app/
│ └── admin-web-v4/
├── infra/
│ ├── compose/
│ │ ├── docker-compose.core.yml # postgres, redis, kong, caddy
│ │ ├── docker-compose.services.yml # все 8 микросервисов
│ │ ├── docker-compose.frontends.yml # tourist+admin
│ │ └── docker-compose.observability.yml # prometheus, grafana, loki
│ ├── nginx/
│ │ └── api-router.conf # path-prefix роутинг
│ └── caddy/Caddyfile
└── api-admin/ # legacy моно — удаляется в конце фазы 5
6. Этапы (5 фаз)¶
Фаза 0 — Подготовка (1–2 дня)¶
- [ ] Завести
packages/arkhyz-sharedсо скелетами модулей - [ ] Поднять
services/директорию - [ ] Завести
docker-compose.core.yml(то, что общее: db/redis/kong/caddy) - [ ] CI: настроить independent build per service (path-trigger в GitHub Actions)
Фаза 1 — Извлечение arkhyz-resort-svc (пилот, 1 день)¶
Самый изолированный домен — не трогает БД, только внешние скрейперы.
- [ ] Скопировать routers/resort_status.py, webcams.py, weather.py в services/resort-svc
- [ ] Минимальный FastAPI с /health
- [ ] Dockerfile + добавить в compose
- [ ] Nginx: /api/v1/resort/* → resort-svc:9104
- [ ] Удалить эти роутеры из hotel_api_v2
- [ ] Smoke test → деплой → откат если что
Фаза 2 — arkhyz-auth-svc (2 дня)¶
- [ ] Перенести
auth*,sms,users,roles - [ ] Сгенерировать internal-only HMAC для service-to-service вызовов
- [ ] Frontend
tourist-appиadmin-web-v4уже бьют в/api/v1/auth/*— поменяет только nginx - [ ] Разобрать дубликаты (
auth.py,auth_clean.py,auth_fixed.py,auth_postgres.py) → выбрать каноничный
Фаза 3 — arkhyz-catalog-svc + arkhyz-booking-svc (3 дня)¶
- [ ] Самые большие домены — выносим параллельно
- [ ] booking-svc вызывает catalog-svc через internal HTTP за описаниями
- [ ] Внедрить Redis-кэш в catalog (хеш-ключ по slug отеля)
Фаза 4 — chat-svc, rtc-svc, analytics-svc, platform-svc (5 дней)¶
- [ ] Поэтапно, по одному в день
- [ ] rtc-svc требует особого внимания (WebSocket, sticky sessions)
Фаза 5 — Удаление монолита (1 день)¶
- [ ] Убедиться что
hotel_api_v2не имеет активных роутеров - [ ] Удалить контейнер из compose
- [ ] Архивировать
api-admin/→legacy/api-admin-monolith.tar.gz
7. CI/CD (GitHub Actions)¶
# .github/workflows/services.yml
on:
push:
paths:
- 'services/auth-svc/**'
- 'services/booking-svc/**'
# ... и т.д.
jobs:
detect:
outputs: { changed: ... }
# filter по path → выдаёт список измененных сервисов
build-deploy:
needs: detect
strategy:
matrix: { svc: ${{ fromJSON(needs.detect.outputs.changed) }} }
steps:
- docker build services/${{ matrix.svc }}
- docker push registry/arkhyz-${{ matrix.svc }}
- ssh prod "docker compose pull ${{ matrix.svc }} && docker compose up -d --no-deps ${{ matrix.svc }}"
Эффект: правка resort-svc → пересобирается только resort-svc (~30 сек), остальные 7 сервисов не трогаются.
8. Observability¶
Раз делаем разделение — сразу же:
- Prometheus — метрики из каждого сервиса (/metrics)
- Loki — структурный JSON-лог
- Grafana — дашборды per-service
- Sentry — единая точка ошибок (project per service)
- Health-чеки: каждый сервис отдаёт /health с deps статусом
9. Риски и mitigation¶
| Риск | Mitigation |
|---|---|
| Кросс-сервисные транзакции (booking + payment) | Saga pattern или outbox-таблица в Postgres |
Дубликаты в схеме БД (auth-svc и user-svc обе пишут в users) |
Один сервис — owner таблицы; остальные читают через REST |
| Frontend ломается при path-prefix миграции | Сначала добавляем новые маршруты в nginx, удаляем старые после деплоя |
| JWT secret rotation | Хранить в общем env-файле, перезапуск только auth-svc |
| Локальный dev стал тяжелее (8 контейнеров вместо 1) | docker-compose.minimal.yml для разработки конкретного сервиса |
10. Что нужно от тебя сейчас¶
Подтверди или скорректируй:
1. Декомпозицию по 8 сервисам (раздел 2) — ок или хочешь по-другому?
2. Порядок фаз — стартуем с resort-svc как пилот?
3. Inter-service — REST или сразу gRPC?
4. Shared library в моно-репо или отдельный пакет в pypi/git?
5. CI/CD — готов настраивать GitHub Actions, или у тебя другой раннер?
После твоего OK я создам скелет packages/arkhyz-shared и services/resort-svc (пилот), подниму его рядом с монолитом и переключу /api/v1/resort/* на новый сервис — это можно сделать за один заход без даунтайма.