В последние годы понятие микросервисов получило широкое распространение. Многие программные продукты построены на основе данной архитектуры. В этой статье мы поговорим о том, для чего нужны микросервисы, какие проблемы можно решить с их помощью. Но для начала поговорим о том, как было плохо раньше. Традиционно, успешно развивающиеся приложения имели монолитную архитектуру, то есть в случае с мобильными приложениями, состоящий из единого файла в формате Java WAR (Web Application Archive). Это широко распространенный пример монолитного стиля программной архитектуры, в соответствии с которым система структурируется в виде одного исполняемого файла.  С годами это приложение стало большим и сложным, превратившись в  «беспорядочно структурированные, растянутые, неряшливые, словно перемотанные на скорую руку изоляционной лентой и проводами, джунгли спагетти-кода» (с). Со временем темпы выпуска новых версий замедлились. Приложение обросло множеством устаревших фреймворков.  Но стоит заметить, что в монолитной архитектуре, как таковой нет ничего плохого. Так для небольших приложений важным преимуществом данной архитектуры является простота разработки – все инструменты сосредоточены на построении единого приложения. При этом, даже в случае внесений серьезных изменений, таких как замена кода или структуры базы данных вы можете без особого труда все пересобрать и получить результат. Аналогично легко можно протестировать и развернуть полученное приложение.      Однако, если приложение, что называется “зашло”, то есть понравилось пользователям, оно стало развиваться, код стал обрастать новыми функциями, увеличилось число программистов, участвующих в разработке. А это не только ускорило темпы разрастания кодовой базы, но и повысило накладные расходы на администрирование. Кроме того, начинают возникать проблемы с масштабированием. Так, требования к ресурсам у разных программных модулей начинают конфликтовать между собой. Одним компонентам требуется больше памяти, другим больше процессорных ресурсов, но так как все они находятся внутри одного приложения приходится идти на компромисс, снижая требования для всех компонентов.  И наконец “зависимость от зависимостей”. Наше монолитное приложение использует в своей работе определенный стек технологий, который со временем естественно устаревает.    При этом разработчикам сложно переходить на новые фреймворки и языки программирования. Переписать все монолитное приложение, применив новые и, предположительно, лучшие технологии, было бы чрезвычайно дорого и рискованно. Как следствие, программистам приходится работать с теми инструментами, которые они выбрали при запуске проекта. Из-за этого они часто обязаны поддерживать код, написанный с помощью устаревших средств. Для микросервисной архитектуры можно найти множество определений. В этой сттаье мы предлагаем следующее: микросервисная архитектура - это стиль проектирования, который разделяет приложение на отдельные сервисы с разными функциями. Каждый сервис должен иметь четкий перечень связанных между собой обязанностей. Таким образом, в микросервисной архитектуре единицей модульности является сервис. Взаимодействие с ними осуществляется с помощью API, что позволяет поддерживать модульность.  Одним из основных достоинств микросервисной архитектуры является возможность непрерывной доставки и развертывания крупных, сложных приложений. Достигается это в первую очередь за счет автоматизации тестирования, позволяющего выявить большее число ошибок. Так как все сервисы как правило небольшого размера, написание автоматических тестов значительно упрощается, а их выполнение занимает меньше времени. Меньше ошибок – стабильнее приложение.  Также, каждый сервис может быть развернут независимо от остальных. Так в случае, если разработчикам необходимо внести изменения в сервис, они могут это сделать, не координируясь с другими командами, что существенно упрощает и ускоряет процесс внесения изменений. Кроме того, отдельные команды разработчиков могут отвечать за разработку отдельных сервисов, Это позволяет разрабатывать и масштабировать сервисы отдельно от остальных команд, тем самым экономя время, необходимое на выпуск готового приложения.  Данная архитектура не случайно называется МИКРОсервисной, так как каждый сервис является небольшим, содержит, как правило, не более пары сотен строк кода. В результате работа с таким кодом упрощается, все сервисы запускаются намного быстрее, чем тяжелое, монолитное приложение, и работа с приложением в целом ускоряется. В микросервисной архитектуре каждый сервис можно масштабировать отдельно. Если в монолите нам требовался определенный компромисс по железу для всех компонентов, то в микросервисах мы можем развернуть отдельные сервисы на том оборудовании, которое подходим именно для них. Отдельно хотелось бы отметить устойчивость микросервисных архитектур к различным неполадкам. Так, если в одном сервисе произошла утечка памяти, то она затронет только этот сервис. Но если наша микросервисная архитектура работает на Kubernetes то ситуация становится еще интереснее. K8s увидит, что “потекший” контейнер не отвечает и автоматически перезагрузит его. Тем самым будет обеспечена работоспособность данного сервиса. Это конечно не очень удачный пример с точки зрения программирования, потому что в результате разработчики позже обнаружат и исправят ошибку (когда наконец-то посмотрят в логи), но это пример демонстрирующий устойчивость микросервисной архитектуры. Как уже упоминалось ранее, одна из проблем монолита это зависимость от стека используемых технологий. Микросервисы в значительной степени избавлены от таких ограничений. При создании нового сервиса разработчики могут выбрать наиболее подходящие средства разработки, языки и фреймворки.  Так как микросервисы по определению не содержат много строк кода, мы можем позволить себе переписать сервис на другом языке и посмотреть, насколько эффективно все это будет работать. В случае, если результат нас не устроит мы можем отказаться от изменений не ставя под угрозу весь проект. Конечно, микросервисная архитектура тоже не идеальна и у нее есть свои недостатки. Прежде всего нужно правильно декомпозировать решение на сервисы. Есть опасность попасть в ловушку распределенного монолита – когда мы неправильно разделили систему и у нас получился набор связанных между собой сервисов, которые необходимо развертывать вместе. В результате получаем недостатки и монолита и микросервиса. При создании микросервисной архитектуры у нас возникает проблема межпроцессного взаимодействия. Код сервисов должен быть готов к недоступности или задержкам в работе других сервисов. Также возникают сложности с реализацией сценариев, охватывающих несколько сервисов. Необходимо продумывать вопросы согласованности данных между сервисами.  Кроме того, тестирование микросервисного приложения в целом задача непростая. Можно разработать тесты для отдельных сервисов, но вот тестирование приложения в целом сложнее, чем в случае с монолитом. Ну и наконец, администрирование микросервисов это тоже совсем не просто. Разнородные сервисы нуждаются в едином управлении. Но здесь нам на помощь могут прийти такие инструменты оркестрации как Kubernetes. Таким образом, проектирование приложения на основе микросервисной архитектуры является достаточно сложной и трудоемкой задачей, требующей высокой квалификации прежде всего от архитекторов, проектирующих решение. В этой статье мы только начали рассмотрение микросервисной архитектуры приложений. За кадром остались такие интересные темы, как языки проектирования и шаблонов, межпроцессное взаимодействие и многое другое.   Приглашаю вас на бесплатный вебинар, в процессе которого мы составим дорожную карту для самостоятельного изучения архитектурных принципов и паттернов проектирования. Регистрация на вебинар