Распределенные транзакции в архитектуре микросервиса, как обрабатывать таймауты и неудачные фиксации
Допустим, у вас есть услуга A
это является частью большой микросервисной архитектуры, где эти сервисы обмениваются данными друг с другом либо через API REST, либо через обмен сообщениями, в которых участвует какой-либо брокер (RabbitMQ). обслуживание A
предоставить конечную точку REST, которая должна взаимодействовать с каким-либо сторонним сервисом (например, с сервисом, которого нет в нашей архитектуре), и создавать некоторые вещи там, когда сервис A
Получив ответ от третьей стороны, что все прошло хорошо, он должен сохранить некоторые данные из этого ответа в своей собственной базе данных.
Что было бы лучшим способом решения следующих вопросов, учитывая, что третья сторона не предоставляет никакого механизма идемпотентности.
Создание на сторонней стороне прошло успешно, но запись в БД не сработала
A
, Это может привести к противоречивому состоянию, вы создали что-то на стороне, но у вас нет данных об этом в вашей собственной базе данных.Вы получили тайм-аут от третьей стороны, поэтому вы не можете просто повторить вызов, потому что они не предоставляют никакого механизма идемпотентности. Если вы повторите вызов, потенциально вы можете закончить двумя (или более) созданными ресурсами вместо одного.
Проблема № 1. может быть решена с помощью любого механизма повторных попыток, который может повторять вызов БД для любого количества раз. Проблема с этим подходом заключается в том, что если сервис A
экземпляр, который повторяет вызов БД, неожиданно завершает работу.
Предположительно, лучшим подходом будет то, что сервис после успешного создания на сторонней стороне публикует сообщение RabbitMQ об успешном создании. Эта служба будет прослушивать это сообщение и при вызове может выполнять вызов БД. Имея хороший механизм повтора и пользуясь сообщениями ACKing, можно решить проблему, What if service instance goes down suddenly
, Таким образом, в этом решении служба является издателем и потребителем собственных сообщений. Есть идея получше? Это решение также представит возможную согласованность, потому что вызывающий API (парень, который вызывает службу A
конечная точка) получит ответ сразу после успешного создания на сторонней стороне, но до того, как что-либо сохранится в сервисной базе данных (что на самом деле нужно клиенту API)
Как насчет проблемы тайм-аута? Как справиться с таймаутами от третьих лиц в этом случае?, Я не вижу ничего лучше, чем отправлять вызовы GET, чтобы проверить, что они что-то создали. Еще раз, что вызов GET может быть неудачным, но его можно повторять до тех пор, пока он не будет успешным. Здесь также предельный вариант использования - это что если сервис перестает работать во время вызова GET.
1 ответ
Нелегко правильно настроить отказоустойчивость. Я помню, что для стека netflix они реализовали специальный модуль: hystrix. Может быть, это поможет вам.