Řešení potíží při používání sady Java SDK služby Azure Cosmos DB verze 4 s účty API for NoSQL

PLATÍ PRO: NoSQL

Důležité

Tento článek popisuje řešení potíží pouze se sadou Java SDK služby Azure Cosmos DB verze 4. Další informace najdete v poznámkách k verzi sady Java SDK služby Azure Cosmos DB verze 4, úložišti Maven a tipy k výkonu. Pokud aktuálně používáte starší verzi než v4, přečtěte si průvodce migrací na sadu Java SDK služby Azure Cosmos DB verze 4 , kde najdete pomoc s upgradem na verzi 4.

Tento článek se zabývá běžnými problémy, alternativními řešeními, diagnostickými kroky a nástroji při používání sady Java SDK služby Azure Cosmos DB v4 s účty Azure Cosmos DB for NoSQL. Sada Azure Cosmos DB Java SDK v4 poskytuje logickou reprezentaci na straně klienta pro přístup ke službě Azure Cosmos DB for NoSQL. Tento článek popisuje nástroje a přístupy, které vám pomůžou v případě jakýchkoli problémů.

Začněte tímto seznamem:

  • Podívejte se na část Běžné problémy a alternativní řešení v tomto článku.
  • Podívejte se na sadu Java SDK v centrálním úložišti Azure Cosmos DB, které je dostupné open source na GitHubu. Obsahuje oddíl problémů, který je aktivně monitorován. Zkontrolujte, jestli už není nějaký podobný problém s alternativním řešením. Jedním z užitečných tipů je filtrování problémů podle značky *cosmos:v4-item* .
  • Projděte si tipy pro zvýšení výkonu sady Java SDK služby Azure Cosmos DB verze 4 a postupujte podle navrhovaných postupů.
  • Pokud jste nenašli řešení, přečtěte si zbytek tohoto článku. Pak vytvořte problém GitHubu. Pokud máte možnost přidat značky k problému s GitHubem, přidejte značku *cosmos:v4-item* .

Zachycení diagnostiky

Odpovědi databáze, kontejneru, položky a dotazu mají v sadě Java V4 SDK vlastnost Diagnostics. Tato vlastnost zaznamenává všechny informace související s jedním požadavkem, včetně toho, jestli došlo k opakovaným pokusům nebo přechodným selháním.

Diagnostika se vrátí jako řetězec. Řetězec se mění s každou verzí, protože je vylepšen, aby lépe řešit různé scénáře. U každé verze sady SDK může řetězec narušit jeho formát. Řetězec neza parsujte, abyste se vyhnuli zásadním změnám.

Následující ukázka kódu ukazuje, jak číst diagnostické protokoly pomocí sady Java SDK V4:

Důležité

Doporučujeme ověřit minimální doporučenou verzi sady Java SDK verze 4 a ujistit se, že používáte tuto nebo vyšší verzi. Tady můžete zkontrolovat doporučenou verzi.

Databázové operace

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

Operace s kontejnery

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

Operace s položkami

// 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);

Operace dotazů

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());
});

Výjimky služby Azure Cosmos DB

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);
}

Protokolování diagnostiky

Java SDK verze 4 verze 4.43.0 a vyšší podporují automatické protokolování diagnostiky cosmos pro všechny požadavky nebo chyby, pokud splňují určitá kritéria. Vývojáři aplikací můžou definovat prahové hodnoty pro latenci (pro bod (vytvoření, čtení, nahrazení, upsert, opravu) nebo operace bez bodu (dotaz, kanál změn, hromadný a dávkový)), poplatky za žádost a velikost datové části. Pokud požadavky překročí tyto definované prahové hodnoty, automaticky se vygeneruje diagnostika cosmos pro tyto požadavky.

Sada Java SDK v4 ve výchozím nastavení protokoluje tyto diagnostiky automaticky v určitém formátu. Můžete to ale změnit implementací CosmosDiagnosticsHandler rozhraní a poskytnutím vlastní obslužné rutiny diagnostiky.

Ty CosmosDiagnosticsThresholds se CosmosDiagnosticsHandler pak dají použít v CosmosClientTelemetryConfig objektu, který by se měl předat CosmosClientBuilder při vytváření synchronizačního nebo asynchronního klienta.

POZNÁMKA: Tyto prahové hodnoty diagnostiky se použijí napříč různými typy diagnostiky, včetně protokolování, trasování a telemetrie klienta.

Následující ukázky kódu ukazují, jak definovat prahové hodnoty diagnostiky, vlastní diagnostický protokolovací nástroj a používat je prostřednictvím konfigurace telemetrie klienta:

Definování vlastních prahových hodnot diagnostiky

//  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);

Definování vlastní obslužné rutiny diagnostiky

//  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());
    }
};

Definování služby 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();

Návrh opakování

Pokyny k návrhu odolných aplikací pomocí sad SDK služby Azure Cosmos DB najdete v našem průvodci návrhem odolných aplikací a informace o sémantice opakování sady SDK.

Běžné problémy a alternativní řešení

Kontrola metrik portálu

Kontrola metrik portálu vám pomůže určit, jestli se jedná o problém na straně klienta nebo jestli došlo k problému se službou. Pokud například metriky obsahují vysokou rychlost požadavků omezených rychlostí (stavový kód HTTP 429), což znamená, že požadavek se omezuje, zkontrolujte příliš velkou část Frekvence požadavků.

Problémy se sítí, selhání časového limitu čtení Netty, nízká propustnost, vysoká latence

Obecné návrhy

Pokud chcete zajistit nejvyšší výkon:

  • Ujistěte se, že je aplikace spuštěná ve stejné oblasti jako váš účet služby Azure Cosmos DB.
  • Zkontrolujte využití procesoru na hostiteli, na kterém je aplikace spuštěná. Pokud je využití procesoru 50 procent nebo více, spusťte aplikaci na hostiteli s vyšší konfigurací. Nebo můžete zatížení distribuovat na více počítačích.

Omezování připojení

K omezování připojení může dojít z důvodu limitu připojení na hostitelském počítači nebo vyčerpání portů AZURE SNAT (PAT).

Omezení připojení na hostitelském počítači

Některé systémy Linux, například Red Hat, mají horní limit celkového počtu otevřených souborů. Sokety v Linuxu se implementují jako soubory, takže toto číslo omezuje také celkový počet připojení. Spusťte následující příkaz:

ulimit -a

Maximální povolený počet povolených otevřených souborů, které jsou označené jako "nofile", musí být alespoň dvojnásobná velikost fondu připojení. Další informace najdete v tipech k výkonu sady Java SDK služby Azure Cosmos DB verze 4.

Vyčerpání portů AZURE SNAT (PAT)

Pokud je vaše aplikace nasazená ve službě Azure Virtual Machines bez veřejné IP adresy, navazují ve výchozím nastavení porty Azure SNAT připojení k libovolnému koncovému bodu mimo váš virtuální počítač. Počet připojení povolených z virtuálního počítače ke koncovému bodu služby Azure Cosmos DB je omezený konfigurací Azure SNAT.

Porty Azure SNAT se používají jenom v případech, kdy má váš virtuální počítač privátní IP adresu a proces z virtuálního počítače se pokusí připojit k veřejné IP adrese. Existují dvě alternativní řešení, jak se vyhnout omezení Azure SNAT:

  • Přidejte koncový bod služby Azure Cosmos DB do podsítě virtuální sítě Azure Virtual Machines. Další informace najdete v tématu Koncové body služby Azure Virtual Network.

    Když je koncový bod služby povolený, požadavky se už do Azure Cosmos DB neposílají z veřejné IP adresy. Místo toho se odešle identita virtuální sítě a podsítě. Tato změna může vést k poklesu brány firewall, pokud jsou povoleny pouze veřejné IP adresy. Pokud používáte bránu firewall, když povolíte koncový bod služby, přidejte do brány firewall podsíť pomocí seznamů ACL virtuální sítě.

  • Přiřaďte virtuálnímu počítači Azure veřejnou IP adresu.

Nejde se spojit se službou – brána firewall

ConnectTimeoutException značí, že sada SDK se nemůže spojit se službou. Při použití přímého režimu může dojít k selhání podobné tomuto:

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]

Pokud máte na počítači aplikace spuštěnou bránu firewall, otevřete rozsah portů 10 000 až 20 000, které používají přímý režim. Také postupujte podle limitu připojení na hostitelském počítači.

UnknownHostException

UnknownHostException znamená, že architektura Java nemůže přeložit položku DNS pro koncový bod služby Azure Cosmos DB v ovlivněném počítači. Měli byste ověřit, že počítač dokáže přeložit záznam DNS nebo pokud máte nějaký vlastní software pro překlad DNS (například VPN nebo proxy server nebo vlastní řešení), ujistěte se, že obsahuje správnou konfiguraci pro koncový bod DNS, že chybu nejde vyřešit. Pokud je chyba konstantní, můžete pomocí příkazu ověřit překlad curl DNS počítače do koncového bodu popsaného v této chybě.

Proxy server HTTP

Pokud používáte proxy server HTTP, ujistěte se, že podporuje počet připojení nakonfigurovaných v sadě SDK ConnectionPolicy. V opačném případě dochází k problémům s připojením.

Neplatný vzor kódování: Blokování vlákna vstupně-výstupních operací Netty

Sada SDK používá ke komunikaci se službou Azure Cosmos DB knihovnu Netty IO. Sada SDK má asynchronní rozhraní API a používá neblokující vstupně-výstupní rozhraní API netty. Práce vstupně-výstupních operací sady SDK se provádí na vláknech IO Netty. Počet vláken IO Netty je nakonfigurovaný tak, aby byl stejný jako počet jader procesoru počítače aplikace.

Vlákna Netty vstupně-výstupních operací jsou určena pouze pro neblokující vstupně-výstupní operace Netty. Sada SDK vrátí výsledek vyvolání rozhraní API na jednom ze vstupně-výstupních vláken Netty do kódu aplikace. Pokud aplikace po přijetí výsledků na vlákně Netty provede dlouhou operaci, nemusí sada SDK mít dostatek vstupně-výstupních vláken k provedení interní vstupně-výstupních operací. Takové kódování aplikací může mít za následek nízkou propustnost, vysokou latenci a io.netty.handler.timeout.ReadTimeoutException selhání. Alternativním řešením je přepnout vlákno, když víte, že operace nějakou dobu trvá.

Podívejte se například na následující fragment kódu, který přidává položky do kontejneru (tady najdete pokyny k nastavení databáze a kontejneru.) Můžete provádět dlouhou práci, která trvá více než několik milisekund na vlákně Netty. Pokud ano, můžete se nakonec dostat do stavu, ve kterém není k dispozici žádné vlákno netty vstupně-výstupních operací pro zpracování vstupně-výstupních operací. Výsledkem je chyba ReadTimeoutException.

Rozhraní Async API sady Java SDK V4 (Maven com::azure-cosmos)


//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);

Alternativním řešením je změnit vlákno, na kterém provádíte práci, která nějakou dobu trvá. Definujte jednu instanci plánovače pro vaši aplikaci.

Rozhraní Async API sady Java SDK V4 (Maven com::azure-cosmos)

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

Možná budete muset udělat práci, která nějakou dobu trvá, například výpočetně náročné práce nebo blokování vstupně-výstupních operací. V tomto případě přepněte vlákno na pracovní proces poskytovaný vaším customScheduler rozhraním .publishOn(customScheduler) API.

Rozhraní Async API sady Java SDK V4 (Maven com::azure-cosmos)

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

Pomocí příkazu publishOn(customScheduler)uvolníte vlákno Netty io a přepnete na vlastní vlákno poskytované vlastním plánovačem. Tato úprava řeší problém. Už nebudete mít io.netty.handler.timeout.ReadTimeoutException chybu.

Příliš vysoká frekvence požadavků

Toto selhání je selhání na straně serveru. Označuje, že jste spotřebovali zřízenou propustnost. Zkuste to znovu později. Pokud k tomuto selhání dochází často, zvažte zvýšení propustnosti kolekce.

  • Implementace backoffu v intervalech getRetryAfterInMilliseconds

    Během testování výkonu byste měli zvýšit zatížení, dokud nedojde k omezení malé míry požadavků. Pokud dojde k omezení, měla by se klientská aplikace pro interval opakování zadaný serverem vrátit zpět. Dodržování zpětného běhu zajišťuje, že strávíte minimální dobu čekáním mezi opakovanými pokusy.

Zpracování chyb z reaktivního řetězce sady Java SDK

Zpracování chyb ze sady Java SDK služby Azure Cosmos DB je důležité, pokud jde o logiku aplikace klienta. Existují různé mechanismy zpracování chyb poskytované architekturou jádra reaktoru, které je možné použít v různých scénářích. Doporučujeme zákazníkům podrobně porozumět těmto operátorům zpracování chyb a použít ty, které nejlépe vyhovují scénářům logiky opakování.

Důležité

Operátor nedoporučujeme používat onErrorContinue() , protože se nepodporuje ve všech scénářích. Všimněte si, že onErrorContinue() je specializovaný operátor, který může znamenat, že chování reaktivního řetězce není jasné. Funguje na upstreamových, nikoli podřízených operátorech, vyžaduje, aby fungoval konkrétní operátor, a obor může snadno rozšířit upstream do kódu knihovny, který ho nepředvídal (což vede k nezamýšlenému chování.) Další podrobnosti o tomto speciálním operátorovi najdete v dokumentacionErrorContinue().

Selhání při připojování k emulátoru služby Azure Cosmos DB

Certifikát HTTPS emulátoru služby Azure Cosmos DB je podepsaný svým držitelem. Aby sada SDK fungovala s emulátorem, naimportujte certifikát emulátoru do java TrustStore. Další informace najdete v tématu Export certifikátů emulátoru služby Azure Cosmos DB.

Problémy se konflikty závislostí

Sada Azure Cosmos DB Java SDK načítá mnoho závislostí; Obecně platí, že pokud strom závislostí projektu obsahuje starší verzi artefaktu, na které závisí sada Java SDK služby Azure Cosmos DB, může dojít k neočekávaným chybám generovaným při spuštění aplikace. Pokud ladíte, proč vaše aplikace neočekávaně vyvolá výjimku, je vhodné pečlivě zkontrolovat, jestli strom závislostí nechtěně nenačítá starší verzi jedné nebo více závislostí sady Java SDK služby Azure Cosmos DB.

Alternativním řešením takového problému je určit, které závislosti projektu přinášejí starou verzi, a vyloučit tranzitivní závislost na této starší verzi a umožnit sadě Azure Cosmos DB Java SDK přenést novější verzi.

Pokud chcete zjistit, které závislosti projektu přinášejí starší verzi něčeho, na čem závisí sada Java SDK služby Azure Cosmos DB, spusťte pro váš projekt následující příkaz pom.xml souboru:

mvn dependency:tree

Další informace najdete v průvodci stromem závislostí maven.

Jakmile víte, která závislost projektu závisí na starší verzi, můžete upravit závislost na této knihovně v souboru pom a vyloučit tranzitivní závislost podle následujícího příkladu (což předpokládá, že jádro reaktoru je zastaralá závislost):

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

Další informace najdete v průvodci vyloučením tranzitivní závislosti.

Povolení protokolování klientské sady SDK

Sada Azure Cosmos DB Java SDK v4 používá jako fasádu protokolování SLF4j, která podporuje protokolování do oblíbených rozhraní protokolování, jako jsou log4j a logback.

Pokud například chcete jako rozhraní protokolování použít log4j, přidejte do cesty ke třídám Java následující knihovny.

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

Přidejte také konfiguraci log4j.

# 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

Další informace najdete v návodu k protokolování sfl4j.

Statistika sítě operačního systému

Spuštěním příkazu netstat získejte představu o tom, kolik připojení je ve stavech, například ESTABLISHED a CLOSE_WAIT.

V Linuxu můžete spustit následující příkaz.

netstat -nap

Ve Windows můžete spustit stejný příkaz s různými příznaky argumentů:

netstat -abn

Vyfiltrujte výsledek jenom na připojení ke koncovému bodu služby Azure Cosmos DB.

Počet připojení ke koncovému bodu služby Azure Cosmos DB ve ESTABLISHED stavu nesmí být větší než nakonfigurovaná velikost fondu připojení.

Ve stavu může být mnoho připojení ke koncovému CLOSE_WAIT bodu služby Azure Cosmos DB. Může existovat více než 1 000. Číslo, které je vysoké, značí, že se připojení navazují a rychle odtrhávají. Tato situace může způsobit problémy. Další informace najdete v části Běžné problémy a alternativní řešení .

Běžné problémy s dotazy

Metriky dotazů vám pomůžou určit, kde dotaz tráví většinu času. Z metrik dotazů můžete zjistit, kolik z toho se stráví back-endem a klientem. Přečtěte si další informace o průvodci výkonem dotazů.

Další kroky