Это продолжение цикла статей про разработку архитектуры. Ссылки на статьи:

Event driven architecture (EDA)

Ещё одна из популярных архитектур — Event driven architecture (EDA), что в переводе на русский означает “архитектура на основе событий”. Суть данной архитектуры состоит в том, что приложение работает с событиями (эвентами), которые генерируются пользователем или другими системами.

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

Юзер послал запрос на сервер, который в свою очередь сходил в базу данных и обновил в ней данные. И всё бы хорошо, но если у нас процесс обновления локации будет содержать сложные проверки и вычисления, то это негативно повлияет на общую скорость работы системы и, как следствие, на user experience. В таком случае наши пользователи просто начнут отваливаться и не обновят запросы в базе данных. Если у нас процесс занимает какое-либо время, то лучше это спроектировать, используя паттерн эвентной архитектуры. В таком случае на запрос пользователя будет создан только эвент, говорящий о том, что пользователь хочет обновить определенные данные в базе. Однако все проверки и само обновление будет выполняться уже позже и другим сервисом. На схеме это будет выглядеть так:

Юзер сделал запрос на сервер и создал эвент о том, что хочет обновить данные в базе. Этот эвент кладется либо в очередь сообщений, либо в Kafka, это уже дело вкуса. 

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

То есть, если вы хотите, чтобы ваши микросервисы общались в архитектуре EDA, то выглядеть у вас это будет примерно так:

На самом деле, данная архитектура несёт в себе много недостатков, хотя есть и преимущества. Давайте, по классике, начнём с недостатков:

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

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

  • Требуется больше вычислительных ресурсов на создание эвентов и их чтение. При неоптимальном подходе эвентная архитектура может занимать до 50% вашего процессорного времени сервера, хотя конечно, как правило, если такую архитектуру использовать правильно и в нужном месте, то использование накладных ресурсов не будет превышать 10-15% мощности сервера.

  • Также появляется единая точка отказа — это наша шина. К счастью, сейчас шины надёжные, но об этом всё равно нужно помнить.

  • Требуется  много памяти для хранения самих эвентов.

Окей, с недостатками разобрались. Что там по преимуществам?

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

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

  • Вы также можете отследить любой момент времени и откатить продукт к состоянию на любую дату.

  • Становится намного проще распределять нагрузку на сервер по времени суток. Если в системе есть пиковые часы нагрузок, а в остальное время сервер простаивает, то в пиковые часы вы можете просто создавать эвенты, а сервер, предназначенный для их обработки, будет просто постепенно их обрабатывать, не сильно думая о том, что ему это нужно сделать за 10 секунд пока http request пользователя не закрылся.

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

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

Я так же оставлю ссылку на статью об антипатернах в эвентной архитектуре: "Антипаттерны событийно-ориентированной архитектуры".

Со статьёй помогала @Ethera, за что ей большое спасибо и плюсик в карму, если кто может.)

Комментарии (9)


  1. lair
    19.04.2022 14:32

    Event system architecture (EDA),

    Как у вас из Event System Architecture получилось EDA?


    1. Kecven Автор
      19.04.2022 14:57

      eda (event driven architecture). Да, ошибочка. Поправлю.


  1. comerc
    19.04.2022 15:01
    +1

    Человек старается, хотя уже две первые части заминусовали. Настойчивость - самое главное качество. Плюс в карму и на заметку.


    1. Kecven Автор
      19.04.2022 15:31
      +1

      Спасибо, на этот раз мне помогала @Ethera с проверкой на ошибки. )


    1. nibb13
      19.04.2022 18:22
      +2

      Присоединяюсь ко мнению! Материалы интересные, понятные и в перспективе получится полезный гайд для начинающих. Отдельный плюс автору за краткость.


  1. makar_crypt
    19.04.2022 19:01

    И как в этом архитектурном варианте решается проблема "случайно не перезаписать" по американски это называется false positive конкуренция?

    Пример всё как у вас: есть сервис БИЛИНГ и ЛОТ:

    СРАЗУ УЧТЕМ ЧТО СЕРВИСЫ ВЫПОЛНЯЮТСЯ в 1м экземпляре, в 1 потоке.

    1) 2е пользователей одновременно жмут кнопку "купить лот",

    2) WEB API создает 2 сообщений в шину для сервиса ЛОТ

    3) сервис ЛОТ делает базовые проверки, что лот существует , у него есть цена, и т.д. выплевывает 2 сообщений в шину для БИЛИНГА "списать 500$"

    4) БИЛИНГ начинает очухивается и начинает обрабатывать и у 1го и у 2го пользователя удачно списываются деньги. Выплевываеет 2 сообщения обратно в сервис ЛОТ

    5) И тут приходит 1е сообщение , мы перезаписываем допустим OWNER_ID=1 у лота, а потом приходит 2е сообщение и бац мы перезаписывает на OWNER_ID=2.

    Сразу откину решение что на шаге "3" помечать что этот лот уже в процессе обработки , и 2е сообщение уже на этом этапе откидывать, сказав "брат всё, этот лот уже в процессе сорри". Т.К. когда сообщение 1го человека дойдет до БИЛИНГА, тупа у человека не хватит денег, а мы ВТОРОГО уже откинули, хотя он мог купить т.к. у него хватало денег. Вы хотите терять деньги? я нет.

    Надеюсь понятно описал простую ситуацию.


  1. stone_evil
    20.04.2022 06:58

    Все слишком поверхностно, в каждом пункте плюсов\минусов крайне спорные утверждения, а от словосочетания "эвентная архитектура" испытываешь мини-оргазм. Боюсь, что эту статью я бы не рекомендовал "чайникам", только хуже себе сделают.


    1. makar_crypt
      20.04.2022 13:28

      ну если автор не может ответить , а вы профи, могли бы и мне выше ответить


  1. Emil983
    20.04.2022 19:00

    Что-то тут разные вещи смешаны, message bus да и вообще EDA подразумевает именно общение сервисов через события. Вот это "Вы также можете отследить любой момент времени и откатить продукт к состоянию на любую дату" совсем не обязательно подразумевается в EDA. Для этого всё-таки должен быть реализован event sourcing, обычно событие удаляется из шины после того как потребитель его обработал и передал acknowledgement о нем.