Циклическая зависимость клиентов микросервисов

#php #node.js #microservices

#php #node.js #микросервисы

Вопрос:

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

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

Вот сценарий:

  • Две службы: автомобильная и страховая
  • Два клиентских пакета, CarClient и InsuranceClient.

Всякий раз, когда какой-либо службе необходимо связаться с автосервисом, она должна использовать для этого пакет CarClient . И всякий раз, когда какой-либо службе необходимо взаимодействовать со службой страхования, она должна использовать пакет InsuranceClient .

Пакет CarClient имеет объект передачи данных (DTO) Car , где одним из его свойств является insurance . Типом для этого свойства является DTO, доступный в пакете InsuranceClient, CarInsurance .

Проблема заключается в том, что CarInsurance DTO должен получить доступ к перечислению, доступному в пакете CarClient, CarTypeEnum . Теперь у нас есть два пакета, зависящих друг от друга.

Циклическая зависимость клиентов микросервисов

Возможные решения, которые я могу придумать:

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

Любая помощь приветствуется.

Комментарии:

1. Почему Car и Insurance являются двумя отдельными клиентами / службами? Не могли бы вы объединить их? Я всего лишь новичок и не знаю подробностей ваших приложений, но если две службы уже зависят друг от друга, почему бы не собрать все под одной крышей?

2. Служба страхования выполняет множество задач, не связанных с автомобилями, включая другие виды страхования (например, страхование жилья). Идея микросервиса состоит в том, чтобы разделить эти задачи в их собственном репозитории (сервисе), чтобы мы могли более эффективно кодировать и развертывать. Однако за это приходится платить, поскольку это добавляет немного сложности.

3. Вы говорите о a package в смысле Java? Потому что тогда почему циклическая зависимость является проблемой в этом случае?

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

Ответ №1:

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

В архитектуре MS CarDTO будет иметь свойства, связанные только с car. Если вам нужна информация о страховании, это будет отдельный вызов страховой службы для получения InsuranceDTO, который имеет только страховые свойства.

При вызове любой службы вы должны использовать некоторый ключ, чтобы связать все это воедино. Т.Е. Вы должны позвонить в автосервис с идентификатором клиента, который вы получили от службы поддержки клиентов, и у вашей CarDTO будет carId, затем вы можете позвонить в страховую службу с CustomerID / carId, чтобы получить InsuranceDTO.

Комментарии:

1. Мы извлекаем службу страхования, чтобы получить страховку, но мы добавляем этот объект к свойству в Car dto. Вот почему нам нужен тип. Но, допустим, мы этого не делаем, как нам справиться с проблемой перечисления? Службе страхования необходимо знать, для какого типа автомобиля ей необходимо создать страховку, поэтому она получит идентификатор типа автомобиля с полезной нагрузкой. Вот почему dto обладает этим свойством. Поскольку dto находится в страховом клиенте, этот клиент зависит от клиента car для доступа к перечислению типа car. Если мы этого не сделаем, нам нужно будет дублировать перечисления между этими репозиториями.

2. @crabbly Именно поэтому у вас возникают проблемы. Вы пытаетесь тесно связать две службы. DTO должны быть полностью разделены. Представьте, что вы меняете общий класс и вносите критические изменения — теперь вам нужно перестроить все, что его использует, и повторно развернуть все, что его использует, и вы можете что-то пропустить. Представьте, что у вас 1000 сервисов. Изменение общего класса означало бы повторное развертывание всего.

3. @crabbly В MS вы должны иметь возможность развертывать одну службу и ничего не нарушать или повторно развертывать что-либо, кроме этой службы. Критическое изменение в MS «не разрешено», и вам необходимо разрабатывать свои сервисы с учетом «контроля версий». Например, мы используем согласование типов контента на нашем, и это отлично работает, хотя это немного сложнее сделать правильно. В конце дня /cars / v1 будет иметь вашу текущую версию, а / v2 будет иметь версию с критическими изменениями, и службы могут переходить на v2 по мере необходимости.

4. PS можно «копировать и вставлять» DTO в MS. В конце концов, это просто json. Вы, вероятно, не хотели бы делиться DTO сервера с DTO клиента в любом случае, поскольку они, вероятно, будут отличаться в реальном мире (аннотации и тому подобное).

5. Когда мы меняем DTO, мы меняем контракт Api, поэтому мы должны ожидать, что что-то сломается, несмотря ни на что. Вот почему мы занимаемся управлением версиями. Чтобы этого не произошло. Итак, это не проблема для нас, и это не связано с проблемой выше. Проблема на самом деле просто пытается повторно использовать эти DTO и перечисления. Итак, по вашему мнению, мы должны просто дублировать их в каждом репозитории. Я думаю, это способ сделать это, и он действительно исправит зависимость.

Ответ №2:

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

Если вы разрабатываете свои сервисы на основе идеи DDD (domain driven design), вы можете знать, что одна и та же концепция / сущность может означать разные вещи в разных доменах.

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

Комментарии:

1. Да, в некоторых случаях это кажется правильным подходом. Особенно с перечислениями. В других сценариях, похоже, нам, вероятно, следует устранить зависимость на уровне клиента и позволить службе обрабатывать отношения внутри.

Ответ №3:

Вы могли бы просто не использовать CarTypeEnum в своей страховой службе. Просто используйте carId. Когда вам нужно знать тип, просто попросите автосервис предоставить эту информацию.

Комментарии:

1. Перечисление полезно при использовании типа car для бизнес-логики. Вместо того, чтобы реагировать кодом на статические числа, лучше вместо этого использовать перечисления.