«Скажите, какие основные преимущества микросервисов и почему?». Вероятно, это самый популярный вопрос последних 6–10 лет на любом собеседовании для бэкенд разработчика. Каким‑то чудом он даже обогнал: «Назовите три принципа ООП» и «Чем отличается класс от объекта?»
![](https://habrastorage.org/getpro/habr/upload_files/cbc/496/81c/cbc49681c0df6fb4c2a952cbd7026da1.png)
Эх, где мой 2015-ый, когда на вопрос "Что такое java?" ты отвечал "старый дедовский мотоцикл в моем гараже" и тебя все равно брали ведущим разработчиком. Но время идет, конкуренция растет и требования к кандидатам меняются. В этом цикле статей я бы хотел осветить микросервисную архитектуру: что это такое и зачем она нужна. Статья будет полезна всем тем кто, как и я, прикидывается разработчиком и даже получает за это пачку сухариков на работе.
![](https://habrastorage.org/getpro/habr/upload_files/790/b64/966/790b6496663c72e13f3b5e72e6289b2f.png)
Зачем?
Для того, чтобы ответить на вопрос зачем была создана данная архитектура нужно понимать какую проблему она решает. Лучше всего это можно сделать на примере. Выдумаем ситуацию.
Вы какой-то очень умный и предприимчивый гражданин. Допустим вас зовут Павел Жмуров. Однажды в теплый солнечный день, когда планеты встали в ряд, на вас взошло озарение и вы позаимствовали придумали оригинальный и интересный сайт. Допустим "ВКонтракте". Вы также вспомнили, что у вас есть брат, который, по словам очевидцев, умеет думать на ассемблере и компилировать код в голове. И яркой вспышкой в голове сама собой появилась формула: "идея + брат = деньги". И это сработало, новый ресурс был создан и начал завоевывать аудиторию!
Проходит время и сайт обрастает новыми пользователями. Ваш текущий сервер не справляется с нагрузкой. Необходимо переходить на более мощный и дорогой ресурс. Код обрастает новыми возможностями: игры, приложения, события и много чего еще. Появилось множество других проблем:
команда разрослась. Появилось много merge request'ов. Сложно колаборирорвать.
организация работы возросла многократно
сложность планирования задач в связи с большим количеством разработчиков сильно выросла
Слабая отказоустойсивость. Приложение очень большое но туго связанное. Любое изменения куска программы может привести в нерабочее состояние весь проект
Изменения кода-А влечет изменения кода-Б что, в свою очередь, влечет изменения кода-В и т.д.
сложный процесс тестирования и деплоя
сложный процесс бэкапа
сложность добавления новых возможностей
слишком много денег от которых нужно избавиться путем выбрасывания последних из окна
Текущая монолитная архитектура многие годы решала свою задачу на отлично. Но нагрузка и требования выросли и нужно было что-то менять.
После долгих часов медитаций и бесчисленных ретритов вы наконец нашли выход - отдать задачу брату. Брат же, почесав промежность и понюхав руку, придумал классную идею - а давайте разобьем наш цельный кусок кода на слабосвязанные кусочки. Вместо одного большого мы получим множество маленьких приложений. Команды смогут разделиться на небольшие группы. Изменения в одном проекте не будет влиять на работу других. Деплой и тестирование упростятся в разы. Войны в мире прекратятся. Глобальное потепление остановится. В общем, мы решим большинство выше описанных проблем. А назовем мы сие чудо - микросервисы. Сказано - сделано. Начинаем "пилить" наш монолит.
Принципы микросервисной архитектуры
Становится вопрос - как разрезать пирог так, чтобы идея сработала? Мы, конечно, можем случайным образом разделить код на части в надежде что все настроиться само собой - но есть маленький риск того что этот подход не сработает. Чтобы решить эту задачу более основательно нужно перезагрузить компьютер понять что из себя должен представлять отдельный микросервис и какими свойствами он должен обладать.
Сплоченность (Cohesion)
Элементы, которые тесно связаны или сильно зависят друг от друга должны оставаться вместе. Например: сохранение изображений, его сжатие и дублирование нет смысла разделять. Все три операции довольно тесно связанны друг с другом. С другой стороны, выносить логику покупки стикеров, регистрацию пользователей и добавление игр в один микросервис не даст никаких преимуществ. В таком случае при добавлении новой игры мы можем нарушить функционал регистрации пользователей. При таком подходе мы один монолит разобъем на несколько монолитов. А это, в свою очередь, негативно скажется на вашей карме и зарплате. Как говорил Ницше: "Разбитый на части монолит не равняется (!=) микросервисной архитектуре".
Правильно изолированный сервис позволяет команде заниматься разработкой изолированно от других частей проекта.
Единая ответственность (Single Responsibility)
Каждый микросервис должен делать только одну вещь и делать ее хорошо! При возникновении нового функционала (в простонароде "не баг а фича") нам необходимо четко понимать к какой команде он будет относиться. Весь котекст вокруг конкретных задач должен относиться к единому микросервису. Таким образом при появлении новых неожиданных фич (багов) мы с легкостью можем определить к какой команде это относиться. Исправление данного бага никак не заденет прочие команды и код других проектов.
Слабая связанность (Loosely Coupled)
Каждый микросервис должен иметь минимум общения с прочими микросервисами. С другой стороны если мы на каждый чих будем создавать одтельный микросервис также не даст нам видимых преимуществ.
![](https://habrastorage.org/getpro/habr/upload_files/fd7/d50/82f/fd7d5082f60d58a62bb0072f7ad194ae.png)
В этом случае общение между сервисами превратиться в большую проблему.
![](https://habrastorage.org/getpro/habr/upload_files/b9e/d81/4be/b9ed814be8b1623e0514beae48a3ac7f.png)
Увеличиться время ответа и потеряется второй принцип слабой связанности. Каждый сервис вызывает другой сервис, тот вызывает третий и так до бесконечности. Полностью изолировать сервис невозможно - но необходимо минимизировать его общение. Опять же - множество разбитых кусочков кода не сделает вашу архитектуру микросервисной. Вы получите лишь много монолитов.
И здесь мы подбираемся к важному выводу. Как бы вас жизнь не убеждала в обратном но размер не важен! МИКРО-сервис не означает "мало кода". В данном контексте это стоит воспринимать как логически изолированный контекст приложения (оплата, регистрация, нотификация, UI и т.д). Если вы следуете трем вышеописаным принципам - размер не имеет значения. Какой-то микросервис может быть больше другого в разы и это нормально. Основная идея - разделить код на "контекст" по описанным выше правилам.
Способы декомпозиции
Проще сказать чем сделать ведь непонятно по каким критериям нужно делить код на составные части. Конечно, мы всегда можем подкидывать монетку и случайным образом выбирать кусок кода для его "микросервизации". Помимо множества преимуществ такой подход имеет и несколько недостатков. А в исключительных случаях может не дать ожидаемый результат. Чтобы себя наверняка обезопасить придется рассмотреть другие способы декомпозиции приложения. Проведем мысленный эксперимент на примере типичного онлайн-магазина.
Разделение по бизнес логике
Идея такого подхода в том, что мы делим пирог исходя из бизнес логики. Для этого попытаемся объяснить постороннему человеку основные возможности вымышленного онлайн-магазина:
Скролить по сайту --> Web Service
Добавлять/удалять товары в корзину --> Order Service
Оплачивать выбранные товары --> Payment Service
Писать отзывы на товары --> Review Service
Доставлять купленные товары --> Shipping Service
Добавлять/удалять товары --> Product Service
Сильно тормозить и доставлять не те товары что были выбраны --> Main Core Service
Каждый такой микросервис будет следовать трем основным принципам. Мы точно будем знать какой сервис необходимо ломать менять если необходимо добавить/упростить функционал. Изменения в части доставки никак не связано с отзывами и добавлением товаров. А когда мы расширим способ оплаты мы можем быть уверены что возможность скролить сайт не будет изменена.
Разделение по доменным областям
При данном способе мы можем разделить все приложение на домены:
Ядро системы (Core Subdomain) - самая важная часть без которой все остальное приложение не имеет смысла
Product Service
Поддержка (Support Subdomain) - расширение основных возможностей приложения. Очень важная часть. но без нее приложение сможет существовать
Order service
Inventory Service
Shipping Service
Payment Service
Прочее (Generic Subdomain) - наименее важные компоненты приложения
Reviews Service
Search Service
Images Service
WebUI Service
Security Service
К преимуществам данного подхода можно отнести меньших размер сервиса, более понятную структуру для разработчика и возможность разделить команду по опыту и умениям. К примеру, Generic Subdomain явно менее приоритетен чем Core Subdomain.
Краткое сравнение
![](https://habrastorage.org/getpro/habr/upload_files/2ab/073/8d0/2ab0738d0f720d5ecc59cdbc560652d2.png)
Это не исчерпывающие способы разделение архитектуры, но основные и наиболее популярные. Хочется добавить, что не бывает "идеального" способа или техники декомпозиции. Все, как всегда, сильно зависит от контекста и положения Меркурия в ретрограде.
Продолжение следует.