Почему вообще нужно «распиливать»?
- Командная независимость. Чем меньше команд трогают один и тот же код, тем быстрее идут релизы.
- Масштабируемость. У разных подсистем разные RPS-пики и SLA. Лучше разделить функционалость, чтобы было проще масштабировать.
- Надёжность. Отказ одного сервиса не валит всю систему, если границы корректно очерчены.
Антипример из практики: в одной финтех-компании маркетинговая рассылка была частью монолита. Когда команда маркетинга запустила A/B-эксперимент, Redis-кэш рассылки резко вырос и «съел» всю доступную RAM. Итог ‒ 15-минутный даунтайм платёжного API, хотя письма к платежам вообще не относились.
Шаг 1. Анализ зон ответственности
- Погружаемся в модули монолита. Помечаем, какая часть кода отвечает за какой бизнес-домен: «Профиль», «Платежи», «Лента», «Каталог»…
- Смотрим данные. Изучаем, какие таблицы читает/пишет каждый модуль. Если таблица используется повсеместно, она, скорее всего, «прозвенит» тревогу при миграции.
- Проверяем зависимости. Любой прямой импорт из «чужого» пакета фиксируем ‒ это потенциальная «склейка» доменов.
Шаг 2. Разделяем базы данных по шагам
| Ступени | Что делаем | Зачем | Инструменты |
|---|---|---|---|
| Шаг 1 | Schema Domains – группируем таблицы по доменам в отдельные схемы | Упрощаем миграцию и права доступа | schema_name.table в PostgreSQL |
| Шаг 2 | Query Watcher – следим за кросс-доменными JOIN-ами. Query Watcher —инструмент, который анализирует логи БД и определяет, какие запросы пересекают границы доменов. | Находим «утечки» границ | PgHero, pgbouncer-stats, самописный скрипт на Python |
| Шаг 3 | Application-Level JOINs | Убираем «сквозные» SQL-JOIN-ы ‒ собираем данные в коде через API | REST / gRPC + агрегирующий слой |
Шаг 3. Стартовая партия микросервисов
- Core-сервисы — аутентификация, авторизация, биллинг.
- Инфраструктурные сервисы — работа с шардингом, feature-flags, рассылки.
- Правило зависимости: монолит → сервис, но никогда наоборот. Так мы не создаём Distributed Monolith.
Шаг 4. Подчищаем хвосты
- После каждого «выноса» удаляем из монолита мёртвый код и устаревшие модели.
- Запускаем регрессионные тесты, чтобы убедиться, что монолит всё ещё собирается и деплоится.
- Обновляем документацию и диаграммы ‒ архитектура должна быть самодокументированной.