Школа анализа
и проектирования
информационных систем Бескова и Богачёвой
new
🔥  Регулярные онлайн-конференции школы SE по проектированию информационных систем для бизнеса. Подробнее
Теперь в SE доступна оплата обучения в рассрочку для частных лиц. Выберите обучение и разделите его стоимость на удобные платежи с Яндекс Сплит.
Теперь в SE доступна оплата обучения в рассрочку для частных лиц. Выберите обучение и разделите его стоимость на удобные платежи с Яндекс Сплит.
Теперь доступна оплата обучения в рассрочку для частных лиц. Выберите обучение и разделите его стоимость на удобные платежи с Яндекс Сплит.
🚀 Все воркшопы школы
за 60 тыс. руб!

Уникальная возможность посетить все воркшопы школы по одному абонементу. Экономия 109 тыс. руб.

Подробнее
Марк Ричардс

Книга «Паттерны архитектуры программного обеспечения»

Общие шаблоны архитектуры и способы их применения

Исходный текст, 2015 / Русский перевод, 2023

Оглавление книги
Глава 4

Паттерн архитектуры микросервисов

Архитектура микросервисов быстро завоёвывает популярность в отрасли как жизнеспособная альтернатива монолитным приложениям и сервис-ориентированным архитектурам. Поскольку этот архитектурный паттерн всё ещё развивается, в отрасли существует много путаницы в том, что это за паттерн и как он реализуется. Этот раздел работы предоставит вам ключевые концепции и базовые знания, необходимые, чтобы понять преимущества (и компромиссы) этого важного архитектурного шаблона и того, подходит ли он для вашего приложения.
Описание паттерна
Независимо от выбранной вами топологии или стиля реализации, существует несколько базовых концепций, которые применяются к основному архитектурному паттерну. Первая из этих концепций — это понятие автономно-развёрнутых единиц (separately deployed units). Как показано на Рисунке 4-1, каждый компонент архитектуры микросервисов развёртывается как автономная единица, что упрощает развёртывание благодаря эффективному и оптимизированному конвейеру доставки, повышает масштабируемость и обеспечивает высокую степень разделения компонентов в вашем приложении.
Возможно наиболее важной концепцией, которую необходимо понять при использовании этого паттерна — это понятие сервис-компонента (service component). Вместо того, чтобы думать о сервисах в рамках архитектуры микросервисов, лучше думать о сервис-компонентах, которые могут варьироваться по гранулярности от одного модуля до большой части приложения. Сервис-компоненты содержат один или несколько модулей (например, классы Java), которые представляют функцию с одним единственным назначением (например, предоставление прогноза погоды для города или посёлка), либо независимую часть большого бизнес-приложения (например, размещение акций или расчёт тарифов автострахования). Разработка правильного уровня гранулярности сервис-компонентов является одной из самых больших проблем в архитектуре микросервисов. Более подробно эта проблема обсуждается в следующем подразделе, посвящённом оркестрации сервис-компонентов.

Рисунок 4-1. Базовый паттерн архитектуры микросервисов

Другая ключевая концепция в структуре архитектуры микросервисов заключается в том, что она представляет собой распределённую архитектуру. Это означает, что все компоненты архитектуры полностью автономны друг от друга и доступны через какой-либо протокол удалённого доступа (например, JMS, AMQP, REST, SOAP, RMI, и т. д.). Распределённый характер этого архитектурного паттерна позволяет добиться превосходных характеристик масштабируемости и развёртывания.
Одна из интересных особенностей архитектуры микросервисов состоит в том, что она возникла из проблем, существующих в других распространённых архитектурных паттернах, а не создавалась как самостоятельное концептуальное решение со своими собственными возможными проблемами реализации. Стиль архитектуры микросервисов развился из двух основных источников: монолитных приложений, разработанных с использованием паттерна слоистой архитектуры, и распределённых приложений, разработанных с использованием паттерна сервис-ориентированной архитектуры.
Эволюционный путь от монолитных приложений к микросервисному архитектурному стилю был вызван, прежде всего, развитием культуры непрерывной доставки (Continuous Delivery), а именно — появления конвейера непрерывной доставки, от разработки кода к его эксплуатации, который упрощает развёртывание приложений. Монолитные приложения обычно состоят из тесно-связанных компонентов, которые являются частью единого развёртываемого модуля, что делает изменение, тестирование и развёртывание приложения громоздким и сложным. Из этой ситуации в своё время сначала родилась культура циклов «ежемесячного развёртывания» (monthly deployment), обычно встречающихся в большинстве крупных ИТ-компаний. Эти факторы обычно приводят к созданию хрупких приложений, которые выходят из строя каждый раз, когда релизится что-то новое. Архитектурный паттерн микросервисов решает эти проблемы путём разделения приложения на несколько разворачиваемых модулей (сервис-компонентов), которые могут быть индивидуально разработаны, протестированы и развёрнуты независимо от других сервис-компонентов.
Другой путь эволюции, который привёл к появлению архитектуры микросервисов, связан с проблемами в приложениях, реализующих паттерн сервис-ориентированной архитектуры (Service-Oriented Architecture). Несмотря на то, что сервис-ориентированная архитектура очень мощная и предлагает беспрецедентные уровни абстракции, разнородные возможности подключения, оркестрацию сервисов и обещает согласование бизнес-целей с возможностями ИТ, она, тем не менее, остаётся сложной, дорогой, часто используемой, трудной для понимания и реализации, избыточной для большинства приложений. Стиль архитектуры микросервисов решает эту проблему путём упрощения понятия сервиса, устранения необходимости оркестрации и упрощения подключения и доступа к сервис-компонентам.
Топологии паттерна
Хотя существуют десятки способов реализации паттерна архитектуры микросервисов, три основные топологии выделяются как наиболее распространённые и популярные:
— топология на основе REST API (API REST-based),
— топология на основе приложений REST (application REST-based) и
— топология централизованного обмена сообщениями (centralized messaging).
Топология на основе REST API (API REST-based) полезна для веб-сайтов, которые предоставляют небольшие, самодостаточные отдельные сервисы через API (application programming interface). Эта топология, показанная на Рисунке 4-2, состоит из очень мелких сервис-компонентов (отсюда и название микросервисы), которые содержат один или два модуля, выполняющих определенные бизнес-функции независимо от остальных сервисов. В этой топологии доступ к микросервисам обычно осуществляется с помощью REST интерфейса, реализованного через отдельно развёрнутый веб-интерфейс API. Примеры этой топологии включают в себя распространённые облачные RESTful веб-сервисы, которые предназначены для выполнения одной цели, созданные такими компаниями, как Yahoo, Google и Amazon.

Рисунок 4-2. Топология на основе REST API

Топология на основе приложений REST отличается от топологии на основе REST API тем, что клиентские запросы принимаются через традиционные веб-интерфейсы или через «толстые клиенты» (толстый клиент — это приложение, обеспечивающее расширенную функциональность независимо от центрального сервера, часто сервер в этом случае является лишь хранилищем данных, а вся работа по обработке и представлению этих данных переносится на машину клиента), а не по простому API.
Как показано на Рисунке 4-3, слой пользовательского интерфейса развёртывается как отдельное веб-приложение, которое дистанционно обращается к отдельно развёрнутым сервис-компонентам (бизнес-функциональность) через простые интерфейсы на основе REST. Сервис-компоненты в этой топологии отличаются от компонентов в топологии на основе REST API тем, что эти сервис-компоненты более крупны в своих размерах и представляют собой небольшую часть бизнес-приложения, в отличие от мелких сервисов, служащих только одной узкой цели. Такая топология характерна для бизнес-приложений размером от малого до среднего и которые имеют относительно низкую степень сложности.

Рисунок 4-3. Топология на основе приложений REST

Другим распространённым подходом в рамках паттерна архитектуры микросервисов является топология централизованного обмена сообщениями. Эта топология (показана на Рисунке 4-4) аналогична топологии предыдущего приложения на основе REST, за исключением того, что вместо использования REST для дистанционного доступа используется облегчённый централизованный брокер сообщений (например, ActiveMQ, HornetQ и т.д.). Очень важно при рассмотрении этой топологии не путать её с паттерном сервис-ориентированной архитектуры или считать её «SOA-Lite». Облегчённый брокер сообщений в этой топологии не выполняет никакой оркестрации, преобразования или сложной маршрутизации. Скорее это просто облегчённый транспорт для доступа к дистанционным сервис-компонентам.
Топология централизованного обмена сообщениями обычно встречается в крупных бизнес-приложениях или приложениях, требующих более сложного контроля над транспортным уровнем между пользовательским интерфейсом и сервис-компонентами. Преимущества этой топологии по сравнению с простой топологией на основе REST, рассмотренной ранее, заключаются в расширенных механизмах организации очередей, асинхронном обмене сообщениями, мониторинге, обработке ошибок и лучшей балансировке нагрузки и масштабируемости. Проблемы единой точки отказа и узких мест в архитектуре, обычно связанные с централизованным брокером, решаются с помощью кластеризации и объединения брокеров (разделение одного брокера на несколько экземпляров для распределения проходящего потока сообщений в зависимости от функциональных областей системы).

Рисунок 4-4. Топология централизованного обмена сообщениями

Избегайте зависимостей и оркестрации
Одной из основных проблем архитектурного паттерна микросервисов является определения правильного уровня гранулярности сервис-компонентов. Если сервис-компоненты получаются слишком крупными, то вы не сможете воспользоваться преимуществами этого архитектурного шаблона (такими как высокие показатели развёртывания, масштабируемости, тестируемости и слабые зависимости). Однако, слишком мелкие сервис-компонеты приведут к необходимости оркестрации сервисов, что превратит вашу лёгкую, стройную и бережливую архитектуру микросервисов в тяжеловесную сервис-ориентированную архитектуру, вместе со всей сложностью, путаницей, расходами и оплошностями, обычно присущими приложениям на основе сервис-ориентированной архитектуре.
Если вы обнаружите, что вам нужна оркестрация сервис-компонентов из пользовательского интерфейса или слоя API приложения, то ваши сервис-компоненты слишком мелкие. Аналогично, если вы обнаружите, что для обработки одного запроса вам необходимо проводить межсервисное взаимодействие между сервис-компонентами, то они либо слишком мелкие, либо неправильно разделены с точки зрения бизнес-функциональности.
Межсервисное взаимодействие, которое может привести к нежелательным соединениям между компонентами, может быть проведено через общую базу данных. Например, если сервис-компоненту, обрабатывающему интернет-заказы нужна информация о клиенте, он может обратиться к базе данных, чтобы извлечь необходимые данные, а не вовлекать функционал сервис-компонента клиента.
Общая база данных может удовлетворить потребности в данных, но как насчет общей функциональности? Если сервис-компонент нуждается в функциональных возможностях, содержащихся в другом сервис-компоненте, или общих для всех сервис-компонентов, иногда можно скопировать общую функциональность между сервис-компонентами. Такими действиями вы нарушаете принцип «DRY» (don’t repeat yourself) — «не повторяйся». Это довольно распространённая практика в большинстве бизнес-приложений, реализующих архитектурный паттерн микросервисов, когда приходится соглашаться на избыточность повторения небольших частей бизнес-логики ради сохранения независимости сервис-компонентов и разделения их развёртывания. В эту категорию повторяющегося кода могут попасть небольшие обслуживающие классы (utility services).
Если вы обнаружите, что независимо от уровня гранулярности сервис-компонентов вам всё равно не удаётся избежать оркестрации сервис-компонентов, то это явный признак того, что этот архитектурный паттерн не подходит для вашего приложения. Из-за распределённого характера этого шаблона очень трудно поддерживать единую транзакционную работу между сервис-компонентами. Такая практика потребует использования фреймворка компенсации транзакций с целью отката транзакций (rolling back transactions), что значительно усложняет этот простой и элегантный архитектурный паттерн.
Рекомендации
Архитектурный паттерн микросервисов решает многие общие проблемы, встречающиеся как в монолитных приложениях, так и сервис-ориентированных архитектурах. Поскольку основные компоненты приложения разделяются на более мелкие, отдельно развёртываемые единицы, приложения, построенные с использованием архитектурного паттерна микросервисов, обычно более устойчивые, обеспечивают повышение характеристики масштабируемости и могут легче поддерживать непрерывную доставку (Continuous Delivery).
Ещё одним преимуществом этого паттерна является то, что он обеспечивает возможность развёртывания в режиме реального времени, тем самым значительно снижая потребность в традиционных ежемесячных развёртываниях или развёртываниях «большого взрыва» (big bang) по выходным. Поскольку изменения, как правило, изолированы на уровне конкретных сервис-компонентов, необходимо развёртывать только те сервис-компоненты, которые изменяются. Если у вас есть только один сервис-компонент, вы можете написать специализированный код в приложении пользовательского интерфейса, чтобы обнаружить активное оперативное развёртывание (hot-deployment) и перенаправить пользователей на страницу с ошибкой или страницу ожидания. Кроме того, можно заменить несколько экземпляров сервис-компонентов во время развёртывания в реальном времени. Это обеспечивает непрерывную доступность во время циклов развёртывания (что очень сложно сделать с помощью паттерна слоистой архитектуры).
Последняя рекомендация, которую стоит принять во внимание про паттерн архитектуры микросервисов — так как этот паттерн является распределённой архитектурой он наследует некоторые из тех же самых сложных проблем, которые встречаются в паттерне событийно-ориентированной архитектуре. В частности, проблемы создания, обслуживания и управления контрактами, контроля и обеспечения доступности распределённых узлов, дистанционной аутентификации и авторизации.
Анализ паттерна
Далее приведены оценки и общий анализ характеристик паттерна архитектуры микросервисов. Оценка для каждой из характеристик основана на естественном проявлении данной характеристики, как способности, качества (архитектуры), проявляющейся при реализации паттерна, а также на том, чем в целом известен этот паттерн. Для сопоставительного сравнения и получения представления о том, как этот паттерн соотносится с остальными паттернами нашего обзора, обратитесь к Приложению А в конце книги.
Общая адаптивность (Overall agility)
Оценка: Высокая
Анализ: Общая адаптивность — это способность быстро реагировать на постоянно меняющуюся среду. Благодаря понятию отдельно развёрнутых единиц, внесение изменений обычно изолировано в отдельных сервис-компонентах, что обеспечивает быстрое и простое развёртывание. Также, приложения, созданные с использованием этого паттерна, очень слабо связаны друг с другом, что помогает облегчить внесение изменений.
Простота развёртывания (Ease of deployment)
Оценка: Высокая
Анализ: Характеристики развёртывания шаблона микросервисов оцениваются очень высоко благодаря крупным и независимым дистанционным сервисам. Сервисы обычно развёртываются как отдельные единицы ПО, что даёт возможность выполнять «оперативные развёртывания» (hot deployments) в любое время дня и ночи. Общий риск развёртывания также значительно снижается, так как сбои при развёртывании могут быть устранены быстрее и влияют только на функционирование обновляемого сервиса. Поэтому все остальные функции системы продолжают работать как ни в чём ни бывало.

Тестируемость
Оценка: Высокая
Анализ: Благодаря разделению и изоляции функциональных возможностей бизнес на независимые приложения, тестирование может быть ограничено, что позволяет проводить его более целенаправленно. Регрессионное тестирование для конкретного сервис-компонента намного проще и целесообразнее, чем регрессионное тестирование для всего монолитного приложения. Кроме того, поскольку сервис-компоненты в этом шаблоне слабо связаны, то с точки зрения разработки, гораздо меньше шансов внести изменение, которое нарушит работу другой части приложения. Это облегчает нагрузку на тестирование, исключая необходимость перепроверять всё приложение целиком из-за одного небольшого изменения.
Производительность
Оценка: Низкая
Анализ: Хотя вы можете создавать приложения, реализованные на основе этого шаблона, которые будут работать очень хорошо, в целом этот шаблон не подходит для высокопроизводительных приложений. Причина этому — распределённый характер паттерна архитектуры микросервисов.
Масштабируемость
Оценка: Высокая
Анализ: Поскольку приложение разделено на отдельно развёрнутые единицы, каждый сервис-компонент может быть масштабирован по отдельности. Это обеспечивает возможность точной настройки масштабирования всего приложения. Например, область администрирования приложения для торговли акциями может не нуждаться в масштабировании из-за низкого количества пользователей этой функциональности. И наоборот, сервис-компонент размещения сделок может нуждаться в масштабировании из-за высокой пропускной способности, необходимой большинству приложений для торговли.
Простота разработки
Оценка: Высокая
Анализ: Поскольку функциональные возможности выделены в отдельные сервис-компонеты, их разработка становится более простой из-за меньшего и изолированного объёма. Гораздо меньше вероятность того, что разработчик внесёт изменения в один сервис-компонент, которые повлияют на другие сервис-компонеты, соответственно это снижает необходимость координации между разработчиками и командами разработки.

■ Другие статьи по теме Архитектура

Показать еще