|
Professor Seleznov
|
TL;DR
- Событийно-ориентированная архитектура (англ. event-driven architecture, EDA) — не короткий путь и не «бесплатное» решение. Она приносит с собой новую сложность, новые сценарии отказов и требует по-другому смотреть на проектирование систем.
- В жёстко регулируемых средах паттерны надёжности вроде inbox, outbox, идемпотентных потребителей и явной обработки ошибок — не бонус, а необходимость. Без них слишком легко получить потерянные или задублированные события.
- Разделение доменных и интеграционных событий помогает не вытаскивать внутреннюю модель наружу и даёт системам возможность развиваться независимо, не ломая потребителей.
- У событийно-ориентированных систем есть вполне практические плюсы: слабая связанность, естественный аудиторский след и возможность добавлять новые сценарии, просто подписываясь на уже существующие потоки событий, а не переделывая ядро платформы.
- Успешное внедрение зависит не только от технологий. Не меньшее значение имеют общие стандарты, сильная developer-платформа и нормальное практическое обучение команд.
При обсуждении событийно-ориентированной архитектуры в контексте облака и жёстко регулируемых отраслей полезно сначала выровнять базу. В эту тему приходят люди с разным бэкграундом: кто-то уже обжигался на распределённых системах, кто-то только начинает с ними разбираться. И это важно учитывать — многие идеи здесь на словах выглядят простыми, но на практике их легко использовать неправильно, если не понять суть с самого начала. Эта статья — переработка моего доклада с InfoQ Dev Summit Munich 2025 и опыт работы с событийными cloud-native системами в банкинге. Сначала разберём базу, потом — зачем вообще это всё в регулируемой среде, какие плюсы это даёт в реальности и где начинаются проблемы. В конце — паттерны и практики, которые помогли довести такие системы до продакшена, а не оставить на уровне красивой архитектуры в презентации. Когда базовые вещи становятся понятны, проще ответить на ключевые вопросы: где event-driven действительно уместен, какие комприссы он требует и почему, несмотря на регуляторные ограничения, он всё равно остаётся рабочим выбором для банковских систем. Что такое событие? Событие — это факт изменения состояния внутри системы. Оно может произойти из-за действия пользователя, фонового процесса или внешней системы. Событие либо несёт данные о том, что именно произошло, либо выступает как сигнал: «что-то случилось». Сколько данных класть в событие — вечный спор. Кто-то за минимализм, кто-то за «жирные» события. Мой подход простой: в событии должна быть только та информация, которая напрямую относится к самому изменению состояния. Всё лишнее — источник лишней связанности. Чем проще и компактнее события, тем легче их менять со временем и тем меньше они «сшивают» системы между собой. Команды и события — это разные вещи Одно из самых важных различий в event-driven системах — разница между командами и событиями. И одно из самых частых заблуждений тоже связано именно с этим. Когда команда и событие смешиваются, архитектура может выглядеть событийной, но на деле не даёт ни гибкости, ни нормальной развязки между системами. Команда — это явное указание что-то сделать. Одна система говорит другой: выполни конкретное действие. Даже если команда обрабатывается асинхронно, суть не меняется — от неё ожидают конкретный результат. Событие работает иначе. Это сообщение о том, что что-то уже произошло. Оно не требует реакции и не предполагает ответа. У события может быть один потребитель, несколько или вообще ни одного — и это нормально. Эта разница принципиальна. Если использовать события как замаскированные команды, системы начинают сильнее зависеть друг от друга, а гибкость со временем уходит. Поэтому важно чётко понимать, когда вы действительно посылаете команду, а когда публикуете событие. Что на самом деле значит событийно-ориентированная архитектура Когда с базовыми определениями разобрались, саму событийно-ориентированную архитектуру описать уже проще. Это подход, при котором системы взаимодействуют через публикацию и обработку событий. Одни сервисы публикуют события в eventing-платформу, другие подписываются на те события, которые им нужны. При этом producer не знает — и не должен знать, — кто именно читает его события и читает ли их вообще. Событийно-ориентированную архитектуру часто путают с event sourcing, но это разные вещи. Event sourcing — это способ хранить состояние приложения не как «снимок на сейчас», а как последовательность неизменяемых событий. Например, вместо записи «в корзине 4 товара» система хранит четыре события «товар добавлен», а текущее состояние восстанавливает, проигрывая их по порядку. Подход мощный, но сложный и требовательный к реализации. И главное — event sourcing не является обязательной частью событийно-ориентированной архитектуры. Эти темы часто идут рядом, потому что event-sourced системы естественно работают с событиями. Но если вы строите взаимодействие через события, это ещё не значит, что вам автоматически нужен event sourcing. Это отдельное архитектурное решение со своей ценой. Cloud Native на практике Cloud native — это не просто «запустить что-то в облаке». В облаке можно держать почти любую систему, в том числе очень далёкую от современных инженерных практик. Cloud-native подход — про другое: про системы, которые изначально проектируют под масштабирование, частые релизы и эксплуатацию через автоматизацию, а не через ручные операции. Часто такие системы строят на микросервисах, но это не единственный вариант. Модульный монолит тоже вполне может работать хорошо. Суть не в форме архитектуры как таковой, а в инженерной дисциплине: CI, CD, infrastructure as code и нормальная автоматизация всего жизненного цикла системы. На этом фоне событийно-ориентированная архитектура выглядит вполне естественно. Она хорошо ложится на асинхронное взаимодействие, слабую связанность и независимые поставки изменений — а это как раз базовые свойства cloud-native систем. Банкинг как ограничение Банковская сфера добавляет в эту картину много ограничений. Банки — большие и жёстко регулируемые организации, которые отвечают за деньги клиентов. Регуляторика влияет не только на технологии, но и на культуру команд, отношение к риску и скорость изменений. Поэтому осторожность к новым архитектурным подходам здесь вполне ожидаема. Но при этом современные инженерные практики уже давно не роскошь. Финансовые системы становятся всё масштабнее и сложнее, а ожидания клиентов только растут. В Investec — международной банковской и инвестиционной группе с корнями в Великобритании и Южной Африке — мы целенаправленно внедряли cloud-native и event-driven подходы, не выходя за рамки строгих регуляторных требований. Почему событийно-ориентированная архитектура важна Когда базовые принципы понятны, ценность событийно-ориентированного подхода становится гораздо заметнее. Его плюсы — не из презентаций и не из теории. В банкинге они хорошо видны в реальных продакшен-сценариях. Один из самых наглядных примеров — «развязка» (decoupling), особенно в платёжных системах. Возьмём мониторинг транзакций. Проверять активность по счетам на подозрительные операции нужно обязательно, но такая проверка не должна стоять в критическом пути платежа. Платёж должен проходить максимально надёжно, а мониторинг вполне может жить асинхронно. Если публиковать события о платеже и отдавать их на независимую обработку системам мониторинга, эти два процесса перестают жёстко зависеть друг от друга. В итоге платёжный поток продолжает работать, даже если мониторинг временно недоступен, а сам мониторинг можно развивать отдельно, не рискуя основной логикой платежей.

Рисунок 1: Развязка компонентов в банковской системе Ещё один важный плюс — события формируют неизменяемый журнал активности. В сложных платёжных процессах это уже не просто вспомогательный аудит, а фактически основной источник правды о том, что именно произошло. Такой журнал даёт командам сквозную видимость по всему жизненному циклу платежа, упрощает разбор инцидентов и помогает выполнять требования регуляторов к трассируемости операций. «Веерная обработка» (Fan-out) — ещё один сильный плюс. Одно событие, например успешный платёж, может запустить сразу несколько независимых процессов: обновление лимитов, отправку уведомления клиенту, сверку или любые другие downstream-сценарии. При этом каждый потребитель сам разбирается со своими сбоями и ретраями, не усложняя основной платёжный поток.

Рисунок 2: Веерная обработка в банковской системе Отказоустойчивость в регулируемой среде особенно важна — в том числе потому, что рядом почти всегда есть ненадёжные внешние зависимости, например сторонние антифрод-системы. Событийно-ориентированная архитектура позволяет строить многоуровневые стратегии повторной обработки, управлять задержками между повторными попытками и отправлять проблемные сообщения в очередь необработанных сообщений, если автоматически восстановиться уже не получается. Это не даёт «токсичным» событиям распространяться по системе и помогает безопаснее переживать сбои. И ещё один важный момент: зрелая событийная платформа действительно даёт эффект быстрого подключения. Новые возможности — например, программы лояльности — можно запускать, просто подписавшись на уже существующие потоки событий, без изменений в ядре системы. Если события изначально спроектированы корректно и остаются стабильными, новые сценарии добавляются быстро и без жёсткой связки с системами-источниками. Что создаёт проблемы — и что действительно помогает В теории событийно-ориентированная архитектура легко выглядит почти идеальной. На практике всё быстро становится сложнее. У этого подхода есть вполне конкретные болевые точки, и в банкинге цена ошибки здесь особенно высока. Хорошая новость в том, что большая часть этих проблем давно известна, и для них уже есть рабочие решения. Человеческий фактор Самая большая сложность в событийно-ориентированной архитектуре — не технология, а смена мышления. Инженерам приходится уходить от привычной модели «запрос — ответ» и учиться думать через асинхронность, согласованность в конечном счёте и независимую обработку сбоев. На практике это ощущается очень быстро. В одном из направлений, где мы внедряли и событийно-ориентированный подход, и хранение состояния через журнал событий, новым специалистам обычно требовалось около полугода, чтобы выйти на темп более опытных коллег. На старте команды часто переусложняют то, что уже не так важно, и одновременно недооценивают вещи, которые в распределённых системах действительно критичны: согласованность, ретраи и обработку отказов. Это влияет не только на код, но и на всю организацию. Поэтому человеческий фактор здесь нельзя считать второстепенной проблемой. Инструменты и поддержка Проблему человеческого фактора нельзя решить одними разговорами о «правильном подходе». Нужны реальные вложения в инструменты и поддержку. Хорошая платформа для разработчиков с нормальными шаблонами, общими модулями и готовыми базовыми решениями заметно ускоряет вход. Особенно хорошо работают заранее подготовленные типовые маршруты разработки: новым командам не приходится каждый раз с нуля собирать одни и те же «кирпичи» для событийных микросервисов. Но одной платформы мало. Без обучения она быстро превращается просто в набор удобных кнопок. Давать командам мощные инструменты и не объяснять, как такие системы ведут себя в проде, — рискованная идея. Особенно если учесть, что сбои обычно случаются в самый неподходящий момент. У нас лучше всего сработал практический подход. Мы сводили вместе команды внедрения и команды разработки, чтобы они вместе проектировали небольшие, но реальные событийно-ориентированный сервисы, а потом доводили их до продакшена. Это оказалось намного полезнее, чем просто выдать документацию и ждать, что люди сами во всём разберутся. Такой формат дал командам гораздо больше уверенности в самостоятельной работе. Ещё один важный момент — как можно раньше договориться о стандартах. Если заранее определить контракты событий, права доступа и базовый технологический стек, дальше будет намного меньше фрагментации и хаоса, а использовать события в масштабе всей организации станет заметно проще. Защита от потери и дублирования событий Ещё одна ключевая тема — надёжность. В банкинге потерянные или задублированные события недопустимы. Пропущенный платёж за аренду или двойное списание депозита — это не экзотический пограничный случай, а полноценный инцидент. Поэтому такие риски нужно закладывать ещё на этапе проектирования. Чтобы снизить их, мы используем паттерны outbox и inbox. Outbox нужен для того, чтобы изменение состояния и запись события происходили в одной транзакционной границе. Это защищает от ситуации, когда данные уже изменились, а событие так и не было опубликовано. Дальше отдельный диспетчер может надёжно забрать эти события и отправить их в eventing-платформу.

Рисунок 3: Паттерны outbox и inbox (паттерны исходящего и входящего журнала событий) Но одного outbox недостаточно. Большинство событийных платформ работают по модели доставки «как минимум один раз», а значит, дубликаты всё равно возможны. Здесь помогает inbox на стороне потребителя: событие сначала фиксируется, и только потом запускается бизнес-логика. Если прилетает дубль, он просто игнорируется. Вместе outbox и inbox закрывают обе проблемы — и потерю, и дублирование событий. А заодно избавляют команды от необходимости каждый раз заново изобретать одну и ту же механику надёжности. Контракты событий — это надолго События уменьшают связанность между системами, но взамен создают долгоживущие контракты. После публикации событие может храниться сколько угодно долго и переигрываться в любой момент. Если удалить поле или поменять его смысл, можно либо сразу сломать потребителей, либо получить ещё более неприятный сценарий — тихие ошибки в их логике. Переписывать исторические события, чтобы задним числом что-то «починить», — плохая идея. Это ломает саму архитектурную модель. Поэтому безопаснее всего относиться к событиям как к публичным API. Проектировать их нужно аккуратно и с запасом, исходя из того, что потребители будут использовать их не только так, как вы изначально задумали. Ломающих изменений лучше избегать. Если без них никак, события нужно версионировать. Версия в метаданных позволяет потребителям корректно обрабатывать несколько вариантов события и безболезненно переигрывать потоки. Разделение доменных и интеграционных событий даёт дополнительную защиту. Доменные события существуют внутри ограниченного контекста и могут меняться свободнее. Интеграционные события пересекают границы систем, поэтому от них требуется другое: стабильность, ясный контракт и предсказуемое поведение. Такое разделение не даёт внутренней модели «утечь» наружу и снижает риск болезненных изменений в будущем. Порядок событий требует внимания Порядок доставки событий — тонкая, но важная тема. Большинство облачных платформ для работы с событиями выбирают масштабируемость, а не строгий порядок. Повторные попытки доставки, задержки и параллельная обработка легко приводят к тому, что события приходят не в том порядке, в котором были созданы. В одних предметных областях это неважно. В других — критично. Обычно здесь есть два рабочих подхода. Первый — явный контроль порядка. События содержат версию или порядковый номер, привязанный к агрегату, а потребитель через логику входящего журнала событий следит, чтобы обработка шла только в правильной последовательности. Подход рабочий, но за него часто приходится платить масштабируемостью. Второй — неявный контроль порядка, когда сама предметная область не даёт системе перейти в некорректное состояние. Например, платёж нельзя обработать, если связанный получатель ещё не создан. Здесь корректность обеспечивается не последовательностью как таковой, а правилами домена. Такой вариант часто масштабируется лучше. Оба подхода нормальны. Важно другое: вопрос порядка нужно решать специально, на этапе дизайна, а не узнавать уже в продакшене, что для вашего домена он оказался критичнее, чем казалось в начале. Сводим всё вместе Такая событийно-ориентированная архитектура собирает в одну систему доменные и интеграционные события, а также паттерны inbox и outbox. В результате получается платформа, которая лучше держит сбои, нормально масштабируется и при этом остаётся удобной для аудита. Каждое значимое изменение состояния фиксируется как событие, надёжно публикуется вместе с сохранением данных, а потребители обрабатывают события через inbox, сохраняя идемпотентность. Для банковской среды это критично: такой подход защищает и от потери, и от дублирования событий.

Рисунок 4: Полная архитектура Разделение доменных и интеграционных событий здесь особенно важно. Доменные события могут спокойно развиваться внутри ограниченного контекста. Интеграционные, наоборот, должны оставаться стабильными и версионируемыми контрактами между системами. За счёт фильтрации, агрегации и преобразования событий на границах контекстов можно не вытаскивать наружу внутреннюю доменную модель и при этом дать системам развиваться независимо, не ломая потребителей. Слабая связанность тоже даёт очень практический эффект. Платежи продолжают работать, даже если зависимые сервисы временно недоступны. Новые возможности можно добавлять, просто подписываясь на существующие потоки событий, не трогая ядро платформы. Плюс сами события формируют естественный аудиторский след: дают сквозную видимость по жизненному циклу транзакции, помогают разбирать инциденты и закрывать требования регуляторов. Когда все эти паттерны встроены в общую платформу для разработчиков, внедрение становится заметно более ровным и предсказуемым. Шаблоны сервисов, общие модули и встроенные механизмы надёжности снимают с команд лишнюю инфраструктурную нагрузку и позволяют сосредоточиться на бизнес-логике. Но без обучения это не работает: инженеры должны понимать не только как поднять сервис, но и как он будет вести себя в продакшене. Заключение Событийно-ориентированная архитектура — не быстрый путь и не «бесплатное» решение. Она приносит с собой новую сложность, новые сценарии отказов и требует другого подхода к проектированию систем. Но если применять её осознанно — с чёткими контрактами событий, проверенными паттернами надёжности и сильной инженерной поддержкой, — она становится прочной основой для современных банковских платформ. По нашему опыту, такой подход позволяет соблюдать жёсткие требования регуляторов и при этом не терять гибкость облачно-ориентированных систем. Он помогает строить системы, которые остаются устойчивыми, расширяемыми и прозрачными в эксплуатации. Если всё сделано правильно, событийно-ориентированная архитектура — это уже не просто технический выбор. Это рабочая модель того, как команды проектируют, запускают и развивают критически важные системы.
 Если после статьи хочется разобрать смежные темы не на уровне схем, а ближе к инженерной практике, обратите внимание на бесплатные уроки от преподавателей Otus. В них есть про event streaming, платформенный подход к разработке и границы микросервисной архитектуры — то есть про те вещи, которые часто определяют, будет событийная система жить в проде или останется красивой диаграммой.
- 13 мая 20:00. «Kafka Streams DSL». Записаться
- 18 мая 20:00. «Деплой на стероидах: ускоряем доставку через Golden Path». Записаться
- 19 мая 20:00. «Грамотная декомпозиция монолита (когда микросервисы не нужны)». Записаться
-Источник
|