Стиль архитектуры микрослужб

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

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

Логическая схема стиля архитектуры микрослужб.

На схеме показана архитектура микрослужб, развернутая в Microsoft Azure. Он организован в восемь помеченных разделов, каждый из которых представляет ключевой архитектурный компонент. Композиция располагается слева направо и сверху вниз. В крайнем левом углу значки обозначены как клиенты и представляют пользователей или внешние системы, которые инициируют запросы к приложению. Стрелка указывает от клиентов к шлюзу API. Запросы передаются через шлюз API и на соответствующие микрослужбы. Стрелки ведут от шлюза API к блоку, называемому микрослужбами. Это поле содержит два значка для доменных служб, один значок для служб композиции и один значок для службы. Стрелки указывают от микросервисов в другой блок, который помечен как базы данных домена. Это поле содержит значки, представляющие две базы данных SQL и базу данных NoSQL. Стрелки также указывают от микрослужб к блоку, обозначенному как промежуточное ПО, ориентированное на сообщения. Стрелки помечены как публикация или подписка и события. На схеме также содержатся поля, представляющие наблюдаемость, управление и оркестрацию, а также DevOps.

Что такое микрослужбы?

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

Компоненты

Помимо самих служб другие компоненты отображаются в типичной архитектуре микрослужб:

  • Управление или оркестрация: Этот компонент управления обрабатывает оркестрацию микрослужб. Он планирует и развертывает службы на разных узлах, обнаруживает сбои, восстанавливается после сбоев и включает автомасштабирование на основе спроса. Платформа оркестрации контейнеров, например Kubernetes, обычно предоставляет эту функцию. В облачных средах такие решения, как приложения контейнеров Azure, обеспечивают управляемое оркестрацию и встроенное масштабирование. Эти средства снижают сложность развертывания и операционные издержки.

    Сведения об оценке этих платформ см. в статье "Выбор варианта вычислений Azure для микрослужб".

  • Шлюз API: Шлюз API служит точкой входа для клиентов. Клиенты отправляют запросы к шлюзу API вместо вызова служб напрямую. Шлюз перенаправит эти запросы в соответствующие внутренние службы. Он также обрабатывает перекрестные проблемы, такие как проверка подлинности, ведение журнала и балансировка нагрузки. В архитектурах микрослужб в облаке упрощенные прокси-серверы служб, такие как Envoy и Nginx, поддерживают внутреннее взаимодействие между службами. Этот тип внутреннего трафика, известный как восточный-западный трафик, обеспечивает расширенную маршрутизацию и управление трафиком.

  • Промежуточное ПО, ориентированное на сообщения: Платформы обмена сообщениями, такие как Apache Kafka и служебная шина Azure, обеспечивают асинхронную связь в микрослужбах, обеспечивая слабую связность и поддерживая высокую масштабируемость. Они формируют основу архитектуры с событийным управлением. Этот подход позволяет службам реагировать на события в режиме реального времени и взаимодействовать с помощью асинхронного обмена сообщениями.

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

  • Управление данными: Хорошо разработанная архитектура базы данных поддерживает автономию и масштабируемость. Микрослужбы часто используют сохраняемость polyglot, выбирая различные типы баз данных, такие как SQL или NoSQL, в зависимости от конкретных потребностей каждой службы. Этот подход соответствует дизайну на основе домена (DDD) и идее ограниченного контекста. Каждая служба владеет своими данными и схемой. Это владение уменьшает зависимости между службами и позволяет службам развиваться независимо. Эта децентрализованная модель повышает гибкость, производительность и устойчивость системы.

Преимущества

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

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

  • Небольшая база кода: В монолитном приложении зависимости кода часто становятся запутанными с течением времени. Добавление новой функции может потребовать изменений во многих частях базы кода. Архитектура микрослужб избегает этой проблемы, не предоставляя общий доступ к коду или хранилищам данных. Этот подход сводит к минимуму зависимости и упрощает внедрение новых функций.

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

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

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

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

Сложности

Преимущества микрослужб приходят с компромиссами. Прежде чем создавать архитектуру микрослужб, рассмотрите следующие проблемы:

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

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

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

  • Перегрузка сети и задержка: Использование множества небольших, детализированных служб может привести к большему взаимодействию между службами. Кроме того, если цепочка зависимостей служб становится слишком длинной (служба A вызывает B, которая вызывает C...), дополнительная задержка может стать проблемой. Необходимо тщательно разработать API. Избегайте чрезмерно разговорчивых API, думайте о форматах сериализации и ищите возможности для использования асинхронных шаблонов связи, таких как шаблонQueue-Based выравнивания нагрузки.

  • Целостность данных: Каждая микрослужба отвечает за сохранение собственных данных. В результате согласованность данных в нескольких службах может быть проблемой. Различные службы сохраняют данные в разные времена, используя разные технологии и потенциально разные уровни успеха. Если в сохранении новых или измененных данных участвует несколько микрослужб, маловероятно, что полное изменение данных может считаться атомарным, согласованным, изолированным и устойчивым (ACID). Вместо этого метод ближе к принципу "Основная доступность", "Нестабильное состояние", "Конечная согласованность" (BASE). Примите возможность окончательной согласованности, где это возможно.

  • Управление: Для успешной архитектуры микрослужб требуется зрелая культура DevOps. Корреляция логирования в разных службах может быть сложной задачей. Как правило, ведение журнала должно сопоставлять несколько вызовов службы для одной операции пользователя.

  • Управление версиями: Обновления службы не должны прерывать службы, зависящие от нее. Несколько служб могут обновляться в любой момент времени, поэтому без тщательного планирования могут возникнуть проблемы с обратной или прямой совместимостью.

  • Набор навыков: Микрослужбы являются высоко распределенными системами. Тщательно оцените, имеет ли команда навыки и опыт успешного выполнения.

Лучшие практики

  • Структурируйте услуги в соответствии с бизнес-областью. Используйте DDD, чтобы определить ограниченные контексты и определить четкие границы службы. Избегайте создания чрезмерно детализированных служб, что может повысить сложность и снизить производительность.

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

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

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

  • Службы взаимодействуют через хорошо разработанные API. Избегайте утечки сведений о реализации. API должны моделировать домен, а не внутреннюю реализацию службы.

  • Избегайте взаимодействия между службами. Причины связывания включают схемы общей базы данных и жесткие протоколы связи.

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

  • Повышение безопасности с помощью взаимной защиты уровня транспорта (mTLS) для шифрования между службами. Реализуйте управление доступом на основе ролей и используйте шлюзы API для применения политик.

  • Перенесите кросс-системные задачи, такие как аутентификация и завершение SSL, на шлюз. Сетки служб и платформы, такие как Dapr, также могут помочь с общими перекрестными проблемами, такими как проверка подлинности mTLS и устойчивость.

  • Не включайте знания о домене в шлюз. Шлюз должен обрабатывать и направлять клиентские запросы без каких-либо знаний о бизнес-правилах или логике домена. В противном случае шлюз становится дополнительной зависимостью и может привести к взаимозависимости между службами.

  • Службы должны иметь свободное соединение и высокую функциональную сплоченность. Функции, которые, скорее всего, изменятся вместе, следует упаковывать и развертывать вместе. Если они находятся в отдельных службах, эти службы в конечном итоге тесно связаны, так как изменение в одной службе требует обновления другой службы. Чрезмерно болтливое взаимодействие между двумя службами может быть симптомом жесткой связи и низкой сплоченности.

  • Используйте конвейеры непрерывной интеграции и непрерывного развертывания (CI/CD) для автоматизации тестирования и развертывания. Развертывайте службы автономно и отслеживайте работоспособность развертывания.

  • Изолируйте неисправности. Используйте стратегии устойчивости, чтобы предотвратить каскадные сбои в службе. Дополнительные сведения см. в разделе "Шаблоны устойчивости " и "Проектирование надежных приложений".

  • Используйте инженерию хаоса, чтобы проверить устойчивость архитектуры микрослужб и ее зависимостей. Оцените и улучшите способ обработки частичных сбоев в системе.

  • Реализуйте централизованное ведение журнала, распределенную трассировку (OpenTelemetry) и коллекцию метрик для обеспечения наблюдаемости.

Антипаттерны для микрослужб

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

  • Реализация микрослужб без глубокого понимания бизнес-домена приводит к плохо выровненным границам службы и подрывает предполагаемые преимущества.

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

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

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

  • Использование универсальных событий заставляет потребителей интерпретировать и фильтровать сообщения. Этот подход добавляет ненужную сложность и снижает ясность в событийно-ориентированной коммуникации.

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

  • Предоставление микрослужб непосредственно потребителям приводит к жесткой связи, проблемам масштабируемости и рискам безопасности. Использование шлюза API обеспечивает чистую, управляемую и безопасную точку входа.

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

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

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

Создание архитектуры микрослужб

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

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

  1. Выполните анализ предметной области для моделирования микрослужб.
  2. Используйте тактический подход на основе DDD для разработки микрослужб.
  3. Определите границы микрослужб.

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

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