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

В 2018 году экспертом, консультантом и архитектором Chris Richardson были опубликованы паттерны микросервисной архитектуры в одноименной книге Microservices Patterns и на сайте. На текущий момент описан 51 паттерн, которые разделены на 3 уровня (Application, Application Infrastructure, Infrastructure) и 15 категорий: Architectural style, Service boundaries, Refactoring to services, Service collaboration, Transactional messaging, Testing, Deployment, Cross-cutting concerns, Communication styles, External API, Service discovery, Reliability, Security, Observability, UI design.

Представленный набор паттернов помогает решать проблемы, связанные с архитектурой, разработкой и эксплуатацией, и позволяет разработчикам эффективно применять микросервисную архитектуру. Под паттерном понимается повторно используемое решение проблемы, возникающей в определенном контексте, а также описание последствий этого решения. Для структурирования паттернов использовался следующий формат:
  • Контекст (Context) — ситуация, в рамках которой применим данный паттерн;
  • Проблема (Problem) — проблема, которую решает паттерн;
  • Силы (Forces) — факторы, ограничения и соображения, которые необходимо учитывать и которые могут влиять на применимость решения;
  • Решение (Solution) — предлагаемое паттерном решение;
  • Последствия (Consequences) — описание последствий применения паттерна: положительные результаты, отрицательные результаты и проблемы, возникающие в результате применения паттерна;
  • Связанные паттерны (Related patterns) — паттерны, предназначенные для решения проблем, порождаемых данным паттерном, а также альтернативные способы решения той же проблемы.

Полный список из 51 паттерна микросервисной архитектуры с описанием и разделенных на 15 категорий:
Архитектурный стиль (Architectural style). Какой архитектурный стиль следует выбрать для приложения?
  • Monolithic architecture — проектирование приложения как единого развертываемого компонента;
  • Microservice architecture — проектирование приложения как набора независимо развертываемых, слабо связанных сервисов.

Границы сервисов (Service boundaries). Как декомпозировать приложение на сервисы?
  • Decompose by business capability — определение сервисов, соответствующих бизнес возможностям;
  • Decompose by subdomain — определение сервисов, соответствующих поддоменам DDD (Domain-Driven Design);
  • Self-contained Service — проектирование сервисов таким образом, чтобы они обрабатывали синхронные запросы без ожидания ответов от других сервисов;
  • Service per team — каждый сервис принадлежит одной команде, которая несет полную ответственность за внесение изменений.

Рефакторинг в сторону сервисов (Refactoring to services). Как выполнить поэтапный переход от существующего приложения к сервисам?
  • Strangler Application — модернизация приложения за счет поэтапной разработки нового (strangler) приложения вокруг легаси приложения;
  • Anti-corruption layer — определение слоя, выполняющего преобразование между двумя доменными моделями.

Взаимодействие сервисов (Service collaboration). Как реализовать сценарии, охватывающие несколько сервисов?
  • Database per Service — у каждого сервиса есть собственная приватная база данных;
  • Shared database — сервисы используют общую базу данных;
  • Saga — использование саг (sagas), представляющих собой последовательности локальных транзакций, для поддержания согласованности данных между сервисами;
  • Command-side replica — поддержание доступной для запросов реплики данных в сервисе, который реализует команду;
  • API Composition — реализация запросов путем вызова сервисов, владеющих данными, и выполнения объединения данных в памяти;
  • CQRS (Command Query Responsibility Segregation) — реализация запросов за счет поддержки одного или нескольких материализованных представлений, доступных для эффективного выполнения запросов;
  • Domain event — публикация события при каждом изменении данных;
  • Event sourcing — сохранение агрегатов в виде последовательности событий.

Транзакционный обмен сообщениями (Transactional messaging). Как отправлять сообщения в рамках транзакции базы данных?
  • Transactional outbox — сервис, отправляющий сообщения, сначала сохраняет сообщение в базе данных как часть транзакции, которая обновляет бизнес-сущности;
  • Transaction log tailing — чтение журнала транзакций базы данных и публикация каждого сообщения или события, добавленного в outbox, в брокер сообщений;
  • Polling publisher — публикация сообщений путем опроса таблицы outbox в базе данных.

Тестирование (Testing). Как тестировать сервисы?
  • Consumer-driven contract test — набор тестов для сервиса, который разрабатывается разработчиками другого сервиса, использующего этот сервис;
  • Consumer-side contract test — набор тестов для клиента сервиса (например, другого сервиса), который проверяет возможность корректного взаимодействия с сервисом;
  • Service component test — набор тестов, проверяющий сервис изолированно с использованием тестовых двойников (test doubles) для всех сервисов, которые он вызывает.

Развертывание (Deployment). Как развертывать сервисы приложения?
  • Multiple service instances per host — развертывание нескольких экземпляров сервиса на одном хосте;
  • Service instance per host — развертывание каждого экземпляра сервиса на отдельном хосте;
  • Service instance per VM — развертывание каждого экземпляра сервиса в отдельной виртуальной машине;
  • Service instance per Container — развертывание каждого экземпляра сервиса в отдельном контейнере;
  • Serverless deployment — развертывание сервиса с использованием serverless-платформы;
  • Service deployment platform — развертывание сервисов с использованием высокоавтоматизированной платформы развертывания, предоставляющей абстракцию сервиса.

Сквозные аспекты (Cross-cutting concerns). Как работать со сквозными аспектами?
  • Microservice chassis — фреймворк, который обрабатывает сквозные аспекты и упрощает разработку сервисов;
  • Externalized configuration — вынесение всей конфигурации, такой как расположение базы данных и учетные данные;
  • Service Template — шаблон, реализующий стандартные сквозные аспекты и предназначенный для копирования разработчиком с целью быстрого начала разработки нового сервиса.

Стили коммуникации (Communication styles). Какие механизмы сервисы используют для коммуникации друг с другом и с внешними клиентами?
  • Remote Procedure Invocation — использование протокола на основе RPI для межсервисной коммуникации;
  • Messaging — использование асинхронного обмена сообщениями для межсервисной коммуникации;
  • Domain-specific protocol — использование предметно-ориентированного протокола;
  • Idempotent Consumer — обеспечение способности потребителей сообщений корректно обрабатывать многократные вызовы с одним и тем же сообщением.

Внешний API (External API). Как внешние клиенты взаимодействуют с сервисами?
  • API gateway — сервис, предоставляющий каждому клиенту унифицированный интерфейс для доступа к сервисам;
  • Backend for front-end — отдельный API gateway для каждого типа клиента.

Обнаружение сервисов (Service discovery). Как клиент сервиса на основе RPI определяет сетевое расположение экземпляра сервиса?
  • Client-side discovery — клиент обращается к реестру сервисов для определения расположения экземпляров сервисов;
  • Server-side discovery — маршрутизатор обращается к реестру сервисов для определения расположения экземпляров сервисов;
  • Service registry — база данных, содержащая сведения о расположении экземпляров сервисов;
  • Self registration — экземпляр сервиса самостоятельно регистрируется в реестре сервисов;
  • 3rd party registration — сторонний компонент регистрирует экземпляр сервиса в реестре сервисов.

Надежность (Reliability). Как предотвратить каскадное распространение сетевых или сервисных отказов на другие сервисы?
  • Circuit Breaker — вызов удаленного сервиса через прокси, который немедленно прекращает вызовы при превышении порогового уровня отказов удаленных вызовов.

Безопасность (Security). Как передавать идентичность инициатора запроса сервисам, которые обрабатывают этот запрос?
  • Access Token — токен, который безопасно хранит информацию о пользователе и передается между сервисами.

Наблюдаемость (Observability). Как понять поведение приложения и устранять проблемы?
  • Log aggregation — агрегация логов приложения;
  • Application metrics — инструментирование кода сервиса для сбора статистики по операциям;
  • Audit logging — запись действий пользователей в базу данных;
  • Distributed tracing — назначение внешним запросам уникальных идентификаторов, передаваемых между сервисами, и сбор информации об их обработке в централизованном сервисе;
  • Exception tracking — отправка всех исключений в централизованный сервис, который агрегирует и отслеживает исключения и уведомляет разработчиков;
  • Health check API — API сервиса, который возвращает состояние работоспособности сервиса и предназначен, например, для опроса системой мониторингаж;
  • Log deployments and changes — логирование каждого развертывания и каждого изменения в (production) окружении/

Проектирование UI (UI design). Как реализовать экран или страницу пользовательского интерфейса, отображающую данные из нескольких сервисов?
  • Server-side page fragment composition — формирование веб-страницы на сервере путем композиции HTML фрагментов, сгенерированных несколькими веб-приложениями, привязанными к отдельным бизнес-возможностям или поддоменам;
  • Client-side UI composition — формирование пользовательского интерфейса на клиенте путем композиции UI фрагментов, отрисованных несколькими UI компонентами, привязанными к отдельным бизнес-возможностям или поддоменам.

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

Мы помогаем CTO, архитекторам и техническим лидерам декомпозировать системы на сервисы, определять границы сервисов и зоны ответственности команд, выбирать и внедрять паттерны взаимодействия сервисов и обеспечения согласованности данных, выстраивать наблюдаемость (Observability), надежность (Reliability), безопасность (Security), тестирование (Testing) и практики развертывания (Deployment). По результатам аудита формируем набор приоритетных рекомендаций и дорожную карту изменений, а также при необходимости проводим обучение по ключевым паттернам и практикам.