Вашему стартапу не нужны 14 микросервисов
Недавно в топ Reddit вышел материал с довольно вызывающим названием: Postgres Is Enough. Его основная мысль проста: большинству проектов не нужны отдельные системы для кеша, очередей, поиска, документов, аналитики и векторных данных. Во многих случаях достаточно одной нормально настроенной базы PostgreSQL.
Я прочитал материал и поймал себя на мысли, что то же самое можно сказать не только о базах данных.
Большинству стартапов не нужны 14 микросервисов. Им нужен работающий продукт, первые пользователи и возможность быстро менять то, что оказалось неправильным.
Но на старте почему-то часто строят архитектуру так, будто завтра придут сто миллионов клиентов.
Как простой продукт превращается в маленький Netflix
Представим обычный сервис: регистрация, личный кабинет, каталог, оплата и уведомления.
Команда решает делать всё «по-взрослому»:
- отдельный сервис авторизации;
- отдельный сервис пользователей;
- отдельный каталог;
- отдельные платежи;
- отдельные уведомления;
- API Gateway;
- очередь сообщений;
- Redis;
- Elasticsearch;
- несколько баз данных;
- Kubernetes для управления всем этим хозяйством.
Продукт ещё не заработал первые деньги, но у него уже есть распределённая система.
На архитектурной схеме это выглядит солидно. В реальной разработке команда начинает выяснять, почему регистрация прошла успешно, а профиль пользователя не создался. Или почему платёж обработался, но уведомление потерялось между сервисами.
Вместо проверки продуктовой гипотезы разработчики проверяют сетевые тайм-ауты.
Микросервисы не убирают сложность
Это главное заблуждение.
Когда большую систему делят на небольшие сервисы, сложность не исчезает. Она просто перемещается из кода в сеть и инфраструктуру.
Обычный вызов функции превращается в HTTP-запрос. Транзакция в одной базе превращается в согласование данных между несколькими хранилищами. Локальная ошибка становится распределённой: один сервис уже выполнил операцию, второй не ответил, третий получил сообщение дважды.
После этого появляются:
- повторные запросы;
- идемпотентность;
- очереди недоставленных сообщений;
- трассировка запросов;
- централизованные логи;
- мониторинг каждого сервиса;
- управление секретами;
- версионирование API;
- отдельные сборки и развёртывания.
Это решаемые задачи. Но стартапу сначала стоит честно ответить: действительно ли они уже стали его задачами?
Spotify, например, отдельно отмечала, что основная сложность микросервиса находится не внутри него, а во взаимодействии с остальной системой. Поэтому тестирование такой архитектуры требует особого внимания к интеграциям. Разбор Spotify Engineering.
Стартапу важнее скорость изменения, а не независимость сервисов
На ранней стадии границы продукта постоянно двигаются.
Сегодня каталог кажется отдельным модулем. Завтра выясняется, что часть его логики должна находиться в оформлении заказа. Послезавтра меняется бизнес-модель и половина сущностей объединяется.
В монолите такое изменение может потребовать нескольких правок в одном репозитории и одной миграции базы.
В микросервисной архитектуре придётся менять контракты, обновлять несколько сервисов, продумывать совместимость версий и согласовывать развёртывание.
Мартин Фаулер ещё в эссе Monolith First обращал внимание на важную закономерность: успешные микросервисные системы часто вырастали из монолита, а попытки начинать новый продукт сразу с микросервисов нередко приводили к серьёзным проблемам.
Причина понятна. Чтобы правильно разделить систему, нужно знать её устойчивые бизнес-границы. А стартап в начале пути ещё только пытается их найти.
Получается странная ситуация: команда закрепляет в архитектуре знания о продукте, которых у неё пока нет.
Монолит не должен быть свалкой
Здесь важно не уйти в другую крайность.
Слова «начните с монолита» не означают, что весь код нужно складывать в один огромный файл, разрешать модулям обращаться друг к другу как угодно и забыть о структуре.
Разумный вариант для большинства новых продуктов — модульный монолит:
- одно приложение;
- один основной репозиторий;
- одна понятная схема развёртывания;
- чёткие границы между бизнес-модулями;
- контролируемые зависимости;
- возможность позднее выделить действительно перегруженный модуль.
Именно такой путь в своё время выбрала Shopify. Несмотря на масштаб платформы и огромную кодовую базу, компания не стала автоматически превращать каждый компонент в отдельный сервис. Вместо этого она сохранила единое приложение, но усилила границы между модулями. Разбор архитектуры Shopify.
Это хороший пример того, что архитектурная зрелость определяется не количеством сервисов.
Иногда более зрелое решение — сознательно отказаться от лишнего сервиса.
С базами происходит то же самое
Допустим, команде понадобился поиск. Она сразу добавляет Elasticsearch.
Затем появляется кеш — подключается Redis. Для фоновых задач берётся ещё одна очередь. Для документов выбирается MongoDB. Для аналитики — отдельное хранилище. Для AI-поиска — векторная база.
В результате у небольшого продукта появляется семь систем, каждую из которых нужно:
- обновлять;
- резервировать;
- защищать;
- наблюдать;
- восстанавливать после сбоя;
- оплачивать;
- понимать хотя бы одному человеку в команде.
Именно против этого выступают авторы Postgres Is Enough. PostgreSQL не лучший инструмент для каждой задачи, но он поддерживает полнотекстовый поиск, JSONB, геоданные, очереди через SKIP LOCKED, векторный поиск через расширения и множество других сценариев.
Специализированная система может быть быстрее. Но разница между «быстрее в тесте» и «выгоднее для бизнеса» бывает огромной.
Когда микросервисы всё-таки нужны
Я не считаю микросервисы ошибкой. В Paladin Engineering мы смотрим на архитектуру не через моду, а через ограничения конкретного продукта.
Выделение отдельного сервиса может быть оправдано, когда:
- часть системы нужно масштабировать независимо;
- над разными областями работают автономные команды;
- компонент требует особых технологий или уровня изоляции;
- сбой одного модуля не должен влиять на остальные;
- границы предметных областей уже понятны и устойчивы;
- единое приложение действительно мешает выпускать изменения.
Ключевое слово здесь — действительно.
Не «когда-нибудь у нас будет миллион пользователей», а «сейчас один компонент создаёт измеримую проблему, которую отдельный сервис решает дешевле других вариантов».
Сначала заработайте право на сложность
Архитектура стартапа должна помогать быстрее отвечать на вопросы:
Нужен ли продукт людям? Готовы ли они платить? Какая функция действительно важна? Что нужно изменить после первых отзывов?
Если большая часть инженерного времени уходит на Kubernetes, очереди, сетевые политики и синхронизацию данных между сервисами, возможно, команда решает проблемы компании, которой ещё не стала.
Мы в Paladin Engineering придерживаемся довольно приземлённого принципа: сложность должна появляться в ответ на реальную потребность продукта, а не для соответствия модной архитектурной схеме.
Начните с хорошо организованного приложения. Используйте одну базу, пока она справляется. Выделяйте сервис только тогда, когда можете конкретно объяснить, какую проблему он решает и сколько будет стоить его содержание.
Вашему стартапу не нужны 14 микросервисов.
По крайней мере, пока у него нет четырнадцати настоящих причин для их появления.