Размер микросервиса

Один из самых часто задаваемых вопросов — каким должен быть размер микросервиса? Попробуем разобраться.

Что есть размер микросервиса?

Начнем с определения микросервисного архитектурного стиля от Мартина Фаулера и пройдемся по выделенному жирным:

Архитектурный стиль микросервисов — это подход, при котором единое приложение строится как набор небольших сервисов, каждый из которых работает в собственном процессе и коммуницирует с остальными используя легковесные механизмы, как правило HTTP. Эти сервисы построены вокруг бизнес-потребностей и развертываются независимо с использованием полностью автоматизированной среды.

Небольшие сервисы — это какие? Правда в том, что мы точно не знаем. Нам сложно определить, что такое «небольшой», но мы точно помимаем, что значит «большой и сложный». Подход «monolith first» нам о том и говорит: стартуйте с хорошего, модульного монолита и начинайте выносить микросервисы, как только сложность начнет снижать вашу продуктивность. С независимостью проще — это, по сути, отсутствие зависимостей 🙂

Сложность микросервисов

Посмотрите на изображение выше. Нас в особенности интересует часть «the decreased coupling of micrservices reduces the attenuation of productivity», что означает «сниженная связанность микросервисов снижает скорость убывания продуктивности».

Вся суть в миграции сложности из бизнес-логики в инфраструктуру. Пока монолитная система не стала достаточно сложной для развития, поддержка инфраструктуры для микросервисов будет снижать продуктивность значительно быстрее, чем зависимости на уровне единой кодовой базы.

Но всегда наступает момент, когда сложность развития монолита не просто начинает замедлять продуктивность, но буквально останавливает разивтие, вначале на небольшие промежутки времени, затем эти промежутки становятся заметнее (code freeze, ручной регресс всего решения и так далее). Вот тут стоит задуматься о выносе первых микросервисов. О том, в каком порядке это лучше делать я писал ранее, сейчас интереснее ответить на вопрос «есть ли какой-то универсальный размер выносимого микросервиса?». И я считаю, что универсального размера нет, но есть требование к изоляции сервисов друг от друга. Ведь если между сервисами появляется сильная зависимость, то на выходе получаем распределенный монолит, а это снижает продуктивность почти до нуля (образно, но не далеко от истины).

То есть можно делить монолит на микросервисы, а микросервисы на более мелкие до тех пор, пока соблюдаются основные принципы изоляции. О них и пойдет дальше речь.

Изоляция по бизнес-потребностям

Самый сильный вид изоляции — изоляция на уровне модели бизнеса. Например, Bounded Context (Ограниченный контекст) и Aggreagte (Агрегат) из Domain Driven Design. Наиболее простой и быстрый способ выявление контекстов и агрегатов из ныне существующих — это Event Storming.

Ограниченные контексты
Агрегат документ в трех разных контекстах

Domain Driven Design позволяет определить стратегический дизайн системы вокруг бизнес-концепций (ограниченных контекстов). По сути — построить модель бизнеса. Все технические решения — это наполнение стратегического дизайна деталями и если контексты изолированы, то технически мы просто не сможем породить зависимости. Проблема только в том, что мы можем 🙂 Особенно, если не учли основные технические принципы изоляции.

Изоляция состояния

Почти всегда микросервис хранит состояние. Можно делить сервис на более мелкие до тех пор, пока ему не потребуется ходить в базу другого сервиса. На картинке один пример, приведу еще и другой. Сущность «Документ», содержит список изменений (в рамках транзакционной границы). Мы решили вынести работу с изменениями в отдельный сервис. Теперь при применении «Изменений» мы либо используем распределенную транзакцию (нет), либо оба сервиса смотрят в одну базу (тоже нет). Следовательно — не выносим работу с изменениями в отдельный сервис.

Изоляция состояния микросервисов

Изоляция в пространстве

Микросервисы не должны ничего знать о месте расположения других микросервисов, ведь микросервисная архитектура — крайне динамична. В любой момент времени какие-то сервисы могут запускаться, другие останавливаться, одновременно может выполняться несколько версий одного сервиса. Тут нам на выручку приходят событийная модель и Service Discovery, но важно обращать внимание, что при дальшейшем разделении на микросервисы мы не забыли учесть этот принцип. Для этого тестируем решение, динамично поднимая, останавливая, перезапуская и выполняя иные действия над микросервисами.

Изоляция микросервисов в пространстве

Изоляция во времени

Микросервисная архитектура — система распределенная, а к распределенным системам применима CAP-теорема: «согласованность, доступность, устойчивость к разделению — выбери любые два».

CAP-теорема

Есть нюанс. Например, где-то не вернул ответ за 30 ms — уже недоступен, а где-то 5 секунд — не криминал. Но вернемся к распределенной природе микросервисов. Сеть не является надежной по-определению, а значит необходимо поддерживать устойчивость к разделению. Следовательно, нам остается идти на компромисс между согласованностью и доступностью. И в микросервисах мы его чаще делаем в сторону доступности, соглашаясь на согласованность в конечном счете (то есть после записи, чтение вернет последние данные, но, возможно, не сразу).

Если при разделении сервиса на более мелкие появляется потребность в распределенной транзакции для поддержания согласованности данных — лучше не делить. А для долгоживущих транзакций есть свои методы, о них когда-нибудь потом.

Изоляция микросервисов во времени

Изоляция сбоев

Сбои в микросервисах происходят постоянно и очень важно, чтобы падение одного микросервиса не приводило к падению другого. С одной стороны здесь нам круто помогает использование событий, Curcuit Breaker, Bulkheads, Fallbacks и другие паттерны, с другой стороны, если один сервис вообще никак не может жить без другого, то, возможно, стоит еще раз пристально посмотреть на границы сервисов — возможно какую-то атомарную часть бизнес-логики мы случайно разнесли по двум сервисам (нарушение high cohesion), либо неверно определили границы сервисов.

Изоляция микросервисов от сбоев

Вывод

Размер микросервиса не так важен, как слабая связанность. Можно декомпозировать монолит на сервисы и сервисы на более мелкие до тех пор, пока:

  • Не нарушаются принципы изоляции, ведь даже из самых мелких по размеру микросервисов можно получить распределенный монолит
  • Инфраструктурная сложность остается под контролем

Оставляйте свои комментарии или пишите на sb@agilemindset.ru, буду рад рад любым отзывам.

Спасибо.

Share

Добавить комментарий