Обработка времени ожидания и настройка повторных попыток в Служебная шина Azure

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

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

Что означает тайм-аут

В зависимости от операции и среды узла время ожидания проявляется в виде TimeoutException, OperationCanceledException или ServiceBusException с ReasonServiceTimeout.

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

  • Клиентская сторона — приложение не может достичь службы вовремя (сетевой путь, DNS, прокси-сервер, брандмауэр), клиент перегружен (нехватка потоков, высокая ЦП) или настроенное время ожидания пробы слишком коротко для операции.
  • Сторона службы — временное состояние службы или более широкий инцидент. Когда проблема на стороне службы, сбой обычно затрагивает множество операций и виден на странице Работоспособность ресурса пространства имен в портале Azure.

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

Настройка параметров повтора

Клиентские библиотеки повторяют временные сбои, включая время ожидания, в соответствии с параметрами повторных попыток, настроенными на клиенте. В библиотеке .NET задайте serviceBusRetryOptions с помощью ServiceBusClientOptions.

var options = new ServiceBusClientOptions
{
    RetryOptions = new ServiceBusRetryOptions
    {
        Mode = ServiceBusRetryMode.Exponential,
        MaxRetries = 3,
        Delay = TimeSpan.FromSeconds(0.8),
        MaxDelay = TimeSpan.FromSeconds(60),
        TryTimeout = TimeSpan.FromSeconds(60)
    }
};

var client = new ServiceBusClient(fullyQualifiedNamespace, credential, options);
Опция Что он контролирует По умолчанию
Mode Является ли отсрочка Fixed или Exponential Exponential
MaxRetries Максимальное количество повторных попыток при временном сбое 3
Delay Базовая задержка между попытками 0,8 секунды
MaxDelay Верхняя граница задержки повторной попытки 60 секунд
TryTimeout Максимальная длительность одной попытки до истечения времени ожидания 60 секунд

Проверьте текущие значения по умолчанию для ссылки ServiceBusRetryOptions, так как они могут меняться между версиями библиотеки. Эквивалентные параметры повторных попыток существуют в клиентских библиотеках Java, JavaScript, Python и Go.

Настройка значений рабочей нагрузки

  • Увеличьте TryTimeout, если выполнение операций по объективным причинам занимает более 60 секунд, например при получении из низконагруженной очереди с большим значением maxWaitTime или при работе в сети с высокой задержкой. Более крупный тайм-аут снижает преждевременное время ожидания, но также продлевает время, прежде чем действительно недостижимая служба столкает ошибку.
  • Увеличьте MaxRetries или MaxDelay, чтобы система выдерживала более длительные переходные состояния ценой более медленного обнаружения отказов.
  • Имейте в виду длительность блокировки. Когда Reason имеет значение ServiceBusy (ограничение пропускной способности), клиент делает 10-секундную паузу перед повторной попыткой. Если длительность блокировки вашей сущности короче, чем резервная, во время ожидания могут быть потеряны сообщения или блокировки сеанса. См. Ограничение скорости.

Избегайте клиентских шаблонов, которые приводят к тайм-аутам

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

Не блокируйте асинхронные вызовы (синхронизация по async)

Вызов .Result, .Wait() или .GetAwaiter().GetResult() в асинхронных API служебная шина блокирует поток из пула потоков. При нагрузке это действие приводит к исчерпанию пула потоков: обратные вызовы, завершающие операции ввода-вывода, не могут выполняться, поэтому операции завершаются по тайм-ауту, даже если служба работает нормально. Симптомом являются тайм-ауты, которые усиливаются при росте параллелизма и исчезают при снижении нагрузки.

Вместо этого используйте async/await в сквозном режиме:

// Avoid
ServiceBusReceivedMessage message = receiver.ReceiveMessageAsync().GetAwaiter().GetResult();

// Prefer
ServiceBusReceivedMessage message = await receiver.ReceiveMessageAsync();

Повторное использование клиента в качестве одноэлементного

Каждый новый ServiceBusClient открывает новое подключение AMQP. Создание клиента для каждого сообщения или запроса приводит к исчерпанию сокетов и вызывает тайм-ауты подключения. Создайте один клиент в течение всего времени существования приложения и повторно используйте его. Дополнительные сведения см. в разделе Ошибки исчерпания сокетов.

Оптимизируйте предварительную выборку и уровень параллелизма

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

Проверка сетевого пути

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

  • Порты AMQP 5671 и 5672 должны быть открыты, либо следует использовать транспорт WebSocket через порт 443.
  • DNS выполняет разрешение пространства имён, включая конфигурацию частной конечной точки и частной DNS-зоны.
  • Прокси-сервер или брандмауэр не перехватывает подключение.

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

Обработка тайм-аутов в коде

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

try
{
    await sender.SendMessageAsync(message);
}
catch (ServiceBusException ex) when (ex.Reason == ServiceBusFailureReason.ServiceTimeout)
{
    // The client already retried. Log for correlation, then decide whether
    // to retry at the application level or surface the failure.
}

Определите, что это — клиент или служба

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

  1. Проверьте страницу работоспособности ресурсов пространства имен на портале Azure для затронутого периода времени.
  2. Проверьте, связаны ли тайм-ауты с высокой загрузкой процессора на стороне клиента или с высокой степенью параллелизма.
  3. Включите ведение журнала на стороне клиента, чтобы увидеть, срабатывают ли повторные попытки и какова исходная ошибка AMQP. См. ведение журнала и диагностику.
  4. Подтвердите сетевой путь и разрешение DNS от узла клиента.

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