Для лучшей иллюстрации я предполагаю API REST для каждого микросервиса.
На мой взгляд, у вас есть IncidentService
, FireHydrantService
и InspectionService
, которые все полагаются на LocationService
.
Следуя микросервисному подходу, вы должны осознавать две цели, которые вы хотите достичь:
- Слабая связь
- Связное поведение
это означает, что вашим службам не разрешено совместно использовать базу данных (это может быть физически, но не логически), поэтому служба не может изменять данные другой службы или напрямую обращаться к своим данным, минуя ответственную службу , Это должно быть сделано ответственной службой исключительно через API. В противном случае связное поведение будет поставлено под угрозу.
RESTful API великолепен, потому что мы хотим также свободно соединяться.
Ресурс может выглядеть так:
"incident": {
"time": "...",
"location" : {
"name": "an arbitrary address"
"href": "apis.yourdomain.com/locationservice/address/1"
"type": "application/json"
},
"nearestHydrant": {
"name": "hydrant 42"
"href": "apis.yourdomain.com/firehydrantservice/hydrant/42"
"type": "application/json"
}
}
Как видите, эти объекты (лучше их представления) представлены только как ссылки, ссылающиеся (сущность) на ответственную службу. Эта связь является слабой, поскольку вероятность того, что ссылка будет изменена как представление сущности, в течение всего срока действия вашего приложения будет меньше. Называя поле, вы также получаете семантику отношения между FireHydrant
и Incident
.
Но все может сложиться очень легко. Предположим, что такое правило, как «доменный объект может быть выдан только ответственным сервисом», чтобы поддерживать связное поведение. Это означает, что только FireHydrantService
разрешено обслуживать FireHydrant
.
Теперь представьте запрос типа «Incident
по адресу 1». К какому сервису нужно обращаться за ближайшим FireHydrant
? Следуя приведенному выше правилу, это должен быть FireHydrantService
. Но как FireHydrantService
знает, что он не знает, что означает ближайший ?
В таком случае существует вещь, называемая неавторизованным кешем (который также можно сохранить в БД). Это просто означает, что LocationService
разрешено хранить FireHydrant
в кеше или в базе данных, но не разрешено делиться ими с другими. Таким образом, вышеприведенное правило все еще соблюдается, а связное поведение все еще под рукой Неавторизованный кеш не должен отражать полный объект домена FireHydrant
, но все необходимое для выполнения UseCases.
Таким образом, IncidentService
запрашивает FireHydrantService
о ближайшем FireHydrant(s)
, что делегируется LocationService
, который запрашивает в своем неавторизованном кэше ближайшее местоположение с типом FireHydrant
, ответ является ссылкой (ссылка ) к самому FireHydrantService
, который проверяет, имел ли FireHydrant
свой Inspection
и, следовательно, действителен ли он в соответствии с бизнес-правилами (если нет, проверял бы следующее) и возвращал ссылку ( Ссылка) на IncidentService
.
Мое эмпирическое правило заключается в том, что каждый сервис может быть запрошен для каждого объекта домена, но может обслуживать только тот объект домена, за который он отвечает. «Запрашиваемые доменные объекты» могут находиться в вышеупомянутом неавторизованном кэше. Это, конечно, приводит к дублированию, и самое интересное - это синхронизировать их. Вещь, которая сразу приходит на ум, - это использование Event Sourcing. Служба генерирует событие «Гидрант 42 вышел из строя», а служба LocationService удаляет гидрант 42 из своего кэша.