Как создать механизм воспроизведения в микросервисе Event-Drive

У нас есть 7 микросервисов, подключенных через eventbus. У нас есть последовательность транзакций в реальном времени:

Сервис 1-> Сервис2-> Сервис3 (и т. Д.) До тех пор, пока транзакции не будут считаться завершенными

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

Конечно, у нас могут быть сбои в любой момент. Таким образом, мы думаем о механизме, чтобы воспроизвести "недоделанные" транзакции в завершении.

Это становится сложно. Два способа, о которых мы думали:

  1. Наличие другой службы (службы супервизора), которая будет регистрировать каждую часть в нашей последовательности в реальном времени и будет достаточно умной, когда транзакции не завершены (тайм-аут), чтобы понять, как мы можем продолжить с левой точки

    Недостатки: много "умной" логики на одном центральном сервисе

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

    Недостатки: много повторяющегося кода на каждом сервисе

Что вы эксперты думаете?

Поблагодарить

2 ответа

Решение

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

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

Я полагаю, что вы могли бы получить больше понимания от таких понятий, как:

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

Мне особенно понравилась глава в книге " ОТДЫХ от исследований к практике". В главе 23 " На пути к распределенным атомарным транзакциям через сервисы REST ful" подробно объясняется шаблон " попробовать / отменить / подтвердить".

В общих чертах это означает, что когда вы выполняете группу транзакций, их побочные эффекты не действуют, пока координатор транзакций не получит подтверждение, что все они были успешными. Например, если вы бронируете рейс в Expedia и ваш рейс состоит из двух рейсов с разными авиакомпаниями, то одна транзакция резервирует рейс с American Airlines, а другая - с United Airlines. Если ваша вторая бронь не удалась, вы хотите компенсировать первую. Но не только это, вы хотите избежать того, чтобы первое бронирование действовало до тех пор, пока вы не смогли подтвердить оба. Таким образом, первоначальная транзакция резервирует, но сохраняет свои побочные эффекты в ожидании подтверждения. И вторая оговорка будет делать то же самое. Как только координатор транзакций узнает, что все зарезервировано, он может отправить сообщение подтверждения всем сторонам, чтобы они подтвердили свое бронирование. Если резервирование не подтверждено в течение разумного промежутка времени, оно автоматически отменяется, но это затрагивает систему.

В книге Enterprise Integration Patterns есть некоторые базовые идеи о том, как реализовать этот вид координации событий (например, посмотрите шаблон менеджера процессов и сравните его с шаблоном маршрутизации, который похож на идеи оркестровки и хореографии в мире микросервисов).

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

В книге " Шаблоны микросервисов" есть целая глава под названием "Управление транзакциями с Sagas", в которой подробно рассматривается, как реализовать решение такого типа.

Несколько других аспектов, которые я обычно рассматриваю, следующие:

идемпотентность

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

Переходные и постоянные ошибки

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

Ошибка восприятия как альтернативный поток

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

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

Транзакция и состояние модели данных являются ключевыми

Я обнаружил, что этот тип транзакционных рабочих процессов требует хорошего проектирования различных состояний, через которые должна пройти ваша модель. Как и в случае шаблона "попробовать / отменить / подтвердить", это подразумевает первоначальное применение побочных эффектов без обязательного предоставления пользователям доступа к модели данных.

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

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

Проектирование распределенных транзакционных рабочих процессов

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

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

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

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

Насколько я знаю (и вы, возможно, уже знаете), кажется, что вы пытаетесь реализовать шаблон прерывателя цепи и использовать ли его как центральную службу или как часть вашей логики бизнес-транзакций.

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

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

Другие вопросы по тегам