Проектирование микросервисов, управляемых событиями, с использованием принципов дизайна, основанных на домене
Table of Contents
Микросервисы, управляемые событиями, представляют собой фундаментальный сдвиг в том, как современные программные системы спроектированы для масштабирования, устойчивости и выравнивания бизнеса. В сочетании с дизайном, управляемым доменом (DDD), эти архитектуры выходят за рамки простого технического разделения для создания систем, которые отражают язык и ограничения фактической области бизнеса. Это руководство обеспечивает тщательный, практический подход к проектированию микросервисов, управляемых событиями, с использованием принципов DDD, охватывающих все, от открытия ограниченного контекста до управления схемой событий.
Понимание микросервисов, управляемых событиями
В традиционной архитектуре, основанной на запросах, службы взаимодействуют синхронно через HTTP или RPC-звонки. Это создает тесную временную связь - абонент должен ждать, пока абонент ответит. Микросервисы, управляемые событиями, инвертируют эту модель: службы публикуют события (сообщения, представляющие что-то, что произошло) для брокера сообщений, а другие службы потребляют эти события асинхронно.
Основные компоненты архитектуры микросервиса, управляемого событиями, включают:
- Производители событий : Услуги, которые обнаруживают и испускают события (например, «OrderPlaced»)
- События потребителей : Услуги, которые подписываются на события и реагируют соответствующим образом
- Брокер сообщений : Промежуточное ПО, такое как Apache Kafka, RabbitMQ или Amazon EventBridge, которое хранит и маршрутизирует события
- Схема событий : центральный магазин для событийных контрактов, позволяющий редактировать и развивать
Эта модель улучшает масштабируемость, поскольку каждая услуга может быть масштабирована независимо от ее собственной нагрузки. Устойчивость повышается, потому что отказ потребителя не блокирует производителя - события сохраняются и могут быть переработаны позже. Кроме того, системы, управляемые событиями, естественным образом поддерживают возможную согласованность, которая часто более уместна, чем распределенные транзакции для крупномасштабных систем.
Основные принципы дизайна, управляемого доменом
Дизайн, основанный на домене, был усовершенствован Эриком Эвансом и сообществом DDD на протяжении десятилетий. Цель состоит в том, чтобы создать программное обеспечение, которое верно моделирует бизнес-домен, а не запутывается в инфраструктурных проблемах. Ключевые строительные блоки DDD непосредственно применимы к дизайну микросервисов:
Ограниченный контекст
Ограниченный контекст — это логическая граница, в рамках которой применяется конкретная модель домена. Например, понятие «клиент» может отличаться между контекстом продаж (где клиент является лидером с контактной информацией) и контекстом доставки (где клиент является адресом и предпочтениями доставки). Каждый ограниченный контекст имеет свой собственный вездесущий язык. В микросервисах каждая услуга обычно владеет точно одним ограниченным контекстом. Это выравнивание является основой микросервисов в стиле DDD.
Сущности и объекты ценности
Сущности — это объекты с уникальной идентичностью, которая сохраняется с течением времени (например, порядок с идентификатором заказа). Объекты ценности — это неизменные объекты, которые описывают аспекты домена без выделенной идентичности (например, адрес, деньги). В микросервисах, управляемых событиями, сами события часто являются объектами ценности — они представляют собой момент времени и должны быть неизменяемыми. Распространенной ошибкой является встраивание изменчивого состояния сущности в события, что приводит к кошмарам эволюции схемы.
агрегировать
Совокупность — это кластер объектов домена, который можно рассматривать как единое целое. Граница транзакции обеспечивает согласованность в агрегате. В архитектуре, управляемой событиями, события публикуются, когда агрегат изменяет состояние. Например, когда агрегатный переход от «подвергающегося» к «подтвержденному» происходит в системе События, подтвержденные . Совокупная граница диктует, какие изменения состояния являются атомарными и какие события поднимаются.
Доменные события
Это краеугольный камень событийно-управляемых систем. событие домена захватывает то, что произошло в домене, который волнует экспертов домена. События называются в прошедшем времени (например, InvoicePaid, InventoryReserved) и несут данные, необходимые для реагирования потребителей. DDD предписывает, что события домена должны быть подняты из модели домена, а не из слоев инфраструктуры. Это гарантирует, что события отражают реальные деловые события, а не технический шум.
Проектирование микросервисов с помощью DDD
Применение DDD к микросервисному дизайну заключается не только в разделении монолита на более мелкие сервисы. Для этого требуется методическое разложение бизнес-доменов на ограниченные контексты, каждый из которых становится кандидатом на микросервис. Процесс включает три основных этапа: стратегический дизайн, тактический дизайн и моделирование событий.
Стратегический дизайн: поиск ограниченных контекстов
Начните с семинара Сторителлинг домена или Event Storming . объедините экспертов и разработчиков домена для отображения потока бизнес-деятельности. По мере идентификации событий и команд группируйте их в контексты. Для системы электронной коммерции типичные ограниченные контексты могут включать:
- Управление заказами: ручки тележки, касса, машина состояния заказа
- Инвентаризация: отслеживает уровни запасов, резервирование, пополнение запасов
- Биллинг: счета-фактуры, платежи, возвраты
- Выполнение : доставка, отслеживание, доставка
- Управление клиентами: профили, предпочтения, аутентификация
Каждый из этих контекстов станет микросервисом. Контекстная карта визуализирует отношения между контекстами — в частности, какие контексты находятся вверх по течению (производят события) и какие находятся вниз по течению (потребляют события).
Тактический дизайн: моделирование в ограниченном контексте
В каждом ограниченном контексте, построить богатую модель домена с использованием объектов, ценностей, агрегатов и событий домена. Например, в контексте управления заказами, вы можете определить:
- Заказ (агрегированный корень): содержит пункты, статус, адрес доставки
- Предмет заказа (субъект): ссылки на продукт, количество, цену
- Адрес доставки (объект оценки): улица, город, zip
- Заказ (доменовое событие): поднимается при подаче заказа
- OrderShipped (доменовое событие): поднимается при переходе заказа на отгрузку
Совокупный корень гарантирует, что все инварианты (например, общий расчет, переходы статуса) выполняются до публикации события. Это согласуется с шаблоном Aggregate и предотвращает утечку несогласованного состояния потребителям.
Моделирование событий: определение событий и хореография
После того, как ограниченные контексты определены, моделируйте события, которые текут между ними. Используйте совместную технику, такую как Моделирование событий (созданное Адамом Дымитруком. Начните с временной шкалы: перечислите события в хронологическом порядке, как они происходят в пользовательском путешествии. Для каждого события решите, какой контекст производит его и какие контексты потребляют его. Для потока размещения заказа хореография может выглядеть так:
- Управление заказами → публикует
- Инвентарь ← потребляет Заказ, резервные запасы, затем публикует ЗапасыЗапасы, несостоявшиеся]
- Биллинг ← потребляет Запаса инвентаря, обрабатывает оплату, публикует Платежи Преуспевшие или Платежи Неудавшиеся
- Управление заказами ← потребляет Платежи Преемственные, меняет статус заказа на «подтвержденный», публикует Подтвержденный заказ
- Выполнение ← потребляет Подтвержденный порядок, запускает доставку, публикует Погруженный
Эта хореография устраняет необходимость в центральном оркестровщике. Каждая служба реагирует на события и может производить новые события. Система в целом достигает возможной согласованности. Для устранения сбоев службы должны быть идемпотентными и способными перерабатывать события.
Преимущества сочетания событийной архитектуры и DDD
Синергия между архитектурой, основанной на событиях, и DDD дает несколько измеримых преимуществ по сравнению с традиционными проектами обслуживания:
Свободное соединение
Услуги общаются исключительно через события, а не прямые вызовы API. Событие — это сообщение «пожар и забвение»: производитель не ожидает синхронного ответа. Это исключает связь во время выполнения. Потребитель может быть добавлен или удален без воздействия на производителя. Изменения внутренней модели одной службы не утекают в другие, пока схема события остается стабильной.
Масштабируемость
Асинхронная обработка событий позволяет каждой службе масштабироваться горизонтально на основе собственной нагрузки. Скачок в размещении заказов не заставляет службу инвентаризации масштабироваться в той же степени; события буферизируются в брокере. Кроме того, вы можете добавить новых потребителей событий (например, механизм рекомендаций, который слушает OrderPlaced) без изменения существующих услуг.
Устойчивость
Если служба выставления счетов не работает, то управление заказами по-прежнему публикует события, которые продолжаются. Когда Биллинг восстанавливается, он воспроизводит отставание. Это гораздо более надежно, чем синхронные цепочки, где один тайм-аут каскадирует всю систему. В DDD совокупная граница гарантирует, что каждая служба может оставаться последовательной, не дожидаясь служб нисходящего потока.
Выравнивание доменов
Возможно, самое сильное преимущество: архитектура отражает бизнес. События названы на языке экспертов домена. Это делает систему прозрачной для заинтересованных сторон и легче развиваться по мере изменения бизнеса. Ограниченные контексты препятствуют слишком общему «общему сервису», который пытается обслуживать нескольких мастеров и в конечном итоге не обслуживает никого.
Вызовы и лучшие практики
Хотя сочетание событийных микросервисов и DDD является мощным, оно вводит новые сложности, которые требуют дисциплинированных инженерных практик.
Управление случайной последовательности
Когда услуги слабо связаны с событиями, система в конечном итоге последовательна. Пользователь может увидеть статус «оплата в ожидании» ненадолго до того, как событие PaymentSucceeded распространяется. Это приемлемо для многих доменов, но вы должны соответствующим образом спроектировать пользовательский опыт. Используйте шаблоны Saga (хореография или оркестровка) для обработки многоступенчатых транзакций. Например, если служба инвентаризации не может резервировать, служба управления заказами должна реагировать на событие компенсации и отменить заказ. В DDD эти компенсации также моделируются как события домена.
Версия событий и эволюция схемы
События - это неизменные записи прошлого, но их схемы должны развиваться. Принять Реестр событий (например, Реестр сменных схем или пользовательское решение) для обеспечения проверки совместимости. Используйте формат сериализации, который поддерживает эволюцию схем, такой как Avro, Protobuf или JSON Schema с версией. Лучшие практики включают:
- Всегда добавляйте новые поля в качестве опции с по умолчанию.
- Не удаляйте поля без периода амортизации.
- События версии на уровне схемы (например, OrderPlacedV2).
- Держите потребителей терпимыми к более старым версиям (вперед совместимость).
Источник событий vs. Уведомления о событиях
Не все события должны храниться в качестве источника истины. Многие реализации используют уведомления о событиях — сообщения, которые информируют другие службы об изменении без сохранения полной истории событий. Напротив, , поиск событий сохраняет каждое изменение состояния в качестве журнала только для добавления и получает текущее состояние из повторения событий. Искать события парно с агрегатами DDD, но вводит сложность в запрашивании и управлении схемой. Используйте поиск событий только тогда, когда вам нужны полные аудиторские следы, временные запросы или поддержка сложной реконструкции состояния.
Импотенция и точно разовая обработка
Распределенные системы часто доставляют события по крайней мере один раз. Создайте так, чтобы ваши потребители были идемпотентными: обработка одного и того же события дважды должна давать один и тот же результат. Общий подход заключается в том, чтобы размножить идентификатор события. В DDD совокупный идентификатор в сочетании с порядковым номером события может служить ключом для дедупликации. Кроме того, убедитесь, что потребители события справляются с дублирующими событиями изящно - не предполагайте уникальную доставку.
Мониторинг и наблюдаемость
Системы, управляемые событиями, сложнее отлаживать, потому что поток асинхронен и охватывает несколько служб. Внедряйте распределенное отслеживание (например, OpenTelemetry) с идентификатором корреляции, который проходит через каждое событие. Логируйте все события публикации событий и потребления с временными метками. Используйте очереди мертвых букв для событий, которые несколько раз не обрабатываются. Инструмент ваш брокер сообщений с такими показателями, как задержка событий (насколько далеко отстает от потребителя) и задержка обработки.
Практические шаги, чтобы начать
- Запустите семинар по штурму событий с экспертами по доменам, чтобы идентифицировать все события домена, команды и ограниченные контексты.
- Определите контекстную карту. Определите, в каких контекстах будут микросервисы, и выведите отношения «вверх/вниз».
- Выберите своего брокера событий (Kafka для высокой пропускной способности, RabbitMQ для более простой маршрутизации или облачный натив, такой как AWS EventBridge).
- Схемы событий проектирования совместно с использованием реестра. Начните с нескольких основных событий.
- Внедрить одну услугу , следуя тактическим шаблонам DDD. Опубликовать свое первое доменное событие.
- Постройте потребителя в другой службе. Проверьте поток асинхронизации сквозной.
- Постепенно расширяйте . Добавьте больше событий, больше потребителей и реализуйте саги для критических потоков.
Пример из реального мира: выполнение заказа электронной коммерции
Рассмотрим уменьшенный, но реалистичный пример. Управление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказамиУправление заказами[[
Внешние ресурсы
Чтобы углубить свое понимание этих концепций, изучите следующие авторитетные источники:
- Статья Мартина Фаулера о микросервисах — основополагающее чтение о границах обслуживания
- Доменной язык — сайт Эрика Эванса по DDD — официальные ресурсы по стратегическому и тактическому DDD
- Сайт моделирования событий — практическое руководство и инструментарий для проектирования событийно-ориентированных систем
- Документация Apache Kafka Streams — для понимания шаблонов обработки событий
Заключение
Проектирование событийно-ориентированных микросервисов с доменно-ориентированными принципами проектирования является проверенным подходом к построению систем, которые являются технически надежными и бизнес-ориентированными. Сочетание ограниченных контекстов, агрегатов, событий домена и асинхронной хореографии дает свободную связь, независимую масштабируемость и устойчивость. В то время как такие проблемы, как возможная согласованность и версия событий, требуют тщательного планирования, выигрыш - это система, которая может развиваться с бизнесом без накопления технического долга. Начните с совместного моделирования, инвестируйте в твердые контракты на события и итеративный. Результат - архитектура, которая рассматривает события не как детали реализации, а как первоклассные представления бизнес-истины.