Введение

Где-то года с 2014 слово “микросервисы” плотно вошло в айтишечку, да так, что создавалось мнение, что микросервисная архитектура — панацея. Так вот — нет :) об этом и статья. Мы разберемся, когда микросервисы нужны, когда они мешают, да и вообще коснемся сервис-ориентированной архитектуры.

Монолиты

Что такое монолит? Мы пишем приложение, не деля его на части, запуская его целиком. Почему это удобно? Сразу видна вся логика приложения, не нужно заботиться о взаимосвязях, легче писать — вся бизнес-логика, работа со всеми данными — все это в одном месте. Монолит легче тестировать (особенно это касается end-to-end тестов) и проще запускать.

Сложности начинаются с ростом техдолга: становится все сложнее и сложнее добавлять новые фичи и фиксить баги из-за высокой связности (как писать код правильно, читайте здесь). Когда монолит растет, неизбежно возникают проблемы, когда некоторые части приложения требуют больше ресурсов. Тогда мы вынуждены либо масштабировать приложение вертикально (просто увеличивать количество выделенных ресурсов), либо горизонтально масштабировать (запускать несколько инстансов приложения) монолит целиком, что достаточно ресурсоемко. Отсюда перейдем к тому, что называется сервис-ориентированной архитектурой (и как это обычно выглядит в реальности).

Сервис-ориентированная архитектура

В идеале сервис-ориентированная архитектура — это куча слабо связанных между собой сервисов, взаимодействующих по какому-то заранее определенному контракту: Взаимодействие может быть выстроено по HTTP, gRPC, очередям сообщений и как только не. Самый важный аспект — это та самая слабая связность сервисов — это позволяет выделять доменные области в отдельные сервисы.

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

Микросерверная архитектура

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

Так же, как и сервисы, они взаимодействуют друг с другом как отдельные сторонние приложения. В них из-за отсутствия связности легко вносить изменения (соблюдая контракт взаимодействия, конечно). Еще прикольно то, что в больших компаниях разные команды могут независимо друг от друга работать над разными микросервисами.

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

А деплой? Деплоить микросервисы гораздо сложнее, чем монолит. Спасибо контейнеризации и штукам для оркестрации типа Kubernetes, это чуть все упрощает, но не отменяет того, что деплоить микросервисы сложнее. А если нужно внести изменения сразу в несколько микросервисов? Взаимодействие разработчиков становится в этом случае очень и очень сложным.

Выводы

А выводы просты. У вас много команд? Микросервисы могут облегчить разработку (хоть и не всегда). Если у вас небольшая команда, пожалуйста, не ведитесь на хайп микросервисов и пилите монолит, стараясь сохранять низкую связность, закладывая в приложение модульность, В этом случае вы при необходимости сможете сравнительно легко выделить что-то в отдельный сервис.

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

В общем, короткий ответ: маленькая команда? Начните с монолита. Много команд? Проработайте взаимодействие между ними, строго обговорите контракт и пилите микросервисы.