Переход от монолита к микросервисам

server2.svg

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


Понятное дело, в сети существует огромное количество экспертных статей, которые показывают нам важность такой архитектуры и рассказывают о том какую архитектуру можно назвать хорошей, а какую не очень. Существует огромное количество методов взаимодействия между отдельными програмками большого приложения со своими протоколами, версионированием протокола и документации, написания документации на программные интерфейсы, способа развертывания и синхронизации всего этого добра вместе. Безусловно, каждая такая статья или метод логичен и последователен и особенно, если описанный метод подтвержден на практике. Но беда не в том, что проектировщики не знают какую систему они хотят в итоге получить. Беда в том, как перейти к такой вот правильной архитектуре и когда же можно прекратить писать монолитное приложение и начать уже писать взрослые микросервисы, чтобы перед пацанами не было стыдно.


Сначала монолит


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


От микросервисов не уйти


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


Главное начать


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


Вышеупомянутые три утверждения ставят перед нами два вопроса: когда и как. Давайте по порядку.


Как понять, что наступил тот самый момент, что пора уже пилить микросервисы?


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


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


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


И самый главный критерий необходимости начать переходить на микросервисную архитектуру — когда стоимость добавления новой фичи начинает превосходить выгоду от этой самой фичи.


С чего начать миграцию архитектуры в пользу микросервисов?


Стратегий смены парадигмы несколько. Самая простая из них и стратегически неправильная — разработать микросервисную архитектуру с нуля, используя монолитное приложение, как пример для подражания. Наверное, распространенность такого подхода и есть главным аргументом приверженцев писать приложения сразу на микросервисах. Но это серьезно добавляет стоимости к изначальной разработке приложения.


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


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


Вместо выводов.


Микросервисы — хорошо. Монолит — хорошо. Хороший код — хорошо. Рабочий код — хорошо. Статья не призывает срочно менять принцип разработки в приложениях, которые тормозят, криво написаны или написаны не так, как хотелось бы. Так же микросервисная архитектура не является панацеей от всех бед разработчиков. В статье описываются точки и способы перехода от монолитной к микросервисной архитектуре.


«Отказоустойчивость», «распределенность», «масштабируемость» это безусловно хорошо, но не это главное преимущество микросервисной архитектуры. Самое важное, что дает такой подход — удешевление стоимости внесения изменений.

Комментарии (4)

  • 1 августа 2016 в 01:45

    +1

    Ну смысла в этой статье нет уже книгу написали.
    Не всегда микрокосервисы лучше монолита. не говорите мне про масштабируемый код в вакууме)
  • 1 августа 2016 в 01:59

    +5

    При переходе на микросервисы надо учитывать общую стоимость владения, а не только затраты на разработку. Разработка микросервисного приложения и правда может оказаться дешевле. Но жизнь продукта разработкой не заканчивается, далее следует саппорт, затраты на который обычно в разы превышают затраты на разработку. По разным оценкам стоимость разработки составляет примерно 10–20%, в то время как саппорт — 60–80% в общих затратах в течение периода эксплуатации.

    Так вот в случае микросервисной архитектуры затраты на саппорт минимум удваиваются.

    Процитирую свой коммент к другой статье, почему это происходит
    В моей компании тоже все на микросервисах, только счастья это не приносит:
    • если ищу причину какого-то бага, то в большинстве случаев где-то по ходу анализа исходника приложения натыкаешься на вызов очередного endpoint-а, приходится скачивать его исходники тоже, а там опять endpoint куда-то еще, и т.д. О локальном дебаге речь вообще даже не поднимается, так как слишком много приложений-микросервисов придется локально конфигурировать. В итоге баги ищутся, в основном, путем смотрения на код.
    • микросервисы, как правильно заметил автор, зачастую написаны на разных версиях разных языков, что делает локальный дебаг трудным или невозможным
    • особенно странно видеть, как зоопарк микросервисов на разных версиях разных языков оперирует с одними и теми же логическими связанными данными. Я, конечно, понимаю, что хотели делать масштабируемо, но на уровне данных все SQL-запросы в итоге идут к одним и тем же базам данных, от чего БД становятся узким местом. Но отмасштабировать БД, как правило, намного труднее.
    • иногда базы данных пытаются сделать масштабируемыми путем разбиения на логически независимые базы. Микросервисы тогда зависимы только от своей БД, и чувствуют себя отлично, но при этом возникает необходимость в процессах копирования данных между БД, синхронизация, ETL и все такое, что тоже немалый источник хлопот.
    • при необходимости внесения изменений в микросервис в большой компании зачастую представляет проблему выявить и, тем более, протестировать, все приложения-юзеры, его использующие. Поэтому часто всместо внесения изменений в существующий микросервис, просто создается очередной модифицированный клон, который делает почти то же самое. В итоге подход, призванный снизить избыточность кода, дает ровно обратный эффект.
    • микросервисы, когда вызывают другие микросервисы по HTTP, работают существенно медленнее, чем если бы тот же код исполнялся из одного процесса, что часто приводит к необходимости все переделывать без микросервисов
    • если любой из нужных микросервисов недоступен, то как правило пользоватетель получает не частично, а полностью неработающее приложение. Это из области мифив, что приложением можно будет пользоваться, но с ограниченниями. Я таких приложений не видел.

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

    В общем это не факт, что на микросервисах удасться сэкономить.
    • 1 августа 2016 в 07:22 (комментарий был изменён)

      +1

      Почему микро-сервис — это обязательно отдельный проект? Ведь можно иметь единую кодовую базу и при этом с успехом использовать микро-сервисы. Например, монолитный код проекта можно запускать с разными конфигами, таким образом формируя любое необходимое количество микро-сервисов.
  • 1 августа 2016 в 02:17 (комментарий был изменён)

    0

    А разве Microsoft Transactions Server c DCOM объектами не этим же занимались?

© Habrahabr.ru