Шаблон компенсирующих транзакций

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

Контекст и проблема

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

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

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

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

Решение

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

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

На схеме показаны шаги по созданию маршрута и шагам компенсирующей транзакции, отменяющей маршрут.

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

Сбой одного шага не всегда требует отката всей системы с помощью компенсирующей транзакции. Например, на туристическом веб-сайте клиент бронирует рейсы F1, F2 и F3, но не может зарезервировать номер в отеле H1. Предложить клиенту номер в другом отеле предпочтительнее, чем отменить рейсы. Клиент по-прежнему может отменить бронирование, что активирует компенсирующую транзакцию для отмены бронирования рейсов. Однако клиент должен принять это решение, а не систему. Когда решения оказывают большое влияние или трудно автоматизировать надежно, включите человека в процесс принятия решений.

Рассмотрим следующие важные моменты:

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

  • Возможно, вы сможете выполнять некоторые шаги отмены параллельно.

  • Возможно, потребуется применить бизнес-специфичные правила. Например, отмена резервирования рейсов может не иметь права клиента на полное возмещение.

Этот подход аналогичен шаблону распределенных транзакций Saga.

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

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

Проблемы и рекомендации

Учитывайте следующие моменты при принятии решения о том, как реализовать этот шаблон.

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

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

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

  • Инфраструктура, обрабатывающая шаги, должна соответствовать следующим критериям:

    • Она устойчива как в исходной операции, так и в компенсирующей транзакции.

    • Он не теряет сведения, необходимые для компенсации неудачного шага.

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

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

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

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

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

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

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

Когда следует использовать этот шаблон

Используйте этот шаблон, когда:

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

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

Этот шаблон может быть не подходит, если:

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

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

Проектирование рабочей нагрузки

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

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

- Критически важные потоки RE:02
- RE:09 Аварийное восстановление

Если этот шаблон вводит компромиссы внутри столпа, рассмотрите их против целей других столпов.

Пример

На следующей схеме показана практическая Azure реализация шаблона компенсирующих транзакций. Другие реализации также могут работать для ваших требований к рабочей нагрузке. Оркестратор, работающий в Azure Container Apps, координирует каждый шаг длительного рабочего процесса, отправляя команды через Azure Service Bus. По мере успешного выполнения каждого шага оркестратор записывает как состояние выполнения, так и соответствующее компенсирующее действие в Azure Cosmos DB, чтобы рабочий процесс можно было возобновить, сопоставить и провести аудит.

Диаграмма, показывающая Azure-воплощение шаблона компенсирующей транзакции.

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

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

В типичной последовательности оркестратор отправляет сообщения о шагах через Service Bus (шаги 1 и 2), получает успешные результаты и сохраняет метаданные форуардирования и компенсации в Azure Cosmos DB.

Вы можете активировать компенсацию двумя способами:

  • Если последующий шаг в той же рабочей нагрузке завершается сбоем, и необходимо отменить предыдущие успешные шаги. Эта компенсация может произойти немедленно, когда шаг возвращает ошибку бизнес-логики, например ошибку проверки правил, или после исчерпания технических повторных попыток, и сообщение перемещается в очередь 'мёртвых' писем.

  • Когда последующий клиент явно запрашивает отмену завершенной операции.

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

Если повторяющиеся повторные попытки по-прежнему завершаются ошибкой, Service Bus перемещает сообщение в очередь недоставленных писем и сохраняет сведения о сбоях. Оркестратор или выделенный обработчик недоставленных букв вызывает оповещение и выдает структурированную телеметрию, включая идентификаторы причин сбоя и корреляции, для Azure Monitor и Log Analytics, которые могут отображаться в Application Insights. Этот рабочий путь помогает командам диагностировать сбои, определять необходимость ручного вмешательства и поддерживать трассировку как в исходных, так и в компенсирующих потоках.

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

Используйте управляемые удостоверения и авторизацию на основе Microsoft Entra ID между компонентами, чтобы избежать общего секрета и принудительного доступа к минимальным привилегиям. При создании упрощенной эталонной схемы эти элементы управления удостоверениями и авторизацией обрабатываются как базовые проблемы реализации, а не явные шаги потока. Держите схему сосредоточенной на оркестрации, повторных попытках, компенсации и обработке сбоев.

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

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

  • Проектирование для самовосстановления: использование компенсирующих транзакций в рамках подхода самовосстановления для приложений.

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

  • Шаблон повторных попыток: используйте этот шаблон для обработки временных сбоев и минимизации необходимости компенсационных транзакций.

  • Шаблон распределенных транзакций Saga: используйте этот шаблон для управления согласованностью данных в микрослужбах в распределенных транзакциях. Сага использует компенсирующие транзакции для восстановления сбоев.

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