Я занимаюсь исследовательским проектом, в котором изучаю варианты обработки изменений в микросервисной архитектуре, управляемой событиями.
Итак, скажем, у нас есть приложение, в котором мы получили четыре разных сервиса. Каждый из этих сервисов имеет собственную базу данных для хранения локальных данных.
В этой настройке четыре службы обмениваются данными друг с другом с помощью шины событий. Поэтому, когда что-то происходит в сервисе, оно публикует событие. Все остальные сервисы, которые заинтересованы в этом событии, будут обрабатывать его по-своему.
В этом случае различные сервисы в архитектуре должны иметь «контракты» относительно содержания этих событий (атрибутов и т. Д.). Так что сервисы имеют «слабо связанные зависимости» от этих событий
Мой вопрос: как мы можем справиться с изменениями в этих событиях?
Итак, скажем, служба A регистрирует новых пользователей в приложении. Поэтому он отправляет событие «UserRegistered». Служба B получает это событие и обрабатывает его. Но некоторые разработчики из команды службы C решили, что им также нужен пол зарегистрированного пользователя. Таким образом, событие изменилось и пол атрибута добавляется в событие «UserRegistered».
Как мы можем быть уверены, что Служба B все еще может получить одно и то же событие с этим дополнительным атрибутом без повторного развертывания?
И есть ли другие способы решения этой проблемы, кроме создания версий этих событий?
Ответы:
События не о том, что изменилось. Они о том, когда что-то изменилось.
Я могу создать систему событий, полностью отделенную от содержимого, которое изменилось. Таким образом, все, что я узнал из события, это то, что объект был обновлен. Если я даже забочусь о том, что объект был обновлен, я скажу любому, кто знает, как разговаривать с этим объектом, чтобы спросить, что изменилось.
Это не решает проблему передачи этих изменений. Это просто мешает ему стать частью системы событий.
Примером одного из способов решения проблемы разных версий данных является создание наблюдателем и передача наблюдаемого объекта в коллекцию. Наблюдаемый объект заполняет коллекцию самыми последними данными, и когда управление возвращает, вы (наблюдатель) получаете то, что вам нужно. Если есть еще что-то, что вас не волнует, потому что вы никогда не слышали об этом, вы просто игнорируете это.
Множество других способов снять шкуру с этой кошки, но это один из тех, что я сделал именно в этом случае.
источник
UserRegistered
событие, если было событие, которое не содержало информацию о пользователе, было бы 1 опубликованное сообщение на шину и затем {количество заинтересованных служб} запросов к службе пользователя или опубликованные сообщения в автобус. Затем будут сообщения {количество заинтересованных служб} разного размера. Хотя я думаю, что это, вероятно, более чистый дизайн на бумаге, если производительность вызывает беспокойство, она ломается в любой нетривиальной системе, особенно в сети.Фреймворки, такие как NServiceBus, обрабатывают это, используя управление версиями событий с полиморфной отправкой сообщений.
Например, версия 1 службы A может опубликовать событие как IUserRegistered_v1. Когда Service A версии 1.1 необходимо включить дополнительное поле, оно может объявить интерфейс IUserRegistered_v1_1, который будет наследоваться от IUserRegistered_v1, а также объявить некоторые дополнительные поля.
Когда служба A публикует событие IUserRegistered_v1_1, NServiceBus отправляет сообщение всем конечным точкам, которые обрабатывают IUserRegistered_v1 или IUserRegistered_v1_1.
источник
Постепенное улучшение
Простое изменение модели заключается в том, что когда слушатели регистрируются в качестве наблюдателя, они включают список или другую структуру элементов данных, о которых они хотят знать. Это может работать, если данные, возвращаемые из службы, просты, но если у вас есть достаточное количество иерархических данных, это может быть очень сложно реализовать.
Скала
Если вы действительно хотите надежный способ сделать это, спроектируйте сервис так, чтобы он сохранял историю изменений, которые были внесены в данные, которые он хранит. По сути, вы никогда не обновляете записи в своей базе данных, вы добавляете новые записи, где каждая представляет изменение. Каждая из этих новых записей связана с идентификатором события, который идентифицирует действие. Сохраняется четная запись со всей необходимой информацией об изменении (кто, что, когда и т. Д.). Это имеет некоторые другие преимущества, которые выходят за рамки этого ответа, но обсуждаются в этой статье о теореме CAP .
После внесения изменений вы создаете запись о событии и добавляете все новые данные в свою базу данных. Затем вы публикуете событие для слушателей, которое содержит (минимально) идентификатор события. Затем слушатели могут запросить данные, связанные с этим идентификатором, и получить версию данных, связанных с ним. Тогда каждый слушатель может получить все, что ему нужно, без объединения потребностей других разных слушателей. Я бы посоветовал вам добавить подмножество наиболее часто используемых полей данных в сообщение о событии, чтобы слушатели могли отфильтровывать события, которые им не интересны. Это может снизить болтливость процесса, и некоторым слушателям, возможно, никогда не потребуется вызывать назад на всех. Это также защищает вас от проблем со временем. Если вы просто перезвоните в сервис и получите данные на основе ключа, могут быть другие изменения, произошедшие между получением события и получением данных для него. Это может не иметь значения для всех слушателей, но может создать большие проблемы, если вам нужно знать обо всех изменениях. Вышеупомянутое пошаговое улучшение дизайна совместимо с этим подходом, если вы действительно хотите включить его в 11.
Отчасти это может быть излишним для того, что вам нужно сделать, но, по моему опыту, если у вас нет точного способа посмотреть, как меняется запись с течением времени, вы или кто-то, работающий с вашими данными, в конечном итоге захотят этого.
источник
@CandiedOrange делает правильный комментарий в комментарии к своему собственному ответу относительно расширяемых форматов данных, таких как xml.
Это не должно иметь значения, пока вы добавляете данные. Однако предоставьте разумные значения по умолчанию для более старых событий / необязательных полей.
Вам нужно только обновить услуги, которые касаются - в данном случае - пола. Анализатор xml / json должен иметь возможность игнорировать дополнительные данные для других служб. Конечно, это зависит от вашего выбора парсера и формата данных события.
Я не согласен с событиями, не имеющими соответствующих данных, хотя. Для получения событий события должны определять, что изменилось. При получении события другим сервисам не нужно извлекать данные из источника события.
источник