Dela via


Felsöka problem när du använder Azure Cosmos DB Async Java SDK v2 med API för NoSQL-konton

GÄLLER FÖR: NoSQL

Viktigt!

Det här är inte den senaste Java SDK:t för Azure Cosmos DB! Du bör uppgradera projektet till Azure Cosmos DB Java SDK v4 och sedan läsa felsökningsguiden för Azure Cosmos DB Java SDK v4. Följ anvisningarna i guiden Migrera till Azure Cosmos DB Java SDK v4 och Guiden Reactor vs RxJava för uppgradering.

Den här artikeln beskriver endast felsökning för Azure Cosmos DB Async Java SDK v2. Mer information finns i Viktig information om Azure Cosmos DB Async Java SDK v2, Maven-lagringsplats och prestandatips.

Viktigt!

Den 31 augusti 2024 dras Azure Cosmos DB Async Java SDK v2.x tillbaka. SDK och alla program som använder SDK fortsätter att fungera. Azure Cosmos DB upphör helt enkelt att tillhandahålla ytterligare underhåll och support för denna SDK. Vi rekommenderar att du följer anvisningarna ovan för att migrera till Azure Cosmos DB Java SDK v4.

Den här artikeln beskriver vanliga problem, lösningar, diagnostiksteg och verktyg när du använder Java Async SDK med Azure Cosmos DB för NoSQL-konton. Java Async SDK tillhandahåller logisk representation på klientsidan för åtkomst till Azure Cosmos DB för NoSQL. I den här artikeln beskrivs verktyg och metoder för att hjälpa dig om du stöter på problem.

Börja med den här listan:

Vanliga fel och lösningar

Nätverksproblem, netty-timeoutfel, lågt dataflöde, hög svarstid

Allmänna förslag

  • Kontrollera att appen körs i samma region som ditt Azure Cosmos DB-konto.
  • Kontrollera CPU-användningen på värden där appen körs. Om CPU-användningen är 90 procent eller mer kör du appen på en värd med en högre konfiguration. Eller så kan du distribuera belastningen på fler datorer.

Anslutningsbegränsning

Anslutningsbegränsning kan inträffa på grund av antingen en anslutningsgräns på en värddator eller på grund av överbelastning av Azure SNAT-portar (PAT).

Anslutningsgräns på en värddator

Vissa Linux-system, till exempel Red Hat, har en övre gräns för det totala antalet öppna filer. Sockets i Linux implementeras som filer, så det här antalet begränsar även det totala antalet anslutningar. Kör följande kommando.

ulimit -a

Antalet maximalt tillåtna öppna filer, som identifieras som "nofile", måste vara minst dubbelt så stora som din anslutningspool. Mer information finns i Prestandatips.

Azure SNAT-portöverbelastning (PAT)

Om din app distribueras på virtuella Azure-datorer utan en offentlig IP-adress upprättar Azure SNAT-portar som standard anslutningar till valfri slutpunkt utanför den virtuella datorn. Antalet anslutningar som tillåts från den virtuella datorn till Azure Cosmos DB-slutpunkten begränsas av Azure SNAT-konfigurationen.

Azure SNAT-portar används endast när den virtuella datorn har en privat IP-adress och en process från den virtuella datorn försöker ansluta till en offentlig IP-adress. Det finns två lösningar för att undvika Azure SNAT-begränsning:

  • Lägg till azure Cosmos DB-tjänstslutpunkten i undernätet för ditt virtuella Azure Virtual Machines-nätverk. Mer information finns i Tjänstslutpunkter för Azure Virtual Network.

    När tjänstslutpunkten är aktiverad skickas inte längre begäranden från en offentlig IP-adress till Azure Cosmos DB. I stället skickas det virtuella nätverket och undernätets identitet. Den här ändringen kan leda till att brandväggen tas bort om endast offentliga IP-adresser tillåts. Om du använder en brandvägg lägger du till ett undernät i brandväggen med hjälp av ACL:er för virtuella nätverk när du aktiverar tjänstslutpunkten.

  • Tilldela en offentlig IP-adress till din virtuella Azure-dator.

Det går inte att nå tjänsten – brandväggen

ConnectTimeoutException anger att SDK:et inte kan nå tjänsten. Du kan få ett fel som liknar följande när du använder direktläget:

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]

Om du har en brandvägg som körs på din appdator öppnar du portintervallet 10 000 till 20 000 som används av direktläget. Följ även anslutningsgränsen på en värddator.

HTTP-proxy

Om du använder en HTTP-proxy kontrollerar du att den har stöd för antalet anslutningar som konfigurerats i SDK ConnectionPolicy. Annars kan du stöta på anslutningsproblem.

Ogiltigt kodningsmönster: Blockera Nätig I/O-tråd

SDK använder Netty IO-biblioteket för att kommunicera med Azure Cosmos DB. SDK:t har Async-API:er och använder icke-blockerande I/O-API:er för Netty. SDK:s I/O-arbete utförs på IO Netty-trådar. Antalet IO Netty-trådar har konfigurerats för att vara samma som antalet CPU-kärnor på appdatorn.

Netty I/O-trådarna är avsedda att endast användas för icke-blockerande Netty I/O-arbete. SDK:n returnerar API-anropsresultatet på en av Netty I/O-trådarna till appens kod. Om appen utför en långvarig åtgärd när den har fått resultat på Netty-tråden kanske SDK:t inte har tillräckligt med I/O-trådar för att utföra sitt interna I/O-arbete. Sådan appkodning kan resultera i lågt dataflöde, hög svarstid och io.netty.handler.timeout.ReadTimeoutException fel. Lösningen är att växla tråden när du vet att åtgärden tar tid.

Ta till exempel en titt på följande kodfragment. Du kan utföra långvarigt arbete som tar mer än några millisekunder på Netty-tråden. I så fall kan du så småningom hamna i ett tillstånd där det inte finns någon Netty IO-tråd för att bearbeta I/O-arbete. Därför får du ett ReadTimeoutException-fel.

Async Java SDK V2 (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);
}

Lösningen är att ändra den tråd som du utför arbete som tar tid. Definiera en singleton-instans av schemaläggaren för din app.

Async Java SDK V2 (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);

Du kan behöva utföra arbete som tar tid, till exempel beräkningsmässigt tungt arbete eller blockering av I/O. I det här fallet växlar du tråden till en arbetare som tillhandahålls av din customScheduler med hjälp av API:et .observeOn(customScheduler) .

Async Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)

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

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

Med hjälp observeOn(customScheduler)av släpper du Netty IO-tråden och växlar till din egen anpassade tråd som tillhandahålls av den anpassade schemaläggaren. Den här ändringen löser problemet. Du får inget io.netty.handler.timeout.ReadTimeoutException fel längre.

Problem med uttömd anslutningspool

PoolExhaustedException är ett fel på klientsidan. Det här felet indikerar att din apparbetsbelastning är högre än vad SDK-anslutningspoolen kan hantera. Öka storleken på anslutningspoolen eller distribuera belastningen på flera appar.

Begärandefrekvensen är för hög

Det här felet är ett fel på serversidan. Det anger att du har förbrukat ditt etablerade dataflöde. Försök igen senare. Om du ofta får det här felet bör du överväga en ökning av insamlingens dataflöde.

Det gick inte att ansluta till Azure Cosmos DB-emulatorn

HTTPS-certifikatet för Azure Cosmos DB-emulatorn är självsignerat. För att SDK ska fungera med emulatorn importerar du emulatorcertifikatet till en Java TrustStore. Mer information finns i Exportera Azure Cosmos DB-emulatorcertifikat.

Problem med beroendekonflikter

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

Ovanstående undantag tyder på att du är beroende av en äldre version av RxJava lib (t.ex. 1.2.2). Vår SDK förlitar sig på RxJava 1.3.8 som har API:er som inte är tillgängliga i tidigare version av RxJava.

Lösningen för sådana problem är att identifiera vilket annat beroende som ger RxJava-1.2.2 och exkludera det transitiva beroendet av RxJava-1.2.2 och låta CosmosDB SDK ta med den nyare versionen.

För att identifiera vilket bibliotek som innehåller RxJava-1.2.2 kör du följande kommando bredvid projektet pom.xml fil:

mvn dependency:tree

Mer information finns i guiden för maven-beroendeträd.

När du har identifierat att RxJava-1.2.2 är transitivt beroende av vilket annat beroende i projektet, kan du ändra beroendet av den lib-filen i din pom-fil och undanta RxJava transitivt beroende:

<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>

Mer information finns i guiden exkludera transitiva beroenden.

Aktivera klient-SDK-loggning

Java Async SDK använder SLF4j som loggningsfasad som stöder inloggning i populära loggningsramverk som log4j och logback.

Om du till exempel vill använda log4j som loggningsramverk lägger du till följande libs i java-klassökvägen.

<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>

Lägg också till en log4j-konfiguration.

# 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

Mer information finns i loggningshandboken för sfl4j.

Os-nätverksstatistik

Kör netstat-kommandot för att få en uppfattning om hur många anslutningar som finns i tillstånd som ESTABLISHED och CLOSE_WAIT.

I Linux kan du köra följande kommando.

netstat -nap

Filtrera resultatet till endast anslutningar till Azure Cosmos DB-slutpunkten.

Antalet anslutningar till Azure Cosmos DB-slutpunkten i ESTABLISHED tillståndet får inte vara större än din konfigurerade storlek på anslutningspoolen.

Många anslutningar till Azure Cosmos DB-slutpunkten kan vara i tillståndet CLOSE_WAIT . Det kan finnas fler än 1 000. Ett tal som är högt anger att anslutningar upprättas och rivs snabbt. Den här situationen kan orsaka problem. Mer information finns i avsnittet Vanliga problem och lösningar .