Перейти к содержанию

План перехода на микросервисную архитектуру

Цель: разделить монолитный 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/* на новый сервис — это можно сделать за один заход без даунтайма.