Логотип компании Goodbit
Иван

Иван

Проектный руководитель

Архитектура микросервисов на примере Java: когда монолит не работает

Презентация
Соты

В практике ScienceSoft мы часто прибегаем к микросервисам при разработке больших и сложных веб-приложений, особенно облачных. Тем не менее, в начале сотрудничества некоторые наши заказчики задаются вопросом: «Почему мы должны отказываться от старого и проверенного монолита в пользу более затратной, трудоемкой разработки?» И они правы. Разработка на основе микросервисов гораздо более требовательна и ресурсоемка, но с учетом преимуществ, которые может получить бизнес, она может полностью окупиться.

Краткое обновление монолита и микросервисов

Монолитная архитектура

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

Архитектура микросервисов

Архитектура микросервисов — это частный случай сервис-ориентированной архитектуры (SOA). SOA — это стиль разработки программного обеспечения, в котором независимо развертываемые модули взаимодействуют друг с другом через протокол связи по сети. Что отличает микросервисы, так это степень, в которой эти модули связаны. Микросервисы более независимы и имеют как можно меньше общих элементов. Каждый сервер является атомарным по своей природе и выполняет одну определенную бизнес-функцию

Кейс внедрения микросервисов

Рука держит телефон

Кейс внедрения микросервисов

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


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

Что если мы выберем монолит

Когда пользователь открывает приложение для размещения заказа, система последовательно проверяет безопасность, регистрирует пользователя, обрабатывает его запрос, отправляет подтверждение заказа по электронной почте — проверяет успешное завершение сеанса. Что случилось? Все в порядке. Вырванное из контекста приложение просто работает так, как ожидалось, и выполняет свои основные функции. В идеальной ситуации. Однако вот что могло пойти не так на самом деле:

Один два три четыре
Один два три четыре
01

Полное отключение

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

02

Сложные обновления

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

03

Разочаровывающий UX

Поскольку наш монолит продолжает развиваться и расти, он сталкивается с все большей и большей нагрузкой. В монолите производительность практически не масштабируется. Плохая работа — одна из главных причин потери лояльности клиентов. Они не будут ждать и могут просто купить у конкурентов. К счастью, у этой проблемы есть решение, и вот что мы делаем. Теоретически, чтобы справиться с большой нагрузкой, мы могли бы продублировать существующую бизнес-логику. Затем мы получим два одинаковых сервера и распределим нагрузку между ними с помощью динамического балансировщика, который случайным образом перенаправит запрос на менее загруженный из них. Это означает, что если изначально один сервер обрабатывал, скажем, 200 000 QPS (запросов в секунду), что делало его слишком медленным, то теперь каждый из них обрабатывает по 100 000 QPS, не испытывая перегрузок. Однако обслуживание многих серверов довольно затратно, и дальнейшее масштабирование находится под вопросом..

Что меняется с микросервисами

Теперь давайте посмотрим, что из себя представляет приложение, спроектированное как набор из нескольких небольших и независимых частей:

01

Защита от полного отключения

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

02

Простые обновления

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

03

Отличный UX

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

Маршрут пользовательского запроса

Техническая часть проекта

Шаг 1. Разделяем

Техническая часть проекта

Шаг 1. Разделяем

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

Микросервис

Шаг 2. Настраиваем поток сообщений

Соединённые компьютеры

Шаг 2. Настраиваем поток сообщений

Однако разделение было лишь отправной точкой построения архитектуры, ориентированной на микросервисы. Чтобы сделать нашу систему успешной, было важнее и еще сложнее обеспечить бесперебойную связь между вновь созданными распределенными компонентами. Наши микросервисы обменивались данными либо через синхронизирующие протоколы HTTP/REST, либо через асинхронные протоколы AMQP, в зависимости от необходимости (при необходимости). Если вам нужно быстро узнать разницу между синхронными и асинхронными вызовами, я рекомендую проверить это объяснение — оно очень популярно среди наших клиентов и читателей блога.


Также пришлось ввести несколько промежуточных компонентов.

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

Абстракция

Сервер Eureka работал как наше открытие сервера. Так как у нас было несколько серверов на одну функцию (и их количество действительно вскоре увеличилось), необходимо было обнаружение серверов, чтобы вести список используемых профилей пользователей и серверов заказов и помогать им обнаруживать друг друга.

Сервера
Сервера

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

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

Поскольку мы не хотели, чтобы наши пользователи ждали положительного ответа от сервера уведомлений, чтобы продолжить работу, нам нужно было, чтобы уведомления по электронной почте отправлялись независимо. Для этого мы использовали брокер сообщений (RabbitMQ) в качестве посредника между сервером уведомлений и остальными серверами, которые позволяют промежуточный асинхронный обмен сообщениями.

Microservices Architecture

Являются ли микросервисы серебряной пулей?

Как и любой другой архитектурный подход, микросервисы не совсем безупречны. «Разделение за разделение» может оказаться не только бесполезным, но и негативно сказаться на вашем приложении. Чтобы узнать о возможных рисках, рекомендуем ознакомиться с подробным описанием плюсов и минусов микросервисов, подготовленным моим коллегой Геннадием Закалуским.

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

Достигайте больших результатов с помощью микросервисов

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