Здравствуйте, BlackEric, Вы писали:
BE>На хабре есть перевод довольно интересной статьи: Распутывание микросервисов или балансировка сложности в распределенных системах.
Посмотрел я на картинки, и что-то от них SOA пахнуло. Потом почитал немного — не ошибся. Их определение сервиса взято из
Service Oriented Architecture. Вообще определения архитектур варьируются. Я дальше приведу те, которые использую сам (это enterprise integration patterns). Они дают очень четкое различие между SOA & Microservices.
Собственно, сервис на каждый бизнес-процесс — это один из характерных атрибутов SOA. Еще там обычно наблюдаются еще два уровня сервисов (инфраструктура — логи и т.п., и "бизнес-ядро" — всякие пользователи и прочие общие понятия). SOA идеально подходит для случаев, когда бизнес-сценарии включают множество шагов (потенциально — много ручных шагов). Например, "одобрить квартиру в ипотеку" — очень хороший кандидат на SOA. Там много внешних интеграций, процесс может включать осмотр квартиры специалистом и т.п. К сожалению, SOA вроде больше никуда не подходит.
BE>Где наконец-то говорится, что микросервисы это не так уж хорошо и не всегда применимо. В конце статьи очень интересный список ссылок.
Серебрянной пули нет, это известно было и до этого автора. Характерным критерием microservices architecture, которую учил я, является построение сервисов вокруг замкнутых контекстов (
Bounded Context). Т.е. каждый сервис описывается в рамках "своей личной" модели. Микросервисы не допускают в API полей вида "userId — id пользователя в central user-management system", а SOA как раз допускает и даже приветствует. Условно, Backlog в статье имеет своих team и user (могут создаваться из других систем). Эти сущности могут иметь поля вроде externalId, но внутри самого сервиса эти поля не используются! Если выкинуть из первой картинки Backlog непонятную функцию "show item", получится неплохой микросервис.
Микросервисы устраняют проблемы (churn) вокруг широкоиспользуемых классов (вроде пользователя, базовых документов и т.п.) куда в монолите будут периодически пытаться писать много команд. Но зато создает проблемы синхронизации/репликации данных между сервисами и контекстами. Также усложняет UI/фасад, так как нет единого понятия "пользователь". Интерфейсным частям часто приходится ходить во много сервисов и собирать "полное" представление по частям. В общем, компромиссы.
BE>Кто как делает?
Я делаю микросервисы в моем определении (замкнутый контекст). Из артефактов реализации:
База логически у каждого своя (физически — может быть один экземпляр db engine).
Общение (push, в направлении зависимостей) в основном REST Level 2. Т.е. общение в терминах состояний а не операций.
Передача данных "в обратном направлении" — обычно через message queues. Люблю rabbit, где клиенты могут _сами_ подписаться на нужные обмены (exchange). Наличие exchange и форматы сообщений — часть контракта сервиса.
Есть разница между развертыванием (deployment) и сервисами (bounded context, роль в рамках большей системы). Один микросервис может иметь несколько различных компонент (т.е. несколько различных deployment unit). Эти компоненты могут ходить в базу и общаться по внутреннему протоколу. С точки зрения внешнего зрителя — это один среднего размера сервис.
BE>Я тоже считаю, что плодить множество действительно микросервисов с кучей баз данных повышает трудоемкость разработки и поддержки проектов.
Да, микросервисы делать сложнее по многим причинам. В какой-то книжке это прекрасно сформулированно было: если ваши разработчики не могут нормально сделать модульность в рамках одного монолита, то почему вы решили, что они смогут сделать нормальную модульность в рамках распределенной системы? Именно в дизайне модулей, разбиении на компоненты и начинаются проблемы. Всякие там зацепление и связность (coupling & cohesion). Почему-то не любят разработчики эти понятия. Разбивают систему на куски чисто механически. А в распределенной системе этот бардак становится заметен очень рано.
BE>В первую очередь — это необходимость согласовывать изменения между сервисами. И невозможность вытащить данные из одной бд sql запросом.
Так а это две стороны одной и той же медали. В микросервисах вам нужно согласовывать API между компонентами. В одной базе — согласовывать форматы данных хранения. Вот представьте, что моя команда сделала рефакторинг и переколбасила с десяток таблиц. Ваши sql запросы по вытаскиванию данных придется пересматривать. При определенной зрелости команды меньше согласований именно в микросервисах. Одна команда выкатила обратно-совместимый API (новые поля, новые content type, в крайнем случае — новые /api/vX). Затем туда переползают все пользователи сервиса, старый API отключается. Иногда так сделать нельзя, но очень часто все-же можно. Только это нужно уметь, а это задача вроде сложнее сортировки гномиков.