Поделиться через


Устранение неполадок при использовании пакета SDK Async Java для Azure Cosmos DB версии 2 с помощью API для учетных записей NoSQL

Это важно

Это не последняя версия пакета SDK для Java для Azure Cosmos DB! Необходимо обновить проект до пакета SDK Java для Azure Cosmos DB версии 4 , а затем прочитать руководство по устранению неполадок пакета SDK Java для Azure Cosmos DB версии 4. Следуйте инструкциям, приведенным в руководстве по миграции на Azure Cosmos DB Java SDK v4 и в руководстве по Reactor vs RxJava, для обновления.

В этой статье описывается устранение неполадок только для пакета SDK Async Java для Azure Cosmos DB версии 2. Дополнительные сведения см. в заметках о выпуске пакета SDK Async Java для Azure Cosmos DB версии 2, репозитории Maven и советах по производительности .

Это важно

31 августа 2024 г. пакет SDK Async Java для Azure Cosmos DB версии 2.x будет прекращен; пакет SDK и все приложения, использующие пакет SDK, будут продолжать функционировать; Azure Cosmos DB просто перестанет предоставлять дальнейшее обслуживание и поддержку этого пакета SDK. Для перехода на Azure Cosmos DB с пакетом SDK для Java версии 4 рекомендуется следовать инструкциям, приведенным выше.

В этой статье рассматриваются распространенные проблемы, обходные пути, шаги диагностики и средства при использовании пакета SDK для Java Async с учетной записью Azure Cosmos DB для NoSQL. Пакет SDK для Java Async предоставляет логическое представление на стороне клиента для доступа к Azure Cosmos DB для NoSQL. В этой статье описываются средства и подходы, которые помогут вам, если вы столкнетесь с проблемами.

Начните со следующего списка:

Распространенные проблемы и обходные решения для них

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

Общие рекомендации

  • Убедитесь, что приложение запущено в том же регионе, что и учетная запись Azure Cosmos DB.
  • Проверьте использование ЦП на узле, где работает приложение. Если загрузка ЦП составляет 90 процентов или больше, запустите приложение на узле с более высокой конфигурацией. Кроме того, вы можете распределить нагрузку на другие компьютеры.

Регулирование подключений

Регулирование подключений может произойти из-за ограничения подключения на хост-компьютере или из-за истощения портов SNAT (PAT).

Ограничение подключения на хост-компьютере

Некоторые системы Linux, такие как Red Hat, имеют верхний предел общего количества открытых файлов. Сокеты в Linux реализованы в виде файлов, поэтому это число также ограничивает общее количество подключений. Выполните следующую команду.

ulimit -a

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

Исчерпание портов SNAT (PAT) Azure

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

Порты SNAT Azure используются только в том случае, если у виртуальной машины есть частный IP-адрес, а процесс из виртуальной машины пытается подключиться к общедоступному IP-адресу. Существует два обходных решения, чтобы избежать ограничения SNAT Azure:

  • Добавьте конечную точку службы Azure Cosmos DB к подсети виртуальной сети для службы "Виртуальные машины Azure". Дополнительные сведения см. в статье Конечные точки служб для виртуальной сети Azure.

    При включении конечной точки службы запросы больше не отправляются с общедоступного IP-адреса в Azure Cosmos DB. Вместо этого отправляются идентификаторы виртуальной сети и подсети. Это изменение может привести к сбою брандмауэра, если разрешены только общедоступные IP-адреса. Если вы используете брандмауэр, при включении конечной точки службы добавьте подсеть в брандмауэр с помощью ACL виртуальной сети.

  • Назначьте общедоступный IP-адрес виртуальной машине Azure.

Не удается добраться до службы — брандмауэр

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

GoneException{error=null, resourceAddress='https://cdb-ms-prod-westus-fd4.documents.azure.com:14940/apps/e41242a5-2d71-5acb-2e00-5e5f744b12de/services/d8aa21a5-340b-21d4-b1a2-4a5333e7ed8a/partitions/ed028254-b613-4c2a-bf3c-14bd5eb64500/replicas/131298754052060051p//', statusCode=410, message=Message: The requested resource is no longer available at the server., getCauseInfo=[class: class io.netty.channel.ConnectTimeoutException, message: connection timed out: cdb-ms-prod-westus-fd4.documents.azure.com/101.13.12.5:14940]

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

Прокси-сервер HTTP

При использовании прокси-сервера HTTP убедитесь, что он может поддерживать число подключений, указанное в свойстве ConnectionPolicy пакета SDK. В противном случае возникнут проблемы с подключением.

Недопустимый шаблон кодирования: блокировка потока ввода-вывода Netty

Пакет SDK использует библиотеку ввода-вывода Netty для взаимодействия с Azure Cosmos DB. Пакет SDK содержит Асинхронные API и использует неблокирующие API ввода-вывода Netty. Работа ввода-вывода пакета SDK выполняется в потоках IO Netty. Число потоков IO Netty настроено так же, как и количество ядер ЦП компьютера приложения.

Потоки ввода-вывода Netty предназначены только для неблокирующих операций ввода-вывода Netty. Пакет SDK возвращает результат вызова API для одного из потоков ввода-вывода Netty в код приложения. Если приложение выполняет долгосрочную операцию после получения результатов в потоке Netty, пакет SDK может не иметь достаточно потоков ввода-вывода для выполнения внутренних операций ввода-вывода. Такой код приложения может привести к низкой пропускной способности, высокой задержке и io.netty.handler.timeout.ReadTimeoutException сбоям. Обходной путь заключается в переключении потока, когда вы знаете, что операция занимает время.

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

Async Java SDK версии 2 (Maven com.microsoft.azure::azure-cosmosdb)

@Test
public void badCodeWithReadTimeoutException() throws Exception {
    int requestTimeoutInSeconds = 10;

    ConnectionPolicy policy = new ConnectionPolicy();
    policy.setRequestTimeoutInMillis(requestTimeoutInSeconds * 1000);

    AsyncDocumentClient testClient = new AsyncDocumentClient.Builder()
            .withServiceEndpoint(TestConfigurations.HOST)
            .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY)
            .withConnectionPolicy(policy)
            .build();

    int numberOfCpuCores = Runtime.getRuntime().availableProcessors();
    int numberOfConcurrentWork = numberOfCpuCores + 1;
    CountDownLatch latch = new CountDownLatch(numberOfConcurrentWork);
    AtomicInteger failureCount = new AtomicInteger();

    for (int i = 0; i < numberOfConcurrentWork; i++) {
        Document docDefinition = getDocumentDefinition();
        Observable<ResourceResponse<Document>> createObservable = testClient
                .createDocument(getCollectionLink(), docDefinition, null, false);
        createObservable.subscribe(r -> {
                    try {
                        // Time-consuming work is, for example,
                        // writing to a file, computationally heavy work, or just sleep.
                        // Basically, it's anything that takes more than a few milliseconds.
                        // Doing such operations on the IO Netty thread
                        // without a proper scheduler will cause problems.
                        // The subscriber will get a ReadTimeoutException failure.
                        TimeUnit.SECONDS.sleep(2 * requestTimeoutInSeconds);
                    } catch (Exception e) {
                    }
                },

                exception -> {
                    //It will be io.netty.handler.timeout.ReadTimeoutException.
                    exception.printStackTrace();
                    failureCount.incrementAndGet();
                    latch.countDown();
                },
                () -> {
                    latch.countDown();
                });
    }

    latch.await();
    assertThat(failureCount.get()).isGreaterThan(0);
}

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

Async Java SDK версии 2 (Maven com.microsoft.azure::azure-cosmosdb)

// Have a singleton instance of an executor and a scheduler.
ExecutorService ex  = Executors.newFixedThreadPool(30);
Scheduler customScheduler = rx.schedulers.Schedulers.from(ex);

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

Async Java SDK версии 2 (Maven com.microsoft.azure::azure-cosmosdb)

Observable<ResourceResponse<Document>> createObservable = client
        .createDocument(getCollectionLink(), docDefinition, null, false);

createObservable
        .observeOn(customScheduler) // Switches the thread.
        .subscribe(
            // ...
        );

С помощью observeOn(customScheduler)вы освобождаете поток ввода-вывода Netty и переключаеесь на собственный пользовательский поток, предоставляемый настраиваемым планировщиком. Это изменение решает проблему. Вы больше не получите сбой io.netty.handler.timeout.ReadTimeoutException .

Проблема истощения пула подключений

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

Высокая частота запросов

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

Сбой при подключении к эмулятору Azure Cosmos DB

Сертификат HTTPS эмулятора Azure Cosmos DB самозаверяется. Чтобы пакет SDK работал с эмулятором, импортируйте сертификат эмулятора в Java TrustStore. Дополнительные сведения см. в статье "Экспорт сертификатов эмулятора Azure Cosmos DB".

Проблемы с конфликтом зависимостей

Exception in thread "main" java.lang.NoSuchMethodError: rx.Observable.toSingle()Lrx/Single;

Приведенное выше исключение предполагает, что у вас есть зависимость от более старой версии RxJava lib (например, 1.2.2). Наш пакет SDK использует RxJava 1.3.8, который имеет API-интерфейсы, недоступные в более ранней версии RxJava.

Решение для таких проблем — определить, какие другие зависимости приводят к RxJava-1.2.2, исключить транзитивную зависимость от RxJava-1.2.2 и позволить SDK CosmosDB использовать более новую версию.

Чтобы определить, какая библиотека содержит RxJava-1.2.2.2, выполните следующую команду рядом с файлом pom.xml проекта:

mvn dependency:tree

Дополнительные сведения см. в руководстве по дереве зависимостей maven.

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

<dependency>
  <groupId>${groupid-of-lib-which-brings-in-rxjava1.2.2}</groupId>
  <artifactId>${artifactId-of-lib-which-brings-in-rxjava1.2.2}</artifactId>
  <version>${version-of-lib-which-brings-in-rxjava1.2.2}</version>
  <exclusions>
    <exclusion>
      <groupId>io.reactivex</groupId>
      <artifactId>rxjava</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Дополнительные сведения см. в руководстве по исключаемой транзитивной зависимости.

Включение ведения журнала пакета SDK для клиента

Пакет SDK для Java Async использует SLF4j в качестве фасада для логгирования, который поддерживает интеграцию с популярными системами логгирования, такими как log4j и logback.

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

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>${slf4j.version}</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>${log4j.version}</version>
</dependency>

Кроме того, добавьте конфигурацию log4j.

# this is a sample log4j configuration

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=INFO, A1

log4j.category.com.microsoft.azure.cosmosdb=DEBUG
#log4j.category.io.netty=INFO
#log4j.category.io.reactivex=INFO
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %5X{pid} [%t] %-5p %c - %m%n

Дополнительные сведения см. в руководстве по ведению журнала sfl4j.

Статистика сети ОС

Выполните команду netstat, чтобы получить представление о количестве подключений в таких состояниях, как ESTABLISHED и CLOSE_WAIT.

В Linux можно выполнить следующую команду.

netstat -nap

Отфильтруйте результат только для подключений к конечной точке Azure Cosmos DB.

Количество подключений к конечной точке Azure Cosmos DB в ESTABLISHED состоянии не может превышать размер настроенного пула подключений.

Многие подключения к конечной точке Azure Cosmos DB могут находиться в CLOSE_WAIT состоянии. Может быть более 1000. Число, настолько высокое, указывает на то, что соединения устанавливаются и разрываются быстро. Эта ситуация потенциально вызывает проблемы. Дополнительные сведения см. в разделе "Распространенные проблемы и обходные пути ".