В этой статье объясняется, как повысить устойчивость приложений .NET с помощью библиотеки Polly.

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

Даже если вы пишете свои сервисы идеально, безупречный код и так далее, ошибка все равно придет. Почему? Что я сделал не так?

Ответом может быть «Ничего». Некоторые ошибки находятся за пределами нашей области и могут присутствовать только в течение ограниченного времени. Например, если у вас есть проблема с сетью или высокая загрузка ресурсов, API вернет 500 (или другие ошибки).

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

Что такое Полли

Polly - это библиотека устойчивости .NET и обработки переходных сбоев, которая позволяет разработчикам быстро и с поточно-безопасностью выражать политики, такие как Retry, Circuit Breaker, Timeout, Bulkhead Isolation и Fallback.

Polly доступен как пакет Nuget, и установка очень проста:

install-package Polly

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

Реактивная устойчивость

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

ПОВТОРИТЬ

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

Вы можете применить эту стратегию для:

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

В приведенном выше примере мы определили политику для выполнения службы и в случае повторной попытки выполнения исключения три раза с задержкой в ​​500, 1500 и 2000 миллисекунд.

Эта политика может быть бесполезной, когда:

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

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

Автоматический выключатель

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

Автоматический выключатель работает с таким состоянием:

  • Закрыто: приложение работает нормально и каждый запрос отправляется в службу. Состояние не меняется, даже если у вас много отказов, превышающих пороговую границу.
  • Открыто. Служба никогда не вызывается, и приложение сразу дает сбой. Это состояние имеет определенный период продолжительности перед переходом в следующее состояние или непосредственно в состояние закрытия.
  • Half-Open: ограниченное количество вызовов службы разрешено. Если какой-либо вызов был успешным, состояние переходит к Close, с другой стороны, если вы получаете одну ошибку, состояние переходит к Open.

Polly предлагает две реализации автоматического выключателя: базовый автоматический выключатель, который отключается при возникновении определенного количества последовательных отказов, и расширенный автоматический выключатель, который отключается, когда пороговое значение сбоев возникает в течение времени, в течение которого достаточно большой объем запросы как были сделаны.

Эта политика не может быть полезна в следующих случаях:

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

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

Запасные варианты

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

Проактивная устойчивость

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

Тайм-аут

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

Кеширование

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

BulkHaead Isolation

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

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

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

Обертки правил

В реальном случае часто необходимо использовать дополнительную политику в контексте действия. Polly позволяет объединить в цепочку больше политик. В этом примере мы определили политику, которая включает в себя Retry, Circuit Breaker и Timeout.

Политика использования с DI

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

Очевидно, что таким образом одно исключение в соединении вызовет ошибку, и, следовательно, пользователю будет возвращен ответ StatusCode 500.
В этом случае, если мы хотим использовать Polly, чтобы сделать запрос устойчивым, мы можем добавить Политика повторных попыток.

Опрос через HTTP

В современных веб-приложениях обычно используется уровень API для использования бизнес-логики и доступа к данным. Начиная с ASP.NET Core 2.1 регистрация класса HttpClient поддерживается через IHttpClientFactory, что позволяет:

  • Централизовать на Startup Class конфигурацию Http-клиента
  • Определите несколько клиентов и используйте правильный клиент в зависимости от контекста
  • Зарегистрируйте и управляйте жизненным циклом обработчиков, связанных с клиентом

Из метода ConfigureServices класса Startup мы можем настроить параметры по умолчанию для каждого экземпляра HttpClient, такие как базовый URL-адрес, заголовки запроса и назначить имя для экземпляра, используя метод расширения AddHttpClient. После установки пакета Nuget Microsoft.Extensions.Http.Polly можно зарегистрировать на клиенте все возможности отказоустойчивости, предлагаемые Polly.

Можно зарегистрировать несколько политик и HttpHandler, поток выполнения, скорее всего, описан в политике Wraps.

Пример. Обеспечьте отказоустойчивость своего .NET-клиента, созданного с помощью NSwag

В этом примере мы настраиваем консоль приложения для вызова веб-API, интегрируя Polly на клиенте, созданном с помощью NSwag.

Создайте клиента

Мы предполагаем, что мы уже внедрили API, и любые подробности о регистре swagger и генерации клиентов с помощью NSwag требуются в Документацию Microsoft.

Определите политику приложения

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

Для демонстрации мы реализовали следующие политики:

  • Подождите и повторите попытку
  • Автоматический выключатель
  • Повторить навсегда
  • Тайм-аут

В этом контексте можно легко добавить любую другую политику.

Зарегистрируйте HttpClient

В ConfigureService мы можем зарегистрировать одного именованного клиента для каждой политики.

API вызовов с политикой

Клиентский класс, созданный из NSwag, нуждается в конструкторе в экземпляре HttpClient, который может быть сгенерирован с помощью DI. Затем, используя названный HttpClient, мы можем вызывать все API, применяющие разные политики в отношении контекста.

Выводы

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

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

использованная литература