Перейти к основному содержимому

6.11. Модельная архитектура микросервисов

Разработчику Архитектору Аналитику

Модельная архитектура микросервисов

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

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

Уровни моделиной архитектуры микросервисов

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

Уровень сервисов

Уровень сервисов — это ядро микросервисной архитектуры. Он состоит из самих микросервисов, каждый из которых:

  • Реализует одну или несколько тесно связанных бизнес-возможностей.
  • Обладает собственной логикой обработки данных и правилами предметной области.
  • Имеет собственный жизненный цикл: его можно разрабатывать, тестировать, развёртывать и обновлять независимо от других сервисов.
  • Взаимодействует с другими сервисами исключительно через сетевые вызовы, чаще всего посредством HTTP/REST, gRPC или асинхронных сообщений через брокеры.
  • Хранит свои данные в выделенном хранилище, недоступном напрямую другим сервисам.

Каждый микросервис инкапсулирует определённую часть бизнес-логики и данные, необходимые для её выполнения. Это достигается за счёт принципа ограниченного контекста (bounded context), заимствованного из методологии Domain-Driven Design. Ограниченный контекст определяет границы ответственности сервиса и гарантирует согласованность внутри него.

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

Уровень инфраструктуры

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

Основные элементы уровня инфраструктуры:

  • Платформа оркестрации — система, которая управляет жизненным циклом контейнеров с микросервисами. Наиболее распространённым решением является Kubernetes. Платформа отвечает за запуск экземпляров сервисов, их масштабирование в зависимости от нагрузки, восстановление после сбоев и распределение по узлам кластера.
  • Сетевая инфраструктура — набор компонентов, обеспечивающих маршрутизацию трафика между сервисами и от клиентов к сервисам. Сюда относятся ingress-контроллеры, service mesh (например, Istio или Linkerd), балансировщики нагрузки и DNS-сервисы.
  • Хранилища данных — базы данных, очереди сообщений, кэши и другие системы хранения, используемые микросервисами. Каждый сервис может иметь своё выделенное хранилище, но само хранилище управляется на уровне инфраструктуры.
  • Системы логирования и мониторинга — компоненты, собирающие метрики, логи и трассировки выполнения запросов. Они позволяют отслеживать состояние системы в реальном времени и проводить диагностику проблем.

Уровень инфраструктуры делает микросервисы «невидимыми» для внешнего мира в плане их физического размещения. Сервис может быть перемещён между узлами, перезапущен или заменён новой версией без влияния на логику других компонентов системы.

Уровень управления

Уровень управления отвечает за процессы, связанные с жизненным циклом микросервисов и всей системы в целом. Он обеспечивает автоматизацию операций, контроль качества, безопасность и соответствие политикам организации.

Ключевые функции уровня управления:

  • CI/CD-конвейеры — автоматизированные процессы сборки, тестирования и развёртывания микросервисов. Каждый сервис имеет свой независимый конвейер, что позволяет командам быстро и безопасно доставлять изменения в продакшен.
  • Репозитории артефактов — хранилища для образов контейнеров, пакетов зависимостей и других артефактов сборки. Они обеспечивают воспроизводимость и отслеживаемость версий.
  • Системы конфигурации — централизованные хранилища параметров конфигурации, которые могут изменяться без пересборки сервисов. Примеры: Consul, etcd, Spring Cloud Config.
  • Политики безопасности и доступа — механизмы управления идентификацией, аутентификацией и авторизацией. Они регулируют, какие сервисы и пользователи имеют право взаимодействовать с конкретными компонентами системы.
  • Инструменты наблюдаемости — платформы для анализа логов, визуализации метрик и построения карт зависимостей между сервисами. Они помогают понимать поведение системы в целом и выявлять узкие места.

Уровень управления превращает микросервисную архитектуру из набора независимых компонентов в управляемую и контролируемую экосистему.

Компоненты модельной архитектуры микросервисов

Помимо уровней, модельная архитектура микросервисов включает в себя ряд ключевых компонентов, которые обеспечивают её работоспособность и устойчивость.

API Gateway

API Gateway выступает единым входным шлюзом для всех внешних клиентов — веб-приложений, мобильных устройств, партнёрских систем. Он принимает входящие запросы, маршрутизирует их к соответствующим микросервисам, агрегирует результаты и возвращает клиенту единый ответ.

Функции API Gateway:

  • Аутентификация и авторизация запросов.
  • Ограничение скорости (rate limiting).
  • Преобразование протоколов и форматов данных.
  • Кэширование часто запрашиваемых данных.
  • Логирование и мониторинг трафика.

Использование API Gateway упрощает взаимодействие клиентов с системой и снижает связанность между клиентской частью и внутренней структурой микросервисов.

Service Registry и Discovery

В динамической среде микросервисы могут появляться и исчезать в любой момент. Service Registry — это централизованный каталог, в котором регистрируются все активные экземпляры сервисов вместе с их сетевыми адресами. Service Discovery — механизм, с помощью которого сервисы находят друг друга в этом каталоге.

Процесс работы:

  1. При запуске микросервис регистрируется в Service Registry.
  2. Перед отправкой запроса к другому сервису он запрашивает его текущий адрес из Service Registry.
  3. После завершения работы сервис удаляется из реестра.

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

Message Broker

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

Преимущества использования Message Broker:

  • Декуплинг производителей и потребителей сообщений.
  • Гарантированная доставка даже при недоступности получателя.
  • Возможность реализации шаблонов обмена: publish-subscribe, point-to-point, dead-letter queues.
  • Поддержка транзакционной целостности в распределённых операциях.

Популярные решения: RabbitMQ, Apache Kafka, NATS, Amazon SQS.

Circuit Breaker

Circuit Breaker — это паттерн устойчивости, который предотвращает каскадные сбои в системе. Когда один микросервис становится недоступен или начинает отвечать слишком медленно, Circuit Breaker временно блокирует все запросы к нему, возвращая клиенту заглушку или кэшированный результат.

Механизм работы:

  • В нормальном состоянии Circuit Breaker передаёт запросы к целевому сервису.
  • При превышении порога ошибок или задержек он переходит в состояние «разомкнуто».
  • В этом состоянии все запросы сразу же отклоняются без попытки вызова сервиса.
  • Через заданный интервал времени Circuit Breaker переходит в «полуразомкнутое» состояние, пропуская ограниченное количество запросов для проверки доступности сервиса.
  • Если проверка успешна, он возвращается в нормальное состояние.

Этот компонент защищает систему от перегрузки и даёт время на восстановление недоступных сервисов.

Sidecar-контейнеры и Service Mesh

Sidecar — это вспомогательный контейнер, размещаемый в одном поде с основным микросервисом. Он берёт на себя задачи, не связанные напрямую с бизнес-логикой: шифрование трафика, сбор метрик, управление маршрутами.

Service Mesh объединяет все sidecar-контейнеры в единую сеть, управляемую централизованно. Он предоставляет такие функции, как:

  • Безопасная коммуникация между сервисами (mTLS).
  • Точечное управление трафиком (canary-релизы, A/B-тестирование).
  • Наблюдаемость на уровне сети.
  • Политики отказоустойчивости.

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


Компоненты модельной архитектуры микросервисов (продолжение)

Конфигурационные серверы и централизованное управление параметрами

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

Конфигурационный сервер — это централизованное хранилище параметров, к которому микросервисы обращаются при старте или во время выполнения. Такой подход позволяет:

  • Изменять поведение сервиса без пересборки и повторного развёртывания.
  • Поддерживать разные конфигурации для разных окружений (dev, staging, prod).
  • Версионировать изменения конфигурации и откатывать их при необходимости.
  • Контролировать доступ к чувствительным параметрам через политики безопасности.

Популярные решения включают Spring Cloud Config, Consul, etcd, HashiCorp Vault (для секретов) и AWS Systems Manager Parameter Store. Эти системы интегрируются с платформами оркестрации и CI/CD-конвейерами, обеспечивая единый источник правды для всех параметров системы.

Централизованная система логирования и мониторинга

В распределённой системе из десятков или сотен микросервисов отладка ошибок и анализ производительности невозможны без единой системы сбора и анализа данных. Логи, метрики и трассировки запросов объединяются в три основных потока наблюдаемости.

  • Логирование — запись событий, происходящих в каждом сервисе. Логи структурируются в формате JSON и отправляются в централизованное хранилище, такое как Elasticsearch, Loki или Splunk. Это позволяет выполнять поиск по всему кластеру, фильтровать события по сервису, уровню важности или пользовательскому ID.
  • Метрики — количественные показатели состояния системы: количество запросов в секунду, время ответа, использование CPU и памяти, частота ошибок. Системы вроде Prometheus собирают эти данные с каждого узла и предоставляют интерфейсы для визуализации через Grafana.
  • Трассировка — отслеживание пути одного запроса через все микросервисы. Каждый запрос получает уникальный идентификатор (trace ID), который передаётся между сервисами. Инструменты вроде Jaeger или Zipkin собирают временные метки каждого этапа обработки и строят карту вызовов, позволяя точно определить узкое место.

Эти компоненты работают совместно, обеспечивая полную прозрачность над поведением системы в реальном времени.

Шаблоны взаимодействия между микросервисами

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

  • Синхронный вызов через REST/gRPC — наиболее распространённый способ, когда один сервис напрямую вызывает другой и ждёт ответа. Этот подход прост, но создаёт временную зависимость: если целевой сервис недоступен, вызывающий сервис может зависнуть или завершиться с ошибкой.
  • Асинхронное сообщение через брокер — сервис публикует событие, не заботясь о том, кто его получит. Получатели подписываются на нужные типы событий и обрабатывают их независимо. Это снижает связанность и повышает отказоустойчивость.
  • Event Sourcing — вместо хранения текущего состояния объекта сервис сохраняет последовательность событий, которые привели к этому состоянию. Это позволяет восстановить состояние на любой момент времени и легко реализовать аудит изменений.
  • CQRS (Command Query Responsibility Segregation) — разделение операций записи и чтения. Команды (изменения данных) обрабатываются одним набором сервисов, а запросы (чтение) — другим, часто с использованием материализованных представлений для ускорения ответа.

Эти шаблоны не исключают друг друга и часто комбинируются в рамках одной системы.

Управление жизненным циклом и версионирование

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

  • Независимые CI/CD-конвейеры — каждый сервис проходит сборку, тестирование и развёртывание отдельно. Это позволяет командам выпускать изменения в любое время без координации с другими группами.
  • Семантическое версионирование API — при изменении контракта взаимодействия (например, добавлении нового обязательного поля) выпускается новая версия API. Старые клиенты продолжают работать со старой версией, пока не будут адаптированы.
  • Канареечные релизы и A/B-тестирование — новая версия сервиса запускается параллельно со старой, и часть трафика направляется на неё. Это позволяет проверить стабильность и производительность до полного перехода.
  • Откат и аварийное восстановление — в случае критической ошибки система автоматически переключается на предыдущую рабочую версию, минимизируя время простоя.

Такой подход делает процесс доставки программного обеспечения предсказуемым, безопасным и гибким.

Безопасность на всех уровнях

Безопасность в микросервисной архитектуре реализуется сквозным образом — от сетевого уровня до бизнес-логики.

  • Аутентификация и авторизация — каждое взаимодействие между сервисами проходит проверку подлинности. Используются токены (JWT, OAuth2), сертификаты или доверенные прокси (например, Istio mTLS).
  • Шифрование трафика — все сетевые вызовы шифруются с помощью TLS, даже внутри внутренней сети. Это предотвращает прослушивание и подмену данных.
  • Политики доступа — определяются правила, какие сервисы могут вызывать другие. Например, сервис оплаты может вызывать только сервис заказов, но не сервис рекомендаций.
  • Управление секретами — пароли, ключи API и другие чувствительные данные хранятся в защищённых хранилищах (Vault, AWS Secrets Manager) и подгружаются в сервисы только во время выполнения.

Безопасность рассматривается не как дополнительный слой, а как неотъемлемая часть архитектуры.


Принципы проектирования модельной архитектуры микросервисов

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

Автономия сервисов

Каждый микросервис функционирует как независимое приложение. Он обладает собственным кодом, зависимостями, конфигурацией, процессом сборки и развёртывания. Эта автономия распространяется и на данные: сервис владеет своей базой данных или схемой, и другие компоненты системы не имеют прямого доступа к этим данным. Взаимодействие происходит только через публичные интерфейсы — API или события.

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

Границы ограниченного контекста

Ограниченный контекст — это концепция из Domain-Driven Design, которая определяет чёткие границы ответственности для каждого сервиса. Внутри контекста термины, правила и модели имеют однозначное значение. За пределами контекста эти понятия могут трактоваться иначе.

Разделение системы на ограниченные контексты помогает избежать семантической путаницы и дублирования логики. Например, понятие «клиент» в сервисе маркетинга может означать контакт для email-рассылки, а в сервисе продаж — юридическое лицо с договором. Эти две сущности не должны смешиваться, даже если они относятся к одному физическому человеку.

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

Отказоустойчивость по умолчанию

В распределённой системе сбои неизбежны: сеть может быть недоступна, диск — заполнен, процесс — убит из-за нехватки памяти. Микросервисная архитектура проектируется с учётом этих реалий. Каждый компонент должен корректно обрабатывать ошибки, использовать повторные попытки с экспоненциальной задержкой, применять шаблоны Circuit Breaker и Bulkhead.

Отказоустойчивость достигается не только за счёт кода, но и за счёт инфраструктуры: автоматическое восстановление экземпляров, перераспределение нагрузки, резервирование хранилищ. Цель — обеспечить, чтобы частичный сбой не приводил к полному останову системы.

Наблюдаемость как обязательное требование

Если система не наблюдаема, она неуправляема. Каждый микросервис обязан генерировать структурированные логи, предоставлять метрики выполнения и поддерживать сквозную трассировку запросов. Эти данные собираются централизованно и используются для мониторинга, анализа производительности и диагностики инцидентов.

Наблюдаемость встраивается в процесс разработки с самого начала. Команды определяют ключевые показатели эффективности (SLO) и строят дашборды, которые отражают состояние сервиса в реальном времени. Это позволяет оперативно реагировать на отклонения от нормы.

Декларативность и идемпотентность

Интерфейсы микросервисов стремятся к декларативному стилю: клиент описывает желаемое состояние, а сервис заботится о том, как его достичь. Например, вместо последовательности команд «создать заказ», «добавить товар», «применить скидку» клиент отправляет один объект заказа в целевом состоянии.

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

Эволюционность и обратная совместимость

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

  • Добавления новых полей без удаления старых.
  • Использования версионирования URL или заголовков.
  • Поддержки нескольких форматов входных данных.
  • Постепенного вывода устаревших функций с предварительным уведомлением.

Эволюционность позволяет системе расти и адаптироваться к меняющимся требованиям без болезненных миграций.