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

GÄLLER FÖR: NoSQL

Viktigt!

Den här artikeln beskriver endast felsökning för Azure Cosmos DB Java SDK v4. Mer information finns i Viktig information om Azure Cosmos DB Java SDK v4, Maven-lagringsplats och prestandatips. Om du för närvarande använder en äldre version än v4 kan du läsa guiden Migrera till Azure Cosmos DB Java SDK v4 för hjälp med att uppgradera till v4.

Den här artikeln beskriver vanliga problem, lösningar, diagnostiksteg och verktyg när du använder Azure Cosmos DB Java SDK v4 med Azure Cosmos DB för NoSQL-konton. Azure Cosmos DB Java SDK v4 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:

  • Ta en titt på avsnittet Vanliga problem och lösningar i den här artikeln.
  • Titta på Java SDK i den centrala lagringsplatsen för Azure Cosmos DB, som är tillgänglig öppen källkod på GitHub. Det har ett problemavsnitt som övervakas aktivt. Kontrollera om något liknande problem med en lösning redan har lämnats in. Ett användbart tips är att filtrera problem efter taggen *cosmos:v4-item* .
  • Granska prestandatipsen för Azure Cosmos DB Java SDK v4 och följ de föreslagna metoderna.
  • Läs resten av den här artikeln om du inte hittar någon lösning. Ange sedan ett GitHub-problem. Om det finns ett alternativ för att lägga till taggar i ditt GitHub-problem lägger du till en *cosmos:v4-item* tagg.

Samla in diagnostiken

Databas-, container-, objekt- och frågesvar i Java V4 SDK:n har egenskapen Diagnostik. Den här egenskapen registrerar all information som rör den enskilda begäran, inklusive om det fanns återförsök eller tillfälliga fel.

Diagnostiken returneras som en sträng. Strängen ändras med varje version eftersom den förbättras för att bättre felsöka olika scenarier. Med varje version av SDK kan strängen bryta sitt format. Parsa inte strängen för att undvika icke-bakåtkompatibla ändringar.

Följande kodexempel visar hur du läser diagnostikloggar med Java V4 SDK:

Viktigt!

Vi rekommenderar att du verifierar den lägsta rekommenderade versionen av Java V4 SDK och ser till att du använder den här versionen eller senare. Du kan kontrollera den rekommenderade versionen här.

Databasoperationer

CosmosDatabaseResponse databaseResponse = client.createDatabaseIfNotExists(databaseName);
CosmosDiagnostics diagnostics = databaseResponse.getDiagnostics();
logger.info("Create database diagnostics : {}", diagnostics); 

Containeråtgärder

CosmosContainerResponse containerResponse = database.createContainerIfNotExists(containerProperties,
                  throughputProperties);
CosmosDiagnostics diagnostics = containerResponse.getDiagnostics();
logger.info("Create container diagnostics : {}", diagnostics);

Objektåtgärder

// Write Item
CosmosItemResponse<Family> item = container.createItem(family, new PartitionKey(family.getLastName()),
                    new CosmosItemRequestOptions());
        
CosmosDiagnostics diagnostics = item.getDiagnostics();
logger.info("Create item diagnostics : {}", diagnostics);
        
// Read Item
CosmosItemResponse<Family> familyCosmosItemResponse = container.readItem(documentId,
                    new PartitionKey(documentLastName), Family.class);
        
CosmosDiagnostics diagnostics = familyCosmosItemResponse.getDiagnostics();
logger.info("Read item diagnostics : {}", diagnostics);

Frågeåtgärder

String sql = "SELECT * FROM c WHERE c.lastName = 'Witherspoon'";
        
CosmosPagedIterable<Family> filteredFamilies = container.queryItems(sql, new CosmosQueryRequestOptions(),
                    Family.class);
        
//  Add handler to capture diagnostics
filteredFamilies = filteredFamilies.handle(familyFeedResponse -> {
    logger.info("Query Item diagnostics through handle : {}", 
    familyFeedResponse.getCosmosDiagnostics());
});
        
//  Or capture diagnostics through iterableByPage() APIs.
filteredFamilies.iterableByPage().forEach(familyFeedResponse -> {
    logger.info("Query item diagnostics through iterableByPage : {}",
    familyFeedResponse.getCosmosDiagnostics());
});

Azure Cosmos DB-undantag

try {
  CosmosItemResponse<Family> familyCosmosItemResponse = container.readItem(documentId,
                    new PartitionKey(documentLastName), Family.class);
} catch (CosmosException ex) {
  CosmosDiagnostics diagnostics = ex.getDiagnostics();
  logger.error("Read item failure diagnostics : {}", diagnostics);
}

Logga diagnostiken

Java V4 SDK-versioner v4.43.0 och senare stöder automatisk loggning av Cosmos Diagnostics för alla begäranden eller fel om de uppfyller vissa kriterier. Programutvecklare kan definiera tröskelvärden för svarstid (för punkt (skapa, läsa, ersätta, uppdatera, korrigera) eller icke-punktsåtgärder (fråga, ändringsflöde, bulk och batch)), begära debitering och nyttolaststorlek. Om begäranden överskrider dessa definierade tröskelvärden genereras cosmos-diagnostiken för dessa begäranden automatiskt.

Som standard loggar Java v4 SDK dessa diagnostik automatiskt i ett visst format. Detta kan dock ändras genom att implementera CosmosDiagnosticsHandler gränssnittet och tillhandahålla din egen anpassade diagnostikhanterare.

Dessa CosmosDiagnosticsThresholds och CosmosDiagnosticsHandler kan sedan användas i CosmosClientTelemetryConfig objektet, som ska skickas till CosmosClientBuilder när synkroniserings- eller asynkroniseringsklient skapas.

Obs! Dessa diagnostiktrösklar tillämpas på olika typer av diagnostik, inklusive loggning, spårning och klienttelemetri.

Följande kodexempel visar hur du definierar diagnostiktrösklar, anpassad diagnostikloggare och använder dem via konfiguration av klienttelemetri:

Definiera anpassade tröskelvärden för diagnostik

//  Create diagnostics threshold
CosmosDiagnosticsThresholds cosmosDiagnosticsThresholds = new CosmosDiagnosticsThresholds();
//  These thresholds are for demo purposes
//  NOTE: Do not use the same thresholds for production
cosmosDiagnosticsThresholds.setPayloadSizeThreshold(100_00);
cosmosDiagnosticsThresholds.setPointOperationLatencyThreshold(Duration.ofSeconds(1));
cosmosDiagnosticsThresholds.setNonPointOperationLatencyThreshold(Duration.ofSeconds(5));
cosmosDiagnosticsThresholds.setRequestChargeThreshold(100f);

Definiera anpassad diagnostikhanterare

//  By default, DEFAULT_LOGGING_HANDLER can be used
CosmosDiagnosticsHandler cosmosDiagnosticsHandler = CosmosDiagnosticsHandler.DEFAULT_LOGGING_HANDLER;

//  App developers can also define their own diagnostics handler
cosmosDiagnosticsHandler = new CosmosDiagnosticsHandler() {
    @Override
    public void handleDiagnostics(CosmosDiagnosticsContext diagnosticsContext, Context traceContext) {
        logger.info("This is custom diagnostics handler: {}", diagnosticsContext.toJson());
    }
};

Definiera CosmosClientTelemetryConfig

//  Create Client Telemetry Config
CosmosClientTelemetryConfig cosmosClientTelemetryConfig =
    new CosmosClientTelemetryConfig();
cosmosClientTelemetryConfig.diagnosticsHandler(cosmosDiagnosticsHandler);
cosmosClientTelemetryConfig.diagnosticsThresholds(cosmosDiagnosticsThresholds);

//  Create sync client
CosmosClient client = new CosmosClientBuilder()
    .endpoint(AccountSettings.HOST)
    .key(AccountSettings.MASTER_KEY)
    .clientTelemetryConfig(cosmosClientTelemetryConfig)
    .buildClient();

Designa om

Se vår guide för att utforma motståndskraftiga program med Azure Cosmos DB SDK:er för vägledning om hur du utformar motståndskraftiga program och lär dig vilka som är SDK:s återförsökssemantik.

Vanliga fel och lösningar

Kontrollera portalmåtten

Genom att kontrollera portalmåtten kan du avgöra om det är ett problem på klientsidan eller om det finns ett problem med tjänsten. Om måtten till exempel innehåller en hög frekvens av hastighetsbegränsade begäranden (HTTP-statuskod 429) vilket innebär att begäran begränsas kontrollerar du avsnittet Begärandefrekvens för stor .

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

Allmänna förslag

För bästa prestanda:

  • 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 50 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.

Anslut begränsning

Anslut begränsning kan inträffa på grund av antingen en anslutningsgräns på en värddator eller azure SNAT-portöverbelastning (PAT).

Anslut ionsgrä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 för Azure Cosmos DB Java SDK v4.

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:t 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å appdatorn öppnar du portintervallet 10 000 till 20 000, som används av direktläget. Följ också Anslut ionsgränsen på en värddator.

UnknownHostException

UnknownHostException innebär att Java-ramverket inte kan matcha DNS-posten för Azure Cosmos DB-slutpunkten på den berörda datorn. Du bör kontrollera att datorn kan matcha DNS-posten eller om du har någon anpassad DNS-matchningsprogramvara (till exempel VPN eller proxy eller en anpassad lösning), se till att den innehåller rätt konfiguration för DNS-slutpunkten som felet påstår inte kan lösas. Om felet är konstant kan du verifiera datorns DNS-matchning via ett curl kommando till slutpunkten som beskrivs i felet.

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:n har ett Async-API 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, som lägger till objekt i en container (se här för vägledning om hur du konfigurerar databasen och containern.) 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.

Java SDK V4 (Maven com.azure::azure-cosmos) Async API


//Bad code with read timeout exception

int requestTimeoutInSeconds = 10;

/* ... */

AtomicInteger failureCount = new AtomicInteger();
// Max number of concurrent item inserts is # CPU cores + 1
Flux<Family> familyPub =
        Flux.just(Families.getAndersenFamilyItem(), Families.getAndersenFamilyItem(), Families.getJohnsonFamilyItem());
familyPub.flatMap(family -> {
    return container.createItem(family);
}).flatMap(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) {
    }
    return Mono.empty();
}).doOnError(Exception.class, exception -> {
    failureCount.incrementAndGet();
}).blockLast();
assert(failureCount.get() > 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.

Java SDK V4 (Maven com.azure::azure-cosmos) Async API

// Have a singleton instance of an executor and a scheduler.
ExecutorService ex  = Executors.newFixedThreadPool(30);
Scheduler customScheduler = Schedulers.fromExecutor(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 .publishOn(customScheduler) .

Java SDK V4 (Maven com.azure::azure-cosmos) Async API

container.createItem(family)
        .publishOn(customScheduler) // Switches the thread.
        .subscribe(
                // ...
        );

Med hjälp publishOn(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.

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.

  • Implementera backoff vid getRetryAfterInMilliseconds-intervall

    Under prestandatestningen bör du öka belastningen tills en liten mängd begäranden begränsas. Om begränsningen är begränsad bör klientprogrammet backa för det serverspecifika återförsöksintervallet. Om du respekterar backoffen ser du till att du ägnar minimal tid åt att vänta mellan återförsöken.

Felhantering från Java SDK Reactive Chain

Felhantering från Azure Cosmos DB Java SDK är viktigt när det gäller klientens programlogik. Det finns olika mekanismer för felhantering som tillhandahålls av reaktorkärnramverket som kan användas i olika scenarier. Vi rekommenderar att kunderna förstår dessa felhanteringsoperatorer i detalj och använder de som passar deras logikscenarier för återförsök bäst.

Viktigt!

Vi rekommenderar inte att du använder onErrorContinue() operatorn eftersom den inte stöds i alla scenarier. Observera att det onErrorContinue() är en specialistoperatör som kan göra beteendet för din reaktiva kedja oklart. Det fungerar på överordnade, inte underordnade operatorer, det kräver specifikt operatörsstöd för att fungera och omfånget kan enkelt spridas uppströms till bibliotekskod som inte förutsåg det (vilket resulterar i oavsiktligt beteende.). Mer information om den här specialoperatorn finns i dokumentationenonErrorContinue().

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

Azure Cosmos DB Java SDK hämtar många beroenden. Om projektets beroendeträd i allmänhet innehåller en äldre version av en artefakt som Azure Cosmos DB Java SDK är beroende av, kan detta leda till att oväntade fel genereras när du kör programmet. Om du felsöker varför programmet oväntat utlöser ett undantag är det en bra idé att dubbelkolla att beroendeträdet inte av misstag drar in en äldre version av en eller flera Av Azure Cosmos DB Java SDK-beroenden.

Lösningen för ett sådant problem är att identifiera vilket av dina projektberoenden som ger den gamla versionen och undanta det transitiva beroendet av den äldre versionen och tillåta Azure Cosmos DB Java SDK att ta in den nyare versionen.

Om du vill identifiera vilket av dina projektberoenden som ger en äldre version av något som Azure Cosmos DB Java SDK är beroende av kör du följande kommando mot projektet pom.xml fil:

mvn dependency:tree

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

När du vet vilket beroende av projektet som är beroende av en äldre version kan du ändra beroendet av den lib i pom-filen och undanta det transitiva beroendet enligt exemplet nedan (som förutsätter att reactor-core är det inaktuella beroendet):

<dependency>
  <groupId>${groupid-of-lib-which-brings-in-reactor}</groupId>
  <artifactId>${artifactId-of-lib-which-brings-in-reactor}</artifactId>
  <version>${version-of-lib-which-brings-in-reactor}</version>
  <exclusions>
    <exclusion>
      <groupId>io.projectreactor</groupId>
      <artifactId>reactor-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Mer information finns i guiden exkludera transitiva beroenden.

Aktivera klient-SDK-loggning

Azure Cosmos DB Java SDK v4 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 INFO and its only appender to A1.
log4j.rootLogger=INFO, A1

log4j.category.com.azure.cosmos=INFO
#log4j.category.io.netty=OFF
#log4j.category.io.projectreactor=OFF
# 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

I Windows kan du köra samma kommando med olika argumentflaggor:

netstat -abn

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 .

Vanliga frågeproblem

Frågemåtten hjälper dig att avgöra var frågan används för det mesta. Från frågemåtten kan du se hur mycket av det som spenderas på serverdelen jämfört med klienten. Läs mer i frågeprestandaguiden.

Nästa steg