В микросервисной ахриктектуре бывают зависимости, которые накладывают определенные ограничения на используемые сервисы.
Для примера, рассмотрим сервис аренды машин, где используется принцип database per service:
- Микросервис geoareas владеет данными о разных географических полигонах — городах, районах: {id, geometry}
- Микросервис tariffs в свою очередь распоряжается данными о стоимости аренды: {id, geoarea_id, price_per_minute}. Есть зависимость от сервиса geoareas.
В какой-то момент нам понадобилось удалить объект из микросервиса geoareas — вызвать endpoint:
DELETE /geoarea?id={id}.
Это может повлечь ряд проблем вплоть до недоступности микросервиса, т.к. у нас останутся тарифы, указывающие на удаленную геозону.
Появляется неприятная зависимость: чтобы удалить геозону из geoareas нужно в момент удаления сделать запрос в tariffs, чтобы проверить — не зависит ли от нее какой тариф.
Появляется опасная связанность — при таком подходе geoareas в будущем будет отправлять запросы во все микросервисы, где используются геозоны.
В базах данных, кстати, есть автоматический контроль целостности с помощью внешних ключей.
У нас же распределенная микросервисная архитектура и есть несколько вариантов решения:
1. Webhooks
Вариант подразумевает создание в микросервисе, от которого будут зависеть другие микросервисы унифицированного механизма веб-хуков.
Микросервис будет исполнять эти хуки перед тем, как изменить объект. Если хоть один хуков завершился неудачей, то действие над объектом невозможно.
Примером такого веб-хука может быть запрос в сторонний микросервис с предопределенным API.
Для нашего примера веб-хук в микросервисе geoareas выглядел бы следуюшим образом:
WEBHOOK target=”pre-delete” action=”POST tariffs/check_delete?geoarea_id={id}”
В микросервисе tariffs, соответственно, нужно реализовать endpoint /check_delete для проверки того, что зону можно удалить и микросервис tariffs «не против».
Унифицированность таких хуков позволяет легко конфигурировать их на лету. При появлении нового микросервиса, который использует geoareas добавлять в список хуков новую проверку.
Таким образом, geoareas поддерживает механизм унифицированных веб-хуков, но ничего не знает про то, что за логика внутри этих хуков.
2. Reference Counting
В этом варианте мы будем следить за тем, кто использует геозоны.
Расширяем API нашего микросервиса geoareas следующими endpoints:
POST /hold?geoarea_id={id}&holder={holder}
POST /release?geoarea_id={id}&holder={holder}
Таким образом, если хотим создать новый тариф в зоне, то перед этим нужно эту зону заблокировать в сервисе geoareas, например:
POST /hold?geoarea_id=moscow&holder=tariffs_tariffmoscow1
Рядом с геозонами в микросервисе geoareas будем хранить список тех, кто «держит» эти геозоны.
При попытке удаления геозоны проверяем список держателей и не даем удалять, если список не пуст.
Если тариф, держащий геозону, удаляется, то после удаления нужно отпустить блокировку, например:
POST /release?geoarea_id=moscow&holder=tariffs_tariffmoscow1