Для большинства систем нашего масштаба начинать стоит с модульного монолита: одно приложение, одна база, внутри чёткие модули с запретом на обращение к чужим таблицам. Микросервисы нужны, когда отдельные части должны развиваться, масштабироваться или падать независимо, и когда есть люди, которые будут всё это эксплуатировать.
Ошибка чаще стоит дороже в одну сторону: разрезанная раньше времени система получает все сложности распределённости и ни одной из выгод. Услуга по проектированию описана на странице «Микросервисы и высоконагруженные системы», здесь только способ выбора.
Что мы называем монолитом и микросервисами
Монолит — одно развёртываемое приложение: все функции собираются вместе и запускаются одним процессом (или несколькими копиями одного процесса). Это не обязательно «спагетти»: хорошо устроенный монолит делится на модули.
Микросервисы — набор отдельных приложений, каждое со своей базой, своим развёртыванием и своим интерфейсом. Они общаются по сети: запросами или событиями. Между двумя крайностями есть промежуточные варианты, и именно они подходят чаще всего.
| Вариант | Как устроено | Где граница модулей | Как выпускается |
|---|---|---|---|
| Классический монолит | Один код, одна база, модули связаны напрямую | Условная, держится на договорённостях | Всё вместе, одним релизом |
| Модульный монолит | Один код и одна база, но у модулей явные интерфейсы и свои таблицы | Проверяется в сборке: чужие таблицы напрямую читать нельзя | Всё вместе, но тесты показывают, что именно изменилось |
| Сервисы по границам | Несколько приложений, у выделенных частей своя база | Сетевой контракт с версиями | Раздельно для выделенных частей, остальное остаётся вместе |
| Много мелких сервисов | Десятки приложений, у каждого своя команда или владелец | Сетевой контракт и платформа для всех сервисов | Каждый сервис сам по себе |
Дальше сравниваем в основном второй и третий варианты: между ними реально выбирают для большинства бизнес-систем.
Что платите за распределённость
Микросервисы переносят сложность из кода в сеть и в эксплуатацию. Эта сложность не исчезает, а меняет форму. Перед выбором прочитайте список расходов, не только список выгод.
| Что меняется | В монолите | В сервисах | Что нужно, чтобы справиться |
|---|---|---|---|
| Вызов между частями | Вызов функции: быстрый и либо удался, либо нет | Запрос по сети: может быть медленным, потеряться или дойти дважды | Тайм-ауты, повторы с паузой, защита от дублей |
| Согласованность данных | Одна транзакция в одной базе | Данные разнесены, единой транзакции нет | Событийная модель, компенсирующие действия, «исходящий ящик» |
| Отладка | Одна трассировка стека | Запрос проходит через несколько сервисов | Сквозной идентификатор запроса, журналы и трассировка в одном месте |
| Тестирование | Запустил приложение и проверил | Нужны проверки контрактов и стенд со всеми сервисами | Тесты на контрактах между сервисами, тестовое окружение |
| Развёртывание | Одно приложение | Каждый сервис со своей сборкой, версией и откатом | Автоматическая сборка и выкатка, мониторинг каждого сервиса |
| Изменение интерфейса | Меняете вызов и все места его использования | Старые потребители ещё работают на прежней версии | Версии контрактов, период совместимости |
Все шесть расходов закрываются известными приёмами, но каждый приём стоит времени команды и поддерживается постоянно. Небольшая команда тратит на это заметную долю своей работы, которую иначе потратила бы на продукт.
Когда достаточно монолита
Хватает монолита, особенно модульного, если выполняется большинство признаков из списка:
- Одна команда. Люди знают весь код и договариваются голосом. Независимые релизы им не нужны.
- Нагрузка предсказуема. Её можно закрыть копиями приложения за балансировщиком и настройкой базы.
- Тормозит конкретное место. Проблема локализована: запрос без индекса, тяжёлый отчёт, медленная внешняя система. Это лечится без смены архитектуры.
- Данные тесно связаны. Операции должны быть атомарными: списали остаток и создали заказ или не сделали ничего.
- Нет людей для эксплуатации. Нет того, кто настроит мониторинг, трассировку и автоматические релизы для нескольких сервисов.
Если проблема в том, что код разрастается и модули срастаются, лекарство — порядок внутри монолита: явные интерфейсы между модулями, запрет на обход, отдельные схемы данных. Это дешевле разделения и подготавливает его, если оно понадобится. Что в тексте о высокой нагрузке можно сделать без сервисов, перечислено на странице услуги.
Признаки того, что пора выделять сервис
Сервис оправдан, когда у части системы есть причина жить отдельно. Причины бывают четыре, и достаточно одной сильной:
| Причина | Как выглядит | Что выделяем | Что проверить до выделения |
|---|---|---|---|
| Разная нагрузка | Одна часть работает в десятки раз интенсивнее остальных, и её нужно масштабировать отдельно | Приём событий от оборудования, обработка файлов, поиск | Что именно упирается, и нельзя ли решить копированием всего приложения |
| Разная надёжность | Сбой второстепенной части не должен останавливать основную | Уведомления, отчёты, интеграция с нестабильной внешней системой | Умеет ли основная часть жить без выделенной |
| Разная скорость изменений | Одну часть меняют каждую неделю, другую раз в полгода | Часто меняющийся интерфейс, правила расчёта | Что будет при несовпадении версий |
| Разные команды | Две и более группы мешают друг другу в одном репозитории и в одном релизе | Область, которой полностью владеет одна команда | Чётко ли разделены данные и обязанности |
Вторая группа признаков — сигналы, что выделять рано: сервис получается слишком мелким, зависит от соседей на каждом шаге, а данные для одного ответа приходится собирать из нескольких мест. Тогда это не сервис, а часть монолита, разрезанная по сети.
Как разрезать: по понятиям, а не по слоям
Самая частая ошибка при делении — сервисы по слоям: один отвечает за интерфейс, другой за правила, третий за базу. Каждое изменение затрагивает все три, и система получает только накладные расходы сети. Правильнее проводить границы по предметным понятиям: заказ, склад, платёж, документ.
Для каждой границы проверьте три вещи:
- Владение данными. У понятия есть собственная база или схема, и остальные читают её только через интерфейс.
- Самостоятельность. Большинство операций выполняется внутри границы, а не требует вызова пяти соседей.
- Причина меняться вместе. То, что меняется вместе, лежит внутри одной границы.
Практическое правило выделения: начните с самой независимой части, где мало связей и ясные данные. Обычно это уведомления, формирование файлов, приём вебхуков. На ней команда отладит развёртывание, мониторинг и трассировку, прежде чем трогать ядро с заказами и деньгами. Принципы проектирования интерфейсов, на которых держатся такие границы, описаны в статье «Проектирование API для интеграций».
Типичные ошибки
- Распределённый монолит. Сервисы выделены, но общая база осталась, а релизы приходится выкатывать вместе. Все расходы микросервисов, ни одной выгоды.
- Слишком мелкие сервисы. Каждый маленький и прост, но связей между ними много, и понять систему можно только целиком.
- Синхронная цепочка. Запрос проходит через пять сервисов подряд, и доступность всей цепочки падает ниже доступности каждого звена. Подробнее об этом расчёте в статье про доступность «три девятки».
- Нет наблюдаемости. Сервисы запущены, но журналов и трассировки нет, и причину сбоя ищут вручную в нескольких местах.
- Общая библиотека с логикой. Правила бизнеса лежат в общей библиотеке, и любое изменение требует обновить все сервисы одновременно.
- Переход «сразу всё». Остановка разработки на переписывание. Безопаснее постепенная замена с откатом на каждом шаге.
Как перейти без остановки бизнеса
Если решение о выделении принято, безопасный путь — постепенная замена. Перед старой системой ставится прослойка, и функции переезжают в новые модули по одной; старый код отключается, когда в него не остаётся обращений.
- Тесты на текущее поведение. Без них вы не узнаете, что сломали при выносе.
- Границы внутри монолита. Сначала модули, потом сервис. Если граница не держится внутри одного приложения, она не удержится по сети.
- Первая часть — самая независимая. Выделяем и запускаем параллельно со старым путём, сравниваем результаты.
- Данные отдельно. Перенос данных идёт отдельным шагом, с проверкой совпадения и возможностью вернуть.
- Откат на каждом шаге. Пока старый путь жив, вернуться можно за минуты.
Перед началом полезно оценить состояние кода и данных: что связано с чем, где скрытые зависимости. Для этого есть аудит кода и архитектуры. Разбор нашей типовой задачи для многоарендной платформы есть в разделе разборов.
Вопросы подрядчику, который предлагает микросервисы
Если вам предлагают микросервисы, попросите ответить письменно. Ответы показывают, подумал ли подрядчик над вашей системой или повторяет популярное решение.
| Вопрос | Хороший ответ | Тревожный ответ |
|---|---|---|
| Какую проблему это решает у нас | Названа конкретная причина: нагрузка, надёжность, скорость изменений или команда, с замером | Общие слова про современность и масштабируемость |
| Что остаётся в монолите | Есть список того, что не выделяем, и причины | Выделяется всё сразу |
| Как устроены данные | У каждого сервиса своя схема, описано, как собираются сводные отчёты | База общая «пока», срок раздела не назван |
| Кто будет это эксплуатировать | Названы люди, мониторинг и порядок разбора сбоев после сдачи | Эксплуатация не обсуждалась |
| Как откатимся, если не получится | Старый путь живёт параллельно, откат на каждом шаге | Переход одним релизом |
| Сколько это стоит в год | Названы расходы на серверы, мониторинг и сопровождение, без выдуманных сумм | Оценена только разработка |
Общий список вопросов подрядчику собран в статье «Как выбрать подрядчика на разработку ПО». Стоимость владения считается отдельно, см. статью о стоимости владения ИТ-системой.
Что делаем мы и с чего начать
Начинаем с обследования: 200 000 ₽ и 2–3 недели за один контур, 350 000 ₽ и 3–4 недели, если вокруг несколько систем, 500 000 ₽ и 4–6 недель для контура с оборудованием или жёсткими требованиями. На выходе нагрузочная модель, карта границ, рекомендация с причинами (в том числе «оставить монолитом») и вилка бюджета. Стоимость вычитается из первого этапа, если продолжаете с нами, а документом можно пользоваться и без нас.
Дальше, если нужно, пилот одного шага: лёгкий — 150 000–400 000 ₽ за 2–8 недель, тяжёлый — 400 000–1 200 000 ₽ за 2–3 месяца. На любой ступени можно остановиться. Мы работаем над одним контуром, а не строим платформы на сотни сервисов, и не дежурим круглосуточно. Исходники лежат в вашем репозитории с первого коммита. Цены и сроки — на странице «Тарифы», описание услуги — на странице «Микросервисы и высоконагруженные системы».
Частые вопросы
Что лучше: микросервисы или монолит?
Для большинства бизнес-систем с одной командой лучше модульный монолит: проще разрабатывать, тестировать и эксплуатировать. Микросервисы оправданы при разной нагрузке, разной надёжности, разной скорости изменений или нескольких командах, если есть кому их эксплуатировать.
Что такое модульный монолит?
Одно приложение и одна база, но внутри явные модули с публичными интерфейсами. Модули не читают чужие таблицы напрямую, и это проверяется в сборке. Такой порядок удобен сам по себе и позволяет позже выделить модуль в сервис, если понадобится.
Как понять, что пора переходить на микросервисы?
Когда у конкретной части есть сильная причина жить отдельно: другая нагрузка, другие требования к надёжности, другая скорость изменений или собственная команда. Сигнал «код большой» сам по себе причиной не является: сначала наводят порядок внутри монолита.
Микросервисы быстрее монолита?
Не сами по себе. Вызов по сети медленнее вызова функции. Выигрыш бывает в том, что нагруженную часть можно масштабировать отдельно, а не копировать всё приложение. Если тормозит один запрос, быстрее и дешевле его исправить.
Нужен ли Kubernetes для микросервисов?
Не обязательно. Несколько сервисов можно запускать в Docker на нескольких серверах. Kubernetes имеет смысл, когда сервисов много и есть люди, умеющие его эксплуатировать; без таких людей он добавляет собственные риски.
Можно ли вернуться с микросервисов к монолиту?
Можно, и такие случаи встречаются, когда сервисов оказалось слишком много. Объединять проще, если данные не разошлись по разным базам. Решение принимается по тем же критериям, что и выделение.
Сколько стоит проектирование архитектуры?
Обследование стоит 200 000 ₽ (один контур), 350 000 ₽ (несколько систем) или 500 000 ₽ (контур с оборудованием). Пилот одного шага — 150 000–400 000 ₽, несколько частей — 400 000–1 200 000 ₽. Вывод в эксплуатацию от 1 500 000 ₽ этапами по 300 000–700 000 ₽.
Вы дежурите круглосуточно?
Нет, круглосуточной дежурной смены у нас нет. Сопровождение помесячное: 20 000, 60 000 или 120 000 ₽ в месяц на 4, 12 или 25 часов, сверх пакета 5 000 ₽ в час. Если ваша система должна быть доступна круглосуточно, это обсуждается до договора.