В микросервисах должны ли данные храниться в одном сервисе или дублироваться между сервисами? - PullRequest
1 голос
/ 15 марта 2020

У меня есть сервис Scheduler, который позволяет мне добавлять запланированные задачи. Эта служба просто сохраняет в своей базе данных запланированное время и конечную точку для вызова при запуске задачи.

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

На внешнем интерфейсе он должен отображать всю информацию о запланированной задаче напоминания по электронной почте, такую ​​как электронная почта получателя, содержимое электронной почты и была ли она выполнена. Интерфейс извлекает большую часть этой информации из API, находящегося в службе EmailReminder. Это просто, потому что все данные, которые он должен показывать в API из собственной базы данных.

Однако моя дилемма заключается в том, должен ли я сохранять статус done в базе данных службы Scheduler или сохранять этот статус в собственной базе данных соответствующих служб.

Если статус был сохранен в сервисе Scheduler ...

Если я сохраняю статус «выполнено» в сервисе Scheduler, всякий раз, когда другие сервисы должны знать, выполняется ли задача сделано, они должны сделать вызов API для службы Scheduler. Другими словами, сервис EmailReminder должен извлекать статус «выполнено» из сервиса Scheduler для всех записей каждый раз, когда его API вызывается из внешнего интерфейса. Я считаю, что это также повлечет за собой дополнительное время на общий запрос. Но плюсы этого - то, что база данных в сервисе Scheduler является единственным источником правды о том, выполнена задача или нет.

Если статус был сохранен в соответствующих сервисах ...

В этом случае службе EmailReminder не требуется выполнять дополнительный вызов API к службе Scheduler. Информация доступна в собственной базе данных. Это также означает, что при изменении статуса done в службе Scheduler необходимо отправить событие, чтобы сообщить всем службам об обновлении их статуса. Однако недостатком этого является то, что я в основном имею дублированные копии одного и того же фрагмента информации (статус done) в 2 местах; сервис Scheduler и сервис EmailReminder. Существует риск того, что данные могут стать противоречивыми.

В такой микросервисной архитектуре, как та, что у меня есть, лучше хранить такую ​​информацию в службе Scheduler или в соответствующих службах?

Ответы [ 5 ]

1 голос
/ 15 марта 2020

Я думаю, вы должны хранить эту информацию в обеих службах.

Допустим, Scheduler просит EmailReminder отправить электронное письмо с идентификатором # 123, а EmailReminder отправляет электронное письмо и локально сохраняет состояние «электронная почта # 123 отправлено», но подтверждение не происходит (Scheduler не получает ответ или не может сохранить ответ). Теперь у Scheduler нет другого выбора, кроме как повторить запрос. Но когда EmailReminder получает запрос, он знает через свое собственное состояние, что почта уже отправлена, и служба может безопасно не отправлять почту, а просто ответить подтверждением - что, надеюсь, сработает на этот раз.

Когда Scheduler получает ответ, он будет локально сохранять состояние «запланированная задача # 123 завершено» и перестанет повторять запрос.

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

Как Scheduler может изменить свое значение, если это не служба EmailReminder, сообщающая об этом, она имеет сделано?

Существует риск того, что данные могут стать несогласованными.

Да, несогласованные данные здесь означают, что запрос необходимо повторить.

Следует отметить, что такая же проблема несоответствия существует в самой службе EmailReminder, так как электронная почта может быть отправлена, и ошибка предотвращает локальное т. е. корректно обновляется. Таким образом, всегда есть вероятность, что письмо будет отправлено дважды («хотя бы один раз», или вы можете выбрать «не более одного раза», изменив состояние перед отправкой), - но при этом риск ниже.

0 голосов
/ 14 апреля 2020

EmailReminder - единственный объект, который знает, когда было отправлено электронное письмо (т. Е. Задание done).

При использовании подхода, управляемого событиями, EmailReminder может инициировать done событие, которое может быть перехвачено всеми другими участниками системы. Таким образом, каждый может получить копию информации. Это хорошо с точки зрения производительности и устойчивости, если вы имеете дело с недостатками (определение мастера для определенного c набора данных, возможной согласованности и т. Д.).

Вам необходимо оценить, является ли это применимо к вашей системе.

Удачи в вашем проекте.

0 голосов
/ 18 марта 2020

Простой вопрос о совместной обработке. Продукт, произведенный модулями, должен существовать в одном месте, и каждый модуль должен нести ответственность за знание, обрабатывать его или нет. Другими словами, статус «выполнено» - это столбец конечного продукта, а не какой-либо конкретной службы, работающей с ним.

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

0 голосов
/ 16 марта 2020

В общем, я рекомендую не кэшировать / дублировать данные, если у вас нет для этого причины. Аннулирование кэша считается одной из двух сложных вещей в информатике . Подписка на события нисходящих сервисов также добавляет сложности, что увеличивает общую стоимость. Обратите внимание, что я огромный фанат Event-Driven Architecture / Messaging - я просто считаю, что вы должны быть осторожны в том, где и когда вы его используете.

На мой взгляд,

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

не обязательно является отрицательным.

Если эти вызовы очень часто и / или вызывают (или могут вызвать) проблемы с производительностью, это другая история, и кеширование имеет смысл.

0 голосов
/ 15 марта 2020

Это правильная дилемма, и я не думаю, что есть идеальный ответ на это. Каждое решение будет иметь компромисс. В какой-то момент это также сводится к событию Fat против события Thin.

В сценарии события Fat вы бы отправили информацию Status вместе с сообщением, находясь в Thin событие, вы отправляете только событие, а не данные.

Допустим, у вас есть много зависимых служб от ваших Scheduler услуг. Если вы решите инициировать ваше событие без дополнительных данных (или информации о состоянии), у вас могут быть все эти службы, вызывающие ваш API и запрашивающие обновленный Status, вызывающий дополнительную нагрузку на службу. Хотя это может повлечь за собой снижение производительности из-за выполнения дополнительного звонка по проводной связи, если вы не работаете с критичным по времени приложением, я не думаю, что это действительно проблема. Вы также можете кэшировать ответ на сервере, чтобы избежать вызова БД.

Если вы выберете событие Fat, то, поскольку вы отправляете информацию «Статус» вместе с вашим событием, вы не захотите нужен дополнительный вызов API. Это, однако, означает, что вам потребуется дополнительное хранилище для хранения «Статус» в каждой службе. Но хранение - это товар, оно дешевое и, вероятно, не должно быть причиной неиспользования события FAT. Здесь, конечно, есть риск, что если кто-то из подписчиков пропустит событие. Однако управляемая событиями архитектура сопряжена с этими рисками, и вам необходимо сделать свои службы отказоустойчивыми к этим проблемам. Существуют платформы, такие как Kafka и NServiceBus , которые помогают вам снизить эти риски.

...