Устранение неполадок в шине обслуживания Azure Service Bus
В этой статье рассматриваются методы исследования сбоев, параллелизм, распространенные ошибки для типов учетных данных в клиентской библиотеке Java служебной шины Azure и действия по устранению этих ошибок.
Включение и настройка ведения журнала
Пакет SDK Azure для Java предлагает согласованную историю ведения журнала, чтобы помочь в устранении ошибок приложений и ускорить их разрешение. Журналы фиксируют поток приложения до достижения конечного состояния, чтобы помочь найти корневую проблему. Для получения рекомендаций по ведению журнала см. раздел Настройка ведения журнала в пакете SDK Azure для Java и раздел Обзор устранения неполадок.
Помимо включения ведения журнала, установка уровня журнала на VERBOSE
или DEBUG
предоставляет аналитические сведения о состоянии библиотеки. В следующих разделах показаны примеры конфигураций log4j2 и logback, чтобы уменьшить чрезмерное количество сообщений при включении подробного ведения журнала.
Настройка Log4J 2
Чтобы настроить Log4J 2, выполните следующие действия.
- Добавьте зависимости в pom.xml, используя их из примера журнала pom.xml, в разделе "Зависимости, необходимые для Log4j2".
- Добавьте log4j2.xml в папку src/main/resources.
Настройка обратного входа
Чтобы настроить Logback, выполните следующие действия.
- Добавьте зависимости в pom.xml, используя их из примера логирования pom.xml, в разделе "Зависимости, необходимые для Logback".
- Добавьте logback.xml в папку src/main/resources.
Включение ведения журнала транспорта AMQP
Если включение логирования клиентов недостаточно для диагностики проблем, вы можете включить логирование в файл в основной библиотеке AMQP, Qpid Proton-J. Proton-J Qpid использует java.util.logging
. Вы можете включить ведение журнала, создав файл конфигурации с содержимым, показанным в следующем разделе. Или задайте proton.trace.level=ALL
и какие параметры конфигурации требуется для реализации java.util.logging.Handler
. Сведения о классах реализации и их параметрах см. в пакета java.util.logging в документации по пакету SDK для Java 8.
Чтобы отслеживать кадры транспорта AMQP, задайте переменную среды PN_TRACE_FRM=1
.
Пример файла logging.properties
Следующий файл конфигурации записывает выходные данные уровня TRACE из Proton-J в файл proton-trace.log:
handlers=java.util.logging.FileHandler
.level=OFF
proton.trace.level=ALL
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.pattern=proton-trace.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tF %1$tr] %3$s %4$s: %5$s %n
Сократить журналирование
Одним из способов уменьшения логирования является изменение подробности. Другой способ — добавить фильтры, которые исключают журналы из пакетов с именами регистраторов, таких как com.azure.messaging.servicebus
или com.azure.core.amqp
. Примеры см. в xml-файлах в разделах Configure Log4J 2 и Configure logback.
При сообщении об ошибке интересны сообщения журнала из классов в следующих пакетах:
com.azure.core.amqp.implementation
com.azure.core.amqp.implementation.handler
- Исключением является то, что можно игнорировать сообщение
onDelivery
вReceiveLinkHandler
.
- Исключением является то, что можно игнорировать сообщение
com.azure.messaging.servicebus.implementation
Конкурентность в ServiceBusProcessorClient
ServiceBusProcessorClient
позволяет приложению настроить количество вызовов обработчика сообщений одновременно. Эта конфигурация позволяет параллельно обрабатывать несколько сообщений. Для ServiceBusProcessorClient
потребления сообщений из сущности, не являющейся сеансовой, приложение может настроить требуемую конкурентность с помощью API maxConcurrentCalls
. Для сущности с поддержкой сеанса требуемый уровень параллелизма — maxConcurrentSessions
умножить на maxConcurrentCalls
.
Если приложение наблюдает меньше одновременных вызовов обработчика сообщений, чем настроенный параллелизм, это может быть связано с тем, что пул потоков не имеет правильного размера.
ServiceBusProcessorClient
использует потоки управляющей программы из глобального пула потоков "Реактор" ограниченной пула потоков для вызова обработчика сообщений. Максимальное количество параллельных потоков в этом пуле ограничено ограничением. По умолчанию это ограничение составляет десять раз, чем количество доступных ядер ЦП. Для того чтобы ServiceBusProcessorClient
эффективно поддерживал желаемый параллелизм приложения (maxConcurrentCalls
или maxConcurrentSessions
раз maxConcurrentCalls
), лимит пула boundedElastic
должен превышать желаемый параллелизм. Можно переопределить ограничение по умолчанию, задав системное свойство reactor.schedulers.defaultBoundedElasticSize
.
Следует настроить пул потоков и выделение ЦП в зависимости от конкретного случая. Однако при переопределении ограничения пула как начальное значение ограничьте количество потоков до примерно 20–30 на одно ядро ЦП. Рекомендуется ограничить требуемую степень параллелизма для каждого экземпляра ServiceBusProcessorClient
приблизительно до 20-30. Профилируйте и измеряйте конкретный вариант использования и настраивайте аспекты параллелизма соответствующим образом. Для сценариев с высокой нагрузкой следует рассмотреть возможность запуска нескольких экземпляров ServiceBusProcessorClient
, каждый из которых создается из нового экземпляра ServiceBusClientBuilder
. Кроме того, рассмотрите возможность запуска каждой ServiceBusProcessorClient
в выделенном узле ( например, контейнере или виртуальной машине), чтобы простой в одном узле не влиял на общую обработку сообщений.
Имейте в виду, что установка высокого значения для ограничения пула на узле с несколькими ядрами ЦП будет иметь негативные последствия. Некоторые признаки низких ресурсов процессора или пула с чрезмерным количеством потоков на небольшом количестве процессоров: частые тайм-ауты, потеря блокировки, взаимоблокировка или снижение пропускной способности. Если приложение Java запущено в контейнере, рекомендуется использовать два или более ядер виртуального ЦП. При запуске Java- приложений в контейнерных средах не рекомендуется выбирать меньше одного виртуального ядра ЦП. Подробные рекомендации по управлению ресурсами см. в контейнеризации Java-приложений.
Узкие места для общего доступа к подключению
Все клиенты, созданные из общего экземпляра ServiceBusClientBuilder
, используют то же подключение к пространству имен служебной шины.
Использование разделенного подключения позволяет выполнять мультиплексирование операций между клиентами в одном подключении, но такое подключение также может стать перегруженным, если клиентов много или если они вместе создают высокую нагрузку. Каждое подключение имеет поток ввода-вывода, связанный с ним. При совместном подключении клиенты помещают свою работу в рабочую очередь общего потока ввода-вывода, а ход выполнения каждого клиента зависит от своевременного завершения работы в очереди. Поток ввода-вывода обрабатывает поставленные в очередь задачи поочередно. То есть, если очередь задач ввода-вывода общего подключения оказывается с большим количеством необработанных задач, то симптомы похожи на низкой загрузке ЦП. Это условие описано в предыдущем разделе о параллелизме, например, при остановке клиентов, истечении времени ожидания, потере блокировки или замедлении пути восстановления.
Пакет Service Bus SDK использует шаблон именования reactor-executor-*
для потока ввода-вывода подключения. Когда приложение сталкивается с узкими местами общего подключения, это может отразиться на нагрузке на ЦП потока ввода-вывода. Кроме того, в дампе кучи или в динамической памяти объект ReactorDispatcher$workQueue
является рабочей очередью потока ввода-вывода. Длинная очередь работ в снимке состояния памяти в период узкого места может указывать на то, что общий поток ввода-вывода перегружен ожидающими работами.
Таким образом, если нагрузка приложения на конечную точку Service Bus достаточно высока с точки зрения общего количества отправленных и полученных сообщений или размера полезной нагрузки, следует использовать отдельный экземпляр построителя для каждого клиента, которого вы создаете. Например, для каждой сущности — очереди или темы — можно создать новый ServiceBusClientBuilder
и построить клиент на его основе. В случае чрезвычайно высокой нагрузки на определенную сущность может потребоваться создать несколько экземпляров клиента для этой сущности или запустить клиенты на нескольких узлах, например контейнеры или виртуальные машины для балансировки нагрузки.
Клиенты приостанавливаются при работе с пользовательской конечной точкой шлюза приложений
Адрес пользовательской конечной точки ссылается на адрес конечной точки HTTPS, предоставленный приложением, разрешаемый служебной шине или настроенный для маршрутизации трафика в служебную шину. Шлюз приложений Azure упрощает создание интерфейса HTTPS, который перенаправит трафик в служебную шину. Пакет SDK служебной шины можно настроить для приложения, чтобы использовать внешний IP-адрес шлюза приложений в качестве настраиваемой конечной точки для подключения к служебной шине.
Шлюз приложений предлагает несколько политик безопасности, поддерживающих разные версии протокола TLS. Существуют предопределенные политики, применяющие TLSv1.2 в качестве минимальной версии, существуют также старые политики с TLSv1.0 как минимальная версия. Интерфейс HTTPS будет применять политику TLS.
Сейчас Service Bus SDK не распознает определённые TCP-соединения на удалённой стороне у фронтэнда шлюза приложений, который использует TLSv1.0 в качестве минимальной версии. Например, если интерфейс отправляет пакеты TCP FIN, ACK, чтобы закрыть подключение при обновлении его свойств, SDK не может обнаружить это, поэтому не сможет восстановить подключение, и клиенты больше не смогут отправлять или получать сообщения. Такая остановка происходит только при использовании TLSv1.0 в качестве минимальной версии. Чтобы устранить эту проблему, используйте политику безопасности с TLSv1.2 или более поздней версией для внешнего интерфейса шлюза приложений.
Поддержка TLSv1.0 и 1.1 во всех службах Azure уже объявлена к 31 октября 2024 г., поэтому настоятельно рекомендуется перейти на TLSv1.2.
Сообщение или блокировка сеанса потеряна
Очередь или подписка в Service Bus имеет установленную на уровне ресурса длительность блокировки. Когда клиент-получатель извлекает сообщение из ресурса, брокер служебной шины применяет начальную блокировку к сообщению. Начальная блокировка длится в течение времени блокировки, установленного на уровне ресурса. Если блокировка сообщения не продлевается до истечения срока действия, брокер служебной шины освобождает сообщение, чтобы сделать его доступным для других получателей. Если приложение пытается завершить или отказаться от сообщения после истечения срока действия блокировки, вызов API завершается ошибкой com.azure.messaging.servicebus.ServiceBusException: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue
.
Клиент служебной шины поддерживает выполнение задачи обновления фоновой блокировки, которая постоянно обновляет блокировку сообщений каждый раз до истечения срока действия. По умолчанию задача продления блокировки выполняется в течение 5 минут. Длительность продления блокировки можно настроить с помощью ServiceBusReceiverClientBuilder.maxAutoLockRenewDuration(Duration)
. Если передать значение Duration.ZERO
, задача продления блокировки отключена.
В следующих списках описаны некоторые шаблоны использования или среды хостов, которые могут привести к ошибке потери блокировки.
Задача продления блокировки отключена, а время обработки сообщений приложения превышает длительность блокировки на уровне ресурса.
Время обработки сообщений приложения превышает настроенную длительность задачи продления блокировки. Обратите внимание, что если длительность продления блокировки не задана явно, значение по умолчанию — 5 минут.
Приложение включило функцию предварительной выборки, установив значение предварительной выборки положительным целым числом с помощью
ServiceBusReceiverClientBuilder.prefetchCount(prefetch)
. Если включена функция предварительной выборки, клиент получит количество сообщений, равное значению предварительной выборки из сущности служебной шины — очереди или топика — и сохранит их в буфере предварительной выборки в памяти. Сообщения остаются в буфере предварительной выборки, пока они не будут получены в приложение. Клиент не продлевает блокировку сообщений, пока они находятся в буфере предварительной выборки. Если обработка приложения занимает так долго, что срок действия блокировки сообщений истекает во время пребывания в буфере предварительной выборки, приложение может получить сообщения с истекшим сроком действия блокировки. Дополнительные сведения см. в разделе Почему предварительная выборка не является параметром по умолчанию?Хост-среда имеет случайные проблемы с сетью, например, транзитный сбой сети или отключение, которые препятствуют обновить задачу продления блокировки вовремя.
Хостовая среда не имеет достаточного количества центральных процессоров или периодически испытывает нехватку циклов центрального процессора, что задерживает выполнение задачи продления блокировки вовремя.
Время системы хоста некорректное — например, часы смещены — это задерживает задачу продления блокировки и не давая ей выполняться вовремя.
Поток ввода-вывода подключения перегружен, что влияет на его способность своевременно выполнять сетевые вызовы для обновления блокировок. Следующие два сценария могут вызвать эту проблему:
- Приложение выполняет слишком много клиентов-получателей, использующих одно и то же подключение. Дополнительные сведения см. в разделе Узкое место при совместном использовании подключения.
- Приложение настроило
ServiceBusReceiverClient.receiveMessages
илиServiceBusProcessorClient
так, чтобы иметь большие значенияmaxMessages
илиmaxConcurrentCalls
. Дополнительные сведения см. в разделе Параллелизм в ServiceBusProcessorClient.
Число задач продления блокировки в клиенте равно значениям параметра maxMessages
или maxConcurrentCalls
, заданным для ServiceBusProcessorClient
или ServiceBusReceiverClient.receiveMessages
. Большое количество задач продления блокировки, выполняющих несколько сетевых вызовов, также может оказать негативное влияние на регулирование пространства имен служебной шины.
Если у узла недостаточно ресурсов, блокировка всё равно может быть потеряна, даже если выполняется только несколько заданий по продлению блокировки. Если приложение Java запущено в контейнере, рекомендуется использовать два или более ядер виртуального ЦП. При запуске приложений Java в контейнерных средах не рекомендуется выбирать не более 1 виртуальных ЦП. Подробные рекомендации по обеспечению ресурсов см. в контейнеризации приложений Java.
Те же замечания о блокировках также относятся к очереди Service Bus или подписке на тему с включенной поддержкой сеансов. Когда клиент-получатель подключается к сеансу в ресурсе, брокер применяет начальную блокировку к сеансу. Чтобы сохранить блокировку сеанса, задача продления блокировки в клиенте должна продолжать продление блокировки сеанса до истечения срока его действия. Для ресурса с включенной поддержкой сеансов основные разделы иногда перемещаются для обеспечения балансировки нагрузки между узлами служебной шины — например, при добавлении новых узлов для распределения нагрузки. В этом случае блокировки сеанса могут быть потеряны. Если приложение пытается завершить или отказаться от сообщения после потери блокировки сеанса, вызов API завершается ошибкой com.azure.messaging.servicebus.ServiceBusException: The session lock was lost. Request a new session receiver
.
Обновление до версии 7.15.x или последняя версия
При возникновении каких-либо проблем необходимо сначала попытаться решить их, обновив его до последней версии пакета SDK служебной шины. Версия 7.15.x — это основной редизайн, разрешающий долгосрочные проблемы производительности и надежности.
Версия 7.15.x и более поздних версий уменьшает прыжки потоков, удаляет блокировки, оптимизирует код в горячих путях и сокращает выделение памяти. Эти изменения приводят к более чем 45-50 раз большей пропускной способности в ServiceBusProcessorClient
.
Версия 7.15.x и более поздние версии также поставляется с различными улучшениями надежности. В нем рассматриваются несколько условий гонки (например, предварительная выборка и расчеты кредитов) и улучшенная обработка ошибок. Эти изменения приводят к повышению надежности в присутствии временных проблем в различных типах клиентов.
Использование последних клиентов
Новая базовая платформа с этими улучшениями — в версии 7.15.x и более поздних версиях — называется V2-Stack. Данный релиз включает в себя как предыдущее поколение базового стека - стека, который использует версия 7.14.x, - так и новый V2-Stack.
По умолчанию некоторые типы клиентов используют V2-Stack, а для других требуется включение опции V2-Stack. Вы можете включать или отключать определенный стек (версии 2 или предыдущего поколения) для типа клиента, предоставляя значения com.azure.core.util.Configuration
при сборке клиента.
Например, для получения сеанса на основе V2 Stack с ServiceBusSessionReceiverClient
требуется согласие, как показано в следующем примере:
ServiceBusSessionReceiverClient sessionReceiver = new ServiceBusClientBuilder()
.connectionString(Config.CONNECTION_STRING)
.configuration(new com.azure.core.util.ConfigurationBuilder()
.putProperty("com.azure.messaging.servicebus.session.syncReceive.v2", "true") // 'false' by default, opt-in for V2-Stack.
.build())
.sessionReceiver()
.queueName(Config.QUEUE_NAME)
.buildClient();
В следующей таблице перечислены типы клиентов и соответствующие имена конфигураций, а также указывает, включен ли клиент по умолчанию для использования V2-Stack в последней версии 7.17.0. Для клиентов, которые не включены в V2-Stack по умолчанию, можно использовать приведенный выше пример для включения.
Тип клиента | Имя конфигурации | Является ли V2-Stack значением по умолчанию? |
---|---|---|
Клиент отправителя и управления | com.azure.messaging.servicebus.sendAndManageRules.v2 |
да |
Клиент несессионного процессора и приемника реактора | com.azure.messaging.servicebus.nonSession.asyncReceive.v2 |
да |
Клиент приемника обработчика сеансов | com.azure.messaging.servicebus.session.processor.asyncReceive.v2 |
да |
Клиент сеансового получателя реактора | com.azure.messaging.servicebus.session.reactor.asyncReceive.v2 |
да |
Клиент синхронного приемника без привязки к сессии | com.azure.messaging.servicebus.nonSession.syncReceive.v2 |
Нет |
Клиент синхронного приемника сеанса | com.azure.messaging.servicebus.session.syncReceive.v2 |
Нет |
В качестве альтернативы использованию com.azure.core.util.Configuration
вы можете выполнить включение или отключение, установив те же имена конфигураций с помощью переменных среды или системных свойств.
Дальнейшие действия
Если рекомендации по устранению неполадок в этой статье не помогают устранить проблемы при использовании клиентских библиотек SDK Azure для Java, рекомендуется создать запрос в репозитории GitHub Azure SDK для Java.