Чем быстрее идея воплотится в новый проект, тем больше шансов занять нишу, завоевать лояльность пользователей и, как следствие, стать успешнее конкурентов. Ускорить разработку и сделать её более гибкой и управляемой помогает микросервисная архитектура. Вместе с Дмитрием Горчаковым, руководителем отдела разработки РЕД-СОФТ, мы разобрали плюсы и минусы микросервисов, а ещё рассмотрели сценарии, как компании приходят к их внедрению.
Что такое микросервисная архитектура
Большинство проектов, особенно стартапов сначала выбирают монолит, так как нужен быстрый старт при минимальных ресурсах и не ясны перспективы. Но с увеличением размеров и сложности приложения управлять монолитом становится всё труднее. Любое изменение в монолитном приложении может иметь каскадный эффект, оказывая влияние на другие части приложения, что существенно усложняет интеграцию и развертывание в промышленной системе. Также присутствует риск отказа всего приложения в случае ошибки или деградации производительности модуля.
Альтернатива монолиту — микросервисы.
Микросервисная архитектура — один из подходов проектирования, при котором единое приложение строится как набор небольших сервисов. Каждый модуль работает в собственном процессе и взаимодействует с другими модулями. Модули работают независимо и построены вокруг бизнес-потребностей и выполняют определённую функцию. Например, хранят данные пользователей или отвечают за аутентификацию.
Впервые о микросервисах заговорили ещё в 2000-х годах, когда в США произошёл кризис электронных технологий. Тогда был бум на интернет-сервисы, но никто всерьёз не задумывался о масштабировании, а оборудование не было таким мощным. В один момент крупные сервисы не смогли справиться с возросшей нагрузкой и потеряли своих пользователей и инвестиции. Это привело к переоценке многих вещей в индустрии ПО, и уже к началу 2010-х микросервисы сформировались как концепция архитектуры. А к 2014-ому их начали внедрять крупные компании вроде Netflix, Amazon и Twitter.
Минусы микросервисного подхода
При кажущейся простоте и логичности деление большого монолитного приложения на самостоятельные сервисы — сложная техническая задача. Сам микросервисный подход не лишён недостатков, а его плюсы могут оборачиваться минусами:
Сложнее осуществлять мониторинг. Монолит один, и отслеживать, как он работает проще. Микросервисов сотни, а иногда тысячи, и уследить за каждым физически невозможно. Поэтому приходится уделять много внимания системам управления и мониторинга.
Каждый микросервис может использовать тот язык программирования и те технологии, что удобны команде, которая его разрабатывает. С одной стороны, это плюс — какие-то фреймворки и языки лучше заточены под конкретные вещи. Если мы делаем сервис обработки изображений или машинного обучения, можем не заострять внимание на технологиях монолита, а выбрать решение под задачу. С другой стороны, это минус — нужно как-то конфигурировать все микросервисы между собой и поддерживать «зоопарк» технологий.
Снижение доверия. Когда у нас сотни узлов, могут возникать проблемы с аутентификацией и авторизацией, поскольку есть вероятность подсоединения мошенников.
Сложности развёртывания. Чтобы требования по отказоустойчивости выполнялись, микросервисы нужно развёртывать на отдельных серверах. И здесь не работает подход: «Берём приложение, ставим и запускаем». Нужны системы оркестрации и деплоймента.
Плюсы микросервисного подхода
Один из основных плюсов микросервисов — повышение показателей доступности и отказоустойчивости. Когда монолит падает, он полностью перестаёт работать. В приложении с микросервисной архитектурой перестаёт работать только какая-то часть. Например, в интернет-магазине может сломаться корзина, но клиенты без проблем продолжат пользоваться каталогом, добавлять товары в избранное и т.д.
Ещё один плюс — повышение надёжности. Предположим, начинающий разработчик залил непроверенные изменения в прод. В случае с монолитом всё сразу упадёт, а с микросервисом сломается только участок системы, остальное будет работать.
Также важно, что в приложении с микросервисной архитектурой локализуются сложность и риски отказов, а производительность системы масштабируется по горизонтальному пути. Компоненты (узлы) автономны, а значит легче поддаются тестированию.
Как компания понимает, что пора внедрять микросервисы
Глобально можно выделить два подхода к разработке приложений. Первый — когда зрелая компания с опытным архитектором и командой разработки решает написать сервис, который будет выдерживать большие нагрузки. В этом случае уже есть понимание, что монолит не справится с поставленной задачей, нужен другой архитектурный подход. Примеры — «ВКонтакте», «Одноклассники», Mail.ru. Когда они планируют новые продукты, уже понимают, как будут их строить.
Второй подход — когда нужно быстро что-то написать и выкатить, чтобы начать доставлять фичи пользователям. В этом случае мы не знаем, выстрелит проект или нет, поэтому делать сразу микросервисы — оверинжиниринг. Обычно ждут первых результатов, а затем уже принимают архитектурные решения.
Признаки, что пора внедрять микросервисную архитектуру:
Рост нагрузки. У любого монолита есть предел масштабирования, так как он стоит на одной машине. Конечно, машины можно докупить, но эта опция не бесконечна и довольно затратна. Рост стоимости здесь не линеен, и в конечном счёте приведёт к пределу. Скажем, процессор в два раза мощнее, будет стоить не в два, а в четыре раза дороже.
Рост системы. Пользователи добавляются медленно, нагрузка не увеличивается, но фич добавляется всё больше, и постепенно система становится огромной и неповоротливой. Копится технический долг, кодовая база растёт, сложнее добавлять новые функции и при этом ничего не ломать. Разработка становится дороже.
Градация в данных. Появляется какой-то модуль, доступ к которому должен быть быстрее, чем к остальным. Например, мы хотим, чтобы в интернет-магазине доступ к популярным товарам стал быстрее. Делать быстрее доступ ко всем данным (корзине, каталогу и др.) слишком дорого. Вместо этого мы можем выделить под популярные товары отдельный микросервис. Он будет строиться на других технологиях и позволит ускорить доступ.
Появление новых задач. Приходит продакт и говорит, что нужно внедрить машинное обучение. Однако у разработчиков нет соответствующих компетенций для решения этой задачи. Нанимается отдельная команда дата-саентистов, и она пишет микросервис в отдельном репозитории, используя свой стек технологий и специальное оборудование.
Как перейти на микросервисы
Процесс разделения целого приложения на отдельные составляющие довольно сложный. Никто не даст вам время, чтобы разрушить монолит и затем спроектировать микросервисную архитектуру — это противоречит требованиям бизнеса. Разделение должно быть незаметно для пользователей и проходить в несколько этапов, когда работает монолит, а данные постепенно мигрируют в микросервисы.
Каких-то академических подходов к «распиливанию монолита» нет. Всё зависит от особенностей системы и поставленной задачи. Предположим, мы хотим выделить систему подписок в монолите. Вот один из сценариев, как это может быть:
Шаг 1. Выделяем отдельный узел и переносим туда логику. При необходимости делаем рефакторинг кода общей системы, чтобы она была меньше связана с другими модулями, а мы могли вынести её в отдельный узел. Разрабатываем способ взаимодействия.
Шаг 2. Живём «двойной жизнью», пока данные реплицируются. Убеждаемся, что всё работает правильно.
Шаг 3. Полностью отключаем функциональность от монолита и переносим её на микросервисы.
По такому же принципу можно работать и с другими функциональными модулями монолита.
Пример микросервиса Java
Сейчас я пишу учебный проект для курса Слёрма — сервис обмена валюты. И здесь явно присутствует разбиение на несколько узлов: сервис авторизации, модуль котировок, который показывает, сколько стоит валюта, модуль процессинга, где происходит обмен, историю и оповещения.
Всего пять модулей, но чтобы эти пять модулей правильно работали, добавляются ещё обслуживающие модули:
модуль маршрутизации, который будет управлять запросами;
балансировщик нагрузки, который будет следить, чтобы модель котировок не отказывала;
service registry, который поможет команде понять, какие сервисы есть, как работают, какие порты слушают и т.д.;
сервис конфигураций, который будет конфигурировать наши пять модулей;
сервис логирования и журналирования, который поможет быстро обнаруживать проблемы;
сервис трассировки, который позволит определить, где сейчас запрос;
сервис сбора метрик, который покажет, что и как у нас работает, какие бизнес-параметры выполняются.
То есть помимо пяти сервисов, которые выполняют какую-то полезную работу, нам нужны ещё узлы, которые будут играть обслуживающую роль.
Вместо заключения: частые ошибки при работе с микросервисами
Разбивая приложение на микросервисы, разработчики нередко допускаются одни и те же ошибки. Например, забывают о переходном периоде, из-за чего возникает ситуация, когда микросервисы ещё не готовы, а монолит уже упал. Или не заботятся об обслуживающих сервисах. Скажем, без метрик разобраться, что именно сломалось, будет очень сложно. И придётся потратить немало времени, чтобы найти проблему, так как запросы могут путешествовать по разным узлам. Многие бросаются сломя голову внедрять микросервисный подход, игнорируя такие вещи, из-за чего впоследствии возникают серьёзные проблемы. Разделять сложнее, чем объединять, и такому архитектурному рефакторингу подвержены только грамотно написанные и спроектированные модули.
Для тех, кто хочет разобраться в микросервисах
15 июля у нас стартует курс «Микросервисы и API на Java и Kotlin». Вы узнаете, как писать микросервисы и работать с приложениями на одних из самых популярных языков программирования. Познакомитесь с Java-фреймворком для разработки модулей микросервисов Spring Boot и прочими полезными инструментам и подходами.
Комментарии (13)
ProstakovAlexey
01.07.2022 23:06+1В java, python и др. Есть модули, пакеты. Разве это не способ боротся со сложностью кодовой базы? Выделить пакет отдельной команде и другим в него не ходить. Подключать через мавен. Чем такой подход плох? Микросерсисы хлопотрое дело, пока настроиль консул, мониторинг, облачную конфигурацию, кафки и прочее устанешь уже. У кого сотня микросервисов, как вы живете, страдаете?
shadek
02.07.2022 14:49Одно не исключает другое. У нас 200+ микросервисов, 2/3 используют общие пакеты/модули, которые делают отдельные команды. Кафки / хашикорп и все остальное так же нужно и для монолита да еще на разных контурах. Хлопотность микросервисов сильно преувеличена. Но согласен, это не серебряная пуля и не всем надо.
kalombo
03.07.2022 20:36Ну вот представьте всю экосистему Яндекса из сотен сервисов и тысяч программистов в одном монолитном репозитории. Как думаете где страданий больше?
ProstakovAlexey
04.07.2022 09:25Не представляю тысячи программирующих программистов в принципе и в одном репозитарии тем более, живу в провинции, у нас тут своя атмосфера. Обходимся малыми силами во всем, в т.ч. и программировании. Микросервисы тоже внедряем, ну чтобы как в Яндексе, только на команде в которой я работают 5 микросервисов на 4 чел. Поэтому страдаем, а вечером еще надо огород поливать.... Вот и спрашиваю как у остальных. Из вашего коментария так и не понял, что там в Яндексе, ок все или тоже?
kalombo
04.07.2022 11:13Я не из яндекса, но программистов в моей компании тоже много, поэтому я понимаю зачем нужны микросервисы.
Микросервисы тоже внедряем, ну чтобы как в Яндексе
Вот и спрашиваю как у остальных
Понимаете, нет универсального решения. Зачем вы равняетесь на яндекс, если у вас не тысячи программистов, а 5? А вообще у вас классический случай: "О, я услышал про волшебное чудо решение, которое решает все проблемы, давайте затащим его к нам" Когда вы внедряете микросервисную архитектуру нужно понимать, зачем вы её внедряете, чтобы быть как Яндекс? Звучит сомнительно. Если у вас всё прекрасно с монолитом, то делая микросервисы вы создаете себе кучу лишней работы непонятно зачем. Сам сталкивался с таким, когда тимлид, начитавшись про микросервисы, за каким-то чертом вынес rest-апи сервиса в отдельный сервис и поставил между ними очередь для синхронизации. Выхлоп - ноль, а зато столько работы и проблем сразу появилось. А вот когда у вас начинают возникать проблемы, ну представьте, допустим 50 человек работают над монолитом и каждый делает свой реквест, попробуй всё это проконтролируй. Или стало невозможно деплоить это монолитище, каждый раз танцы с бубнами. Или например, у вас есть возможность нанять программистов, но на другом стеке, вам выгодней по трудозатратам сделать 2 сервиса(5 программистов на джаве и 5 на питоне), чем собирать команду из 10 джавистов. То тогда есть повод задуматься о каком-то решении, необязательно сразу микросервисы, может вы сумеете как-то порешать проблемы малой кровью, разбив на модули. В общем вот вам тезис https://martinfowler.com/bliki/MonolithFirst.html
acmnu
04.07.2022 10:02ИМХО, Java хорошо переживает тысячи разрабов в одной репе благодаря всей этой сложившейся культуре с иерархией архитектор-->team lead --> senior --> middle --> junior.
Плюс там паттерны заточены под переиспользование кода с минимальными последствиями.Хотя усилий требуется не мало, конечно.
acmnu
04.07.2022 09:31+1У кого сотня микросервисов, как вы живете, страдаете?
Микросервисы это не столько архитектурная, сколько организационная проблема.
Нужна команда SRE. Программистам хода на продакшен нет. Никогда.
Нужен хороший CI/CD
Нужна строгость в сборке и деплойменте: -snapshot.jar недопустим (он так-то никогда недопустим, но кого это останавливает)
Как можно больше статических проверок контрактов. Как раз в Java c этим прекрасно (хотя я не Java прогер, могу ошибаться)
Как можно больше асинхрона для уменьшения связности.
SDET и QA Automation.
При выполнении этих и еще ряда условий (в том числе архитектурных) масштабируемость резко возрастает и увеличивается независимость команд. Хотя и не ясно нужно ли это конкретно вам.
Есть мифы, частично упомянутые в статье:
Сервис дискавери это сложнА! - Нет, не сложно, поскольку там очень шаблонированный код, особенно в наше время. Да и в большинстве случаев все ограничивается k8s и terraform и не доходит до Consul и Zookeeper
Мониторинг сложнее чем в монолите - Нет, не сложнее. Если не делать архитектурных глупостей, то мониторинг можно шаблонировать и выйдет примерно как с монолитом. А еще раскурить ELK и OpenTelementry. Ну и главная проблема мониторинга едина для всех подходов: необходимо каждый параметр описать и определить диапазоны, а на это уходит дикое количество времени.
Деплоймент это сложнА! - Для программистов да, хотя не то чтобы сложно, а непривычно и ненужно. Но для этого есть отдельные специалисты: SRE, DevOPS, QA
Имхо, с микросервисами есть одна ловушка: когда компания готова к микросервисам, разработка монолита для нее бессмысленна, но вы можете ошибаться, думая, что вы к этому готовы.
mafia8
02.07.2022 01:43+3Время от времени мы договаривались с редактором какой-нибудь провинциальной газеты и писали заметку. В этих заметках никогда не говорилось, что мы открыли новую технологию, — наоборот, мы делали вид, будто микросервисы давно всем известны. В них не содержалось никаких похвал, а всего лишь несколько слов о технологии, — порою в них преобладал позитив, порою описание недостатков, но всегда между строк чувствовалось, что переход на микросервисы неизбежен. (переделал Марка Твена)
arTk_ev
04.07.2022 13:06Если сервисов меньше 10 то можно сидеть на синглтонах. Если их меньше 50, то нужен gi-контенер для сервисов. Если их еще больше, то уже нужно разбивать на слои Model, View, VM.
Основная проблема микросервисов, в том что они противоречат SOLID, поэтому микросервисы обязаны быть независимы друг от друга, без иерархии, вечноживущие и всегда доступны. Ну и не допускать "ад синглтонов" и никаких "хелперов"
acmnu
04.07.2022 13:46вечноживущие и всегда доступны.
Можно эти свойства переложить на отдельные сервисы, например добавив MQ, или сделав связку MQ+ServerLess.
arTk_ev
04.07.2022 15:08Хотя микросервисы позаимствовали с веба, как там реализуют не очень знаком.
Обычно их помещают в DI-контейнеры, который уже внедряет фабрика. Иницилизируются они в строгом порядке сразу все, так как зависимости между ними в любом случае будут.
Контейнеры еще позволяют очень удобно тестировать и удалить все #ifdef в коде, которых и не должно быть в принципе.
Но непонятно как их масштабировать дальше, когда их уже сотни.
eldog
Вот с этим утверждением можно поспорить:
***
Пользователи добавляются медленно, нагрузка не увеличивается, но фич добавляется всё больше, и постепенно система становится огромной и неповоротливой. Копится технический долг, кодовая база растёт, сложнее добавлять новые функции и при этом ничего не ломать. Разработка становится дороже.
***
Если код невозможно поддерживать, значит проблемы с архитектурой. Переход на микросервисфы здесь не спасёт, приветсти код в порядок можно и нужно и на монолите.
AlexSpaizNet
В монолите очень сложно следить за тем кто и что делает и кто какие модули импортит.
Все таки в трушных микросервисах кодовая база на порядок меньше, доступ к коду имеют только реальные овнеры, так что никто ничего там не изменит без открытия нового пиара и никто не заюзает твой модуль так что тебе что бы что-то изменить нужно тестировать пол системы.
Да, в монолите нужно следить за архитектурой. И в любом монолите все начинается красиво. Папочки всякие, модули.... а потом через 5 лет и +100500 разработчиков через которых прошел этот код все превращается в кашу.
Микросервисы конечно приезжают со своими проблемами, но все таки ряд проблем они решают очень хороше.