
В большом количестве статей, источников микросервисы, помимо всего прочего, представляются как способ построить масштабируемое решение. Рассмотрим на примерах, почему это не так. А так же попытаемся внести свою лепту в извечный вопрос:
Что лучше: монолит или микросервис?
Рассмотрим пример.
Допустим, у нас есть микросервис A
, выполняющий
авторизационные запросы "имеет ли право пользователь выполнить
операцию?".
Поскольку изолированно такой микросервис существовать не может,
то в паре с ним существует другой микросервис B
,
который сохраняет в хранилище список соответствий
пользователи-права (Фактически это структура одного микросервиса,
разделённого на два, чтоб распределить нагрузку по логическим
подмодулям. То есть деление даже более мелкое, нежели обычные
микросервисы).
Примерная схема микросервисов показана на рисунке:

В результате изменений в пользовательских данных (регистрация
новых пользователей, ограничения на существующих и т.п.)
микросервис B
"следит" за актуальностью данных в
хранилище, которое использует микросервис A
для
выполнения авторизационных запросов.
Простая схема. Просто устроена, надёжно работает.
Предположим, что количество пользователей, подключающихся к нашей системе, растёт. Каковы "узкие" места в этой архитектуре?
-
нагрузка на CPU в микросервисе
A
-
нагрузка io-read/select в БД
-
нагрузка на CPU в микросервисе
B
-
нагрузка io-write в БД
Вопросы с CPU в микросервисах решаются просто добавлением экземпляров в игру. Здесь масштабирование простое, и не стоит его обсуждать:

Давайте посмотрим, что будет с ростом нагрузки на микросервис
A
и B
?
В определённый момент времени БД перестанет справляться с
потоком запросов на чтение от микросервиса A
. При
наступлении этих проблем обычно вводят в игру RO-реплики БД:

Поскольку микросервис A
не модифицирует записи в
БД, то добавлением реплик к БД можно решить практически все вопросы
масштабирования этого микросервиса.
Но вот вопрос: а что делать, когда микросервис B
приведёт master-БД к лимиту, определённому максимумом нагрузки на
запись (io-write)?
Вариантов решения этих проблем довольно немного. Все они сводятся к тому, чтоб распределить запись в БД по нескольким хостам. Используем схему шардинга или иной масштабируемый multi-master:

Вместо одной БД у нас имеется X
шардов БД,
позволяющих масштабировать нагрузку на запись, и к каждому шарду -
реплики (всего - Y
), позволяющие масштабировать
нагрузку на чтение.
Итого:
По мере роста нагрузки в нашем примере сами микросервисы претерпели немного изменений. Большинство изменений при масштабировании было в хранилище данных.
Если рассмотреть более обобщённо, то при масштабировании микросервисная архитектура сталкивается со следующими проблемами масштабирования:
-
Ограничения CPU на хостах
-
Ограничения IO в хранилищах данных
-
Ограничения пропускной способности сети между хостами
Способы преодоления этих проблем масштабирования ничем не отличаются от способов, применяемых в немикросервисных архитектурах. Мало того, третья проблема встречается в основном именно в микросервисной архитектуре.
Выводы
-
Микросервисная архитектура не является способом масштабирования проекта. Микросервисная архитектура - это способ разделения проекта на модули и инкапсуляции кода (и данных).
-
Основу масштабирования практически любого большого проекта следует искать в области хранения и обработки хранящихся данных.
Монолиты и микросервисы: граница
Если рассмотреть развитие аналогичного монолитного сервиса примерно в таком же ключе, как мы рассматривали выше развитие микросервиса, то в результате его развития будут пройдены те же стадии преодоления проблем. В итоге структура монолита будет включать в себя те же самые компоненты. А если взглянуть на серверное разделение, то будут включать в себя выделенный сервер (кластер серверов) авторизации и сервер регистрации пользователей. Однако, эта структура будет оставаться монолитной.
В чём же отличие? Почему монолит, разделённый на сервисы, остаётся монолитом? Потому что во всех его сервисах используется единая кодовая база.
Если один и тот же код, не будучи выделен в библиотеку, работает во множестве микросервисов, то это - монолитная архитектура.
Построение проектов с нуля: Монолит vs микросервис
Если не рассматривать вновь запускаемые проекты на лямбдах/FaaS, то можно отметить одну чуть ли не во всех проектах встречающуюся особенность:
Как правило, проект на стадии запуска реализации и на стадии запуска MVP отличается довольно сильно. Видение бизнес-развития проекта в стадии после MVP отличается от стартового ещё сильнее. И, чем больше времени проект развивается, тем сильнее эти отличия.
Бизнес-требования к стартующему проекту обычно меняются прямо в процессе реализации его MVP. Да, это не для всех случаев так, но для огромного пула стартапов это именно так.
Что из этого следует? Из этого следует эмпирическое правило: для запуска стартапов необходимо выбирать технологии, исходя из критериев:
-
в дальнейшем понятно, как масштабировать (в основном, это относится к хранилищу)
-
сравнительно просто рефакторить (это относится к выбору технологии построения кода)
-
простое покрытие автоматическими тестами
Для рефакторинга и простоты покрытия тестами монолиты подходят идеально - позволяют работать в режиме "сперва взлетаем, а затем думаем о том, какие крылья нам лучше использовать".
И, исходя из написанного, энергию вечного спора "монолит vs микросервис" на стадии запуска проекта надо направить в русло проработки хранилища данных с изначальной ориентацией на масштабирование. А в процессе развития монолит и микросервис будут иметь весьма похожую архитектуру. Настолько похожую, что отличить их друг от друга будет сложно.