Микросервисы: как работать с отношениями внешнего ключа

85

Архитектура микросервисов предполагает, что каждая служба должна обрабатывать свои собственные данные. Следовательно, любая служба (служба A), зависящая от данных, принадлежащих другой службе (служба B), должна получать доступ к таким данным не путем прямых вызовов БД, а через API, предоставляемый второй службой (служба B).

Итак, что предлагают лучшие практики микросервисов для проверки ограничений внешнего ключа.

Пример: я разрабатываю функцию доставки (микросервис 1) для продуктов, и определенные продукты могут быть доставлены только в определенные места, как указано в таблице продуктов, доступной только для микросервиса продуктов (mircoservice 2).

Как мне убедиться, что микросервис 1 (то есть функция доставки) не принимает заказ в необслуживаемое место. У меня есть этот вопрос, потому что функция доставки не может напрямую обращаться к базе данных продуктов, поэтому на уровне БД нет ограничений, когда заказ на доставку размещен в базе данных доставки (невозможно проверить, существует ли совпадение внешнего ключа в базе данных продуктов или стол).


источник

Ответы:

71

Можно использовать общую базу данных для нескольких микросервисов. Вы можете найти шаблоны для управления данными микросервисов по этой ссылке: http://microservices.io/patterns/data/database-per-service.html . Кстати, это очень полезный блог об архитектуре микросервисов.

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

В вашем примере служба доставки может дублировать места доставки и информацию о продукте. Сервисное обслуживание продуктов управляет продуктами и местоположениями. Затем необходимые данные копируются в базу данных службы доставки с асинхронными сообщениями (например, вы можете использовать rabbit mq или apache kafka). Служба доставки не изменяет данные о продукте и местоположении, но использует эти данные при выполнении своей работы. Если часть данных продукта, используемая службой доставки, часто меняется, дублирование данных с помощью асинхронного обмена сообщениями будет очень дорогостоящим. В этом случае вы должны выполнять вызовы api между продуктом и службой доставки. Служба доставки просит службу доставки проверить, можно ли доставить товар в определенное место. Служба доставки запрашивает у службы Продуктов идентификатор (имя, идентификатор и т. Д.) Продукта и местоположения. Эти идентификаторы могут быть получены от конечного пользователя или совместно использоваться микросервисами. Поскольку базы данных микросервисов здесь разные, мы не можем определять внешние ключи между данными этих микросервисов.

Возможно, вызовы API проще реализовать, но в этом варианте стоимость сети выше. Кроме того, ваши службы менее автономны, когда вы выполняете вызовы api. Потому что в вашем примере, когда служба продукта не работает, служба доставки не может выполнять свою работу. Если вы дублируете данные с помощью асинхронного обмена сообщениями, необходимые данные для доставки находятся в базе данных микросервиса доставки. Когда обслуживание продукта не работает, вы сможете осуществить доставку.

Али Сахлам
источник
2
Отличный ответ. Я использую вызовы API, но для этого также нужна сортировка и разбивка на страницы данных из другой службы. Вы знаете лучший подход для этого случая?
tranceholic
6
Вы должны добавить параметры, связанные с разбивкой по страницам и сортировкой, в свой api. Тогда ответственность за получение нужной страницы в правильном порядке возьмут на себя потребители API. Есть несколько технологий, используемых для определения API, например GraphQL. Насколько мне известно, в этих технологиях уже есть функции сортировки и нумерации страниц. Если вы не используете такую ​​технологию, вы можете просто получить параметры от своего клиента и использовать их для возврата данных, отсортированных по страницам.
Али
1
Действительно отличный ответ!
TS
2
Но сохраните ли вы внешний ключ? Пример: у каждого сообщения в блоге будет много комментариев. У Monolith будет таблица комментариев с внешним ключом к записи в блоге. Однако в микросервисе у нас будет две службы. Сервис 1: Публикация микросервиса с этими полями таблицы (PostID, Name, Content) Сервис 2: Комментарии Microservie с этими полями таблицы (CommentID, PostID, Cpmment) Вопрос в том, нужен ли нам «PostID» в сервисе 2 (микросервис комментариев)? Думаю, ответ положительный, поскольку нам нужно знать, какой комментарий к какому посту принадлежит. Я правильно понимаю?
rakesh mehra
1
Как разделить систему на микросервисы - это совсем другая история, но если вы решили создать 2 микросервиса, такие как публикация и комментарий, вам понадобится идентификатор записи в микросервисе комментариев, поскольку каждый комментарий принадлежит публикации. Однако это не означает, что вам нужно определять FK между этими таблицами. FK - это только ограничение в мире СУБД, которое помогает обеспечить целостность и согласованность данных. Если вы храните данные этих микросервисов в отдельных схемах, вы не можете определить FK или даже можете хранить свои данные в базе данных nosql (что имеет смысл для микросервиса комментариев), где FK не применяется.
Али Сахлам
24

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

Другой момент заключается в том, что только один компонент в вашей системе владеет данными (для операций изменения состояния), другие компоненты могут ЧИТАТЬ, но НЕ ЗАПИСАТЬ, у них могут быть копии данных или вы можете поделиться моделью представления, которую они могут использовать для получения последнего состояния. объекта.

Введение ссылочной целостности снова приведет к связыванию, вместо этого вы хотите использовать что-то вроде Guids для своих первичных ключей, они будут созданы создателем объекта, а все остальное - это управление конечной согласованностью.

Взгляните на выступление Уди Дахана в NDC Oslo для получения более подробной информации.

Надеюсь это поможет

Шон Фармар
источник
2
Ссылка на выступление Уди Дахана очень интересна
Comencau
3

первое решение: состав API

 Implement a query by defining an API Composer, which invoking the
 services that own the data and performs an in-memory join of the
 results

введите описание изображения здесь

второе решение: CQRS

Define a view database, which is a read-only replica that is designed to support that 
query. The application keeps the replica up to data by subscribing to Domain events 
published by the service that own the data.

введите описание изображения здесь

Ali_Hr
источник
1

Обновление 2020 года для этого ответа заключается в использовании инструмента сбора измененных данных, такого как Debezium. Debezium будет отслеживать изменения в таблицах вашей базы данных и передавать их в Kafka / Pulsar (другие каналы), после чего ваши подписчики могут фиксировать изменения и синхронизировать их.

user521990
источник