Предисловие

Я — руководитель группы разработки, провожу технические собеседования в крупных компаниях. И с каждым разом всё чаще замечаю одну тревожную тенденцию. Я спрашиваю кандидата: «Зачем нужны микросервисы?» Он отвечает: «Для масштабирования». Я говорю: «Ок, а как бы ты масштабировал монолит?» Кандидат: «Ну… поставил бы несколько инстансов за балансировщиком». Я: «Отлично. Тогда зачем микросервисы?» Кандидат: «Ну… для отказоустойчивости». Я: «А graceful degradation в монолите можно сделать? Circuit breakers, fallback’и?» Кандидат: «Можно…» Я: «Тогда зачем микросервисы?» И тут кандидат зависает, потому что он не знает настоящего ответа. Он просто выучил набор слов или услышал их от кого-то, но в самой сути не разобрался.

В последнее время, если система — монолит, то она у всех вызывает отторжение, тим лид на собесах стыдиться сказать, что их система монолит, члены команды зачастую также считают это плохим подходом и считают, что если система монолит, то это legacy. В связи с этим я хочу рассказать, почему микросервисы — это не круто, а дорого и сложно.

1. Что такое микросервисы на самом деле?

Микросервисная архитектура (MSA) — это не про технику. Это про команды. Если у тебя 2 команды, работающих над одним монолитом, они будут конфликтовать. Если у тебя 10 команд — они будут убивать друг друга. MSA решает организационную проблему: как сделать так, чтобы команды могли разрабатывать и выкатывать фичи независимо друг от друга. Это единственное обоснование выбора MSA. Соответственно выбор MSA — это не выбор архитектуры из-за NFR, а выбор архитектуры для организации командной работы. Тимлид управляет двумя ресурсами — трудомощность и трудоемкость, аля velocity и capacity из scrum, и если обьем бэклога на систему возрастает, то нужно увеличивать и трудомощность, один тимлид не сможет эффективно управлять командой из 40 человек, здесь уже нужно несколько команд, поддеживающих одну и ту же информационную систему(ИС), тут то и нужно микросервисы. А когда в целом система состоит из 40 микросервисов, эту ИС поддерживает одна команда — то это просто бред.

2. Мифы, которые нужно развеять

Миф 1: Микросервисы нужны для более простого масштабирования и для отказоустойчивости

Горизонтальное масштабирование — это про stateless, если система хранит состояние, ее тоже можно масштабировать, но там надо думать, как это сделать. Если система не хранит состояние, ты ставишь 10 инстансов монолита за прокси(балансировщиком) — и все спокойно масштабируется.

Да, в MSA ты можешь масштабировать только самый нагруженный сервис отдельно. Но это требует дополнительной инфраструктуры, балансировки запросов между сервисами, а также доп издержки на observability для каждой системы.

Альтернатива в монолите: профилируешь, находишь узкое место, выносишь его в отдельный модуль, масштабируешь весь монолит или только этот модуль. Да, это сложнее. Но не настолько, чтобы переписывать всю систему на MSA.

А что касаемо отказоустойчивости, когда говорят про отказоустойчивость, обычно имеют в виду паттерны для отказоустойчивости, аля circuit breaker, bulkhead, rate limiting, fallback и т. д. В монолите всё это тоже можно сделать, можно сделать graceful degradation. Сделать graceful shutdown в монолите даже проще, чем в MSA. Да, в монолите падение модуля заденет другой, если они используют общие ресурсы. Но если правильно спроектировать монолит, то можно добиться почти той же отказоустойчивости, что и в MSA.

Миф 2: Микросервисы нужны для большой базы

В MSA объем БД не магическим образом уменьшается, за это есть плата в виде распределенной транзакции. Это уже сильно сложнее, чем просто транзакции в монолите, т. к. ACID в MSA нельзя поддержать, то нужно что-то думать. Например, Saga, 2PC и т. д. — а это сильно сложнее, чем обычная транзакция. Да и в принципе, оптимизация БД осуществляется другими способами: шардинг, репликация, партицирование и т. д. — всё это, опять же, можно сделать и с монолитом.

Миф 3: Микросервисы нужны для независимых релизов

Вот тут мы потихоньку подходим к действительной причине выбора MSA. MSA позволяет катить фичи независимо, но каждой команде нужен свой CI/CD. Сервисы должны быть слабо связанными, поддерживать обратную совместимость, версионирование, а это уже крайне тяжело сделать. Во многих компаниях куча разрабов просто фигачит брейкинг ченджи в каждом релизе, поэтому про независимый выкат говорить не приходится: командам нужно состыковать свои релизные циклы и по изменениям, которые коснутся других команд, договариваться, чтобы катиться в одно и то же время. В монолите, кстати говоря, можно тоже катиться независимо друг от друга, если соблюдены условия для MSA выше. Можно использовать паттерн SUFA, можно модули разбить на разные репозитории и организовать независимый выкат.

Миф 4: Микросервисы для стартапов имеют место быть, если высокие NFR

Стартапам категорически нельзя начинать с MSA. Если ты стартап — то у тебя нет кучи команд, иначе вы будете много времени тратить на координацию. У тебя нет денег и времени на построение нормальной инфраструктуры, ты умрёшь от распределенных транзакции и eventual consistency, ты не знаешь product market fit — ты будешь часто переписывать код. В MSA кода больше — будешь больше переписывать.

3. Как правильно делать монолит

Да, если делать монолит плохо — он будет плохим. Но проблема не в монолите, а в инженерной дисциплине.

Принципы хорошего монолита:

  1. Модульность. Разбивай код на модули по бизнес-доменам (DDD), а не по слоям(слой инфры, слой бд). Каждый модуль — это независимая единица с чёткими границами.

  2. SUFA-паттерн (Self-Contained Functional Architecture). Каждый функциональный компонент содержит всё необходимое: код, конфиги, миграции. Это позволяет легко выносить модуль в отдельный сервис, если когда-нибудь понадобится.

  3. Никаких God Object’ов. Один класс, который знает всё и делает всё — это антипаттерн. Дели на маленькие классы с одной ответственностью.

  4. Чёткие границы между модулями. Модули общаются через публичные API (не через shared-модели!). Это делает возможным будущее разделение на сервисы.

Когда монолит пора делить?

Когда количество команд превышает 3–5, и они начинают конфликтовать в коде, затягивать CI/CD, бояться релизов. Это сигнал, что пора либо делить на модули с независимыми релизами, либо выносить в MSA.

4. Итого

Правильный ответ про то, когда нужно MSA:

«Микросервисы — это не про технику. Это про команды. Мы используем их, чтобы разные команды могли разрабатывать и выкатывать фичи независимо друг от друга. Всё остальное — масштабирование, отказоустойчивость, производительность — можно сделать и в монолите. Просто это сложнее или требует других подходов. MSA даёт более грубую гранулярность, но за это мы платим деньгами, инфраструктурой и сложностью разработки.» Если кандидат отвечает так — он понимает архитектуру. Если он начинает говорить про Kubernetes, Docker, и Service Mesh, но не про команды — он не понимает сути.

P. S. Для тех, кто всё ещё думает про MSA Если вы четко не можете провести границы в домене, разбить его на независимые модули(именно модули, не слои), то, скорее всего, ваши микросервисы станут «распределенным монолитом». Независмых релизов у вас не будет, отказоустойчивости у вас не будет, будет сильная связанность, и поддерживать такую систему будет сложнее.