Sdílet prostřednictvím


Diagnostika a řešení potíží s pomalými požadavky v sadě .NET SDK služby Azure Cosmos DB

PLATÍ PRO: NoSQL

Ve službě Azure Cosmos DB si můžete všimnout pomalých požadavků. Zpoždění můžou nastat z několika důvodů, jako je omezování požadavků nebo způsob, jakým je vaše aplikace navržená. Tento článek vysvětluje různé původní příčiny tohoto problému.

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

Omezování požadavků je nejčastějším důvodem pomalých požadavků. Azure Cosmos DB omezuje požadavky, pokud překročí přidělené jednotky žádostí pro databázi nebo kontejner. Sada SDK má integrovanou logiku pro opakování těchto požadavků. Článek o řešení potíží s příliš velkou rychlostí požadavků vysvětluje, jak zkontrolovat, jestli dochází k omezování požadavků. Tento článek také popisuje, jak v budoucnu škálovat účet, aby se těmto problémům vyhnul.

Návrh aplikací

Při návrhu aplikace postupujte podle osvědčených postupů sady .NET SDK pro dosažení nejlepšího výkonu. Pokud vaše aplikace nedodržuje osvědčené postupy sady SDK, můžou se vám zobrazit pomalé nebo neúspěšné požadavky.

Při vývoji aplikace zvažte následující skutečnosti:

Operace s metadaty

Pokud potřebujete ověřit, že databáze nebo kontejner existuje, neprovádíte to voláním Create...IfNotExistsAsync nebo Read...Async před provedením operace položky. Ověření by se mělo provést pouze při spuštění aplikace, pokud je to nutné, pokud očekáváte, že se odstraní. Tyto operace s metadaty generují dodatečnou latenci, nemají smlouvu o úrovni služeb (SLA) a mají svá vlastní samostatná omezení. Nedají se škálovat jako datové operace.

Pomalé požadavky v hromadném režimu

Hromadný režim je režim optimalizovaný pro propustnost, který je určený pro operace s velkým objemem dat, nikoli režim optimalizovaný pro latenci. Je určený k nasycení dostupné propustnosti. Pokud při použití hromadného režimu dochází k pomalým požadavkům, ujistěte se, že:

  • Vaše aplikace se kompiluje v konfiguraci vydané verze.
  • Při ladění aplikace neměříte latenci (nejsou připojeny žádné ladicí programy).
  • Objem operací je vysoký, nepoužívejte hromadně pro méně než 1 000 operací. Zřízená propustnost určuje, kolik operací za sekundu můžete zpracovat, vaším cílem by hromadné využití bylo co nejvíce.
  • Monitorujte kontejner pro scénáře omezování. Pokud se kontejner výrazně omezuje, znamená to, že objem dat je větší než zřízená propustnost, musíte buď vertikálně navýšit kapacitu kontejneru, nebo snížit objem dat (možná vytvořit menší dávky dat najednou).
  • Model správně používáte async/await ke zpracování všech souběžných úloh a neblokujete žádnou asynchronní operaci.

Zachytávání diagnostiky

Všechny odpovědi v sadě SDK, včetně CosmosException, mají Diagnostics vlastnost. 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 se vylepšuje pro řešení potíží s různými scénáři. U každé verze sady SDK bude řetězec obsahovat zásadní změny formátování. Ř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 .NET SDK:

try
{
    ItemResponse<Book> response = await this.Container.CreateItemAsync<Book>(item: testItem);
    if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan)
    {
        // Log the response.Diagnostics.ToString() and add any additional info necessary to correlate to other logs 
    }
}
catch (CosmosException cosmosException)
{
    // Log the full exception including the stack trace with: cosmosException.ToString()
    
    // The Diagnostics can be logged separately if required with: cosmosException.Diagnostics.ToString()
}

// When using Stream APIs
ResponseMessage response = await this.Container.CreateItemStreamAsync(partitionKey, stream);
if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan || !response.IsSuccessStatusCode)
{
    // Log the diagnostics and add any additional info necessary to correlate to other logs with: response.Diagnostics.ToString()
}

Diagnostika ve verzi 3.19 a novější

Struktura JSON obsahuje zásadní změny v každé verzi sady SDK. To zneschváňuje analýzu. JSON představuje stromovou strukturu požadavku procházející sadou SDK. V následujících částech najdete několik klíčových věcí, na které se můžete podívat.

Historie procesoru

Nejčastější příčinou nízkých požadavků je vysoké využití procesoru. Pro zajištění optimální latence by využití procesoru mělo být přibližně 40 %. K monitorování maximálního (ne průměrného) využití procesoru použijte interval 10 sekund. Špičky procesoru jsou častější u dotazů napříč oddíly, kdy požadavky můžou pro jeden dotaz provádět více připojení.

Mezi časové limity patří diagnostika, která obsahuje následující:

"systemHistory": [
{
"dateUtc": "2021-11-17T23:38:28.3115496Z",
"cpu": 16.731,
"memory": 9024120.000,
"threadInfo": {
"isThreadStarving": "False",
....
}

},
{
"dateUtc": "2021-11-17T23:38:38.3115496Z",
"cpu": 16.731,
"memory": 9024120.000,
"threadInfo": {
"isThreadStarving": "False",
....
}

},
...
]
  • cpu Pokud jsou hodnoty větší než 70 procent, časový limit bude pravděpodobně způsoben vyčerpáním procesoru. V takovém případě je řešením zjistit zdroj vysokého využití procesoru a snížit toto využití nebo škálovat počítač na větší velikost prostředků.
  • threadInfo/isThreadStarving Pokud uzly mají True hodnoty, příčinou je hladovění vlákna. V tomto případě je řešením prozkoumat zdroj nebo zdroje hladovění vlákna (potenciálně uzamčená vlákna) nebo škálovat počítač nebo počítače na větší velikost prostředku.
  • dateUtc Pokud doba mezi měřeními není přibližně 10 sekund, znamená to také kolize ve fondu vláken. Procesor se měří jako nezávislá úloha, která se každých 10 sekund zařidí do fronty ve fondu vláken. Pokud je doba mezi měřeními delší, znamená to, že asynchronní úlohy se nedají včas zpracovat. Nejběžnějším scénářem je, že kód aplikace blokuje volání přes asynchronní kód.

Řešení

Klientské aplikaci, která používá sadu SDK, by měla být vertikálně navýšena kapacita nebo by se měla škálovat na více instancí.

HttpResponseStats

HttpResponseStatsjsou požadavky, které přejdou na bránu. I v přímém režimu získá sada SDK všechny informace o metadatech z brány.

Pokud je požadavek pomalý, nejprve ověřte, že žádný z předchozích návrhů nevyvolá požadované výsledky. Pokud je stále pomalý, různé vzory ukazují na různé problémy. Další podrobnosti najdete v následující tabulce.

Počet žádostí Scénář Popis
Jedno pro všechny Časový limit požadavku nebo HttpRequestExceptions Odkazuje na vyčerpání portů SNAT nebo nedostatek prostředků na počítači pro zpracování požadavku v čase.
Jedno nebo malé procento (smlouva SLA není porušená) Všechny Jedno nebo malé procento pomalých požadavků může být způsobeno několika různými přechodnými problémy a mělo by se očekávat.
Vše Vše Odkazuje na problém s infrastrukturou nebo sítí.
Smlouva SLA byla porušena. Neprošly žádné změny aplikace a smlouva SLA se zrušila. Odkazuje na problém se službou Azure Cosmos DB.
"HttpResponseStats": [
    {
        "StartTimeUTC": "2021-06-15T13:53:09.7961124Z",
        "EndTimeUTC": "2021-06-15T13:53:09.7961127Z",
        "RequestUri": "https://127.0.0.1:8081/dbs/347a8e44-a550-493e-88ee-29a19c070ecc/colls/4f72e752-fa91-455a-82c1-bf253a5a3c4e",
        "ResourceType": "Collection",
        "HttpMethod": "GET",
        "ActivityId": "e16e98ec-f2e3-430c-b9e9-7d99e58a4f72",
        "StatusCode": "OK"
    }
]

StoreResult

StoreResult představuje jeden požadavek na službu Azure Cosmos DB pomocí přímého režimu s protokolem TCP.

Pokud je stále pomalý, různé vzory ukazují na různé problémy. Další podrobnosti najdete v následující tabulce.

Počet žádostí Scénář Popis
Jedno pro všechny StoreResult obsahuje TransportException Odkazuje na vyčerpání portů SNAT nebo nedostatek prostředků na počítači pro zpracování požadavku v čase.
Jedno nebo malé procento (smlouva SLA není porušená) Všechny Jedno nebo malé procento pomalých požadavků může být způsobeno několika různými přechodnými problémy a mělo by se očekávat.
Vše Vše Problém s infrastrukturou nebo sítí
Smlouva SLA byla porušena. Požadavky obsahují více kódů chyb selhání, například 410 Odkazuje na problém se službou Azure Cosmos DB nebo klientským počítačem.
Smlouva SLA byla porušena. StorePhysicalAddress jsou stejné, bez stavového kódu selhání. Pravděpodobně problém se službou Azure Cosmos DB.
Smlouva SLA byla porušena. StorePhysicalAddress mají stejné ID oddílu, ale jiná ID replik bez stavového kódu selhání. Pravděpodobně problém se službou Azure Cosmos DB.
Smlouva SLA byla porušena. StorePhysicalAddress je náhodný, bez stavový kód selhání. Odkazuje na problém s počítačem.

U více výsledků úložiště pro jeden požadavek mějte na paměti následující skutečnosti:

  • Silná konzistence a konzistence omezené nestarosti vždy mají alespoň dva výsledky úložiště.
  • Zkontrolujte stavový kód každého StoreResult. Sada SDK se automaticky opakuje v několika různých přechodných selháních. Sada SDK se neustále vylepšuje, aby zahrnovala více scénářů.

RequestTimeline

Umožňuje zobrazit čas pro různé fáze odesílání a přijímání požadavků v přenosové vrstvě.

  • ChannelAcquisitionStarted: Čas získání nebo vytvoření nového připojení. Připojení je možné vytvořit z mnoha důvodů, například: Předchozí připojení bylo uzavřeno kvůli nečinnosti pomocí CosmosClientOptions.IdleTcpConnectionTimeout, objem souběžných požadavků překračuje CosmosClientOptions.MaxRequestsPerTcpConnection, připojení bylo ukončeno kvůli chybě sítě nebo aplikace nesleduje vzor Singleton a nové instance se neustále vytvářejí. Po navázání připojení se znovu použije pro následné požadavky, takže by to nemělo mít vliv na latenci P99, pokud se nedějí dříve uvedené problémy.
  • Pipelined Příčinou velkého požadavku může být velký čas.
  • Transit time je velký, což vede k problému se sítí. Porovnejte toto číslo s číslem BELatencyInMs. Pokud BELatencyInMs je malý, pak byl čas strávený v síti, a ne ve službě Azure Cosmos DB.
  • Received Příčinou velkého času může být problém s hladovým ukončením vlákna. Jedná se o čas mezi odezvou a vrácením výsledku.

ServiceEndpointStatistics

Informace o konkrétním back-endovém serveru Sada SDK může otevřít více připojení k jednomu back-endovému serveru v závislosti na počtu čekajících požadavků a maxConcurrentRequestsPerConnection.

  • inflightRequests Počet čekajících požadavků na back-endový server (možná z různých oddílů). Vysoké číslo může vést k většímu provozu a vyšší latenci.
  • openConnections je celkový počet připojení otevřených k jednomu back-endovému serveru. To může být užitečné k zobrazení vyčerpání portů SNAT, pokud je toto číslo velmi vysoké.

ConnectionStatistics

Informace o konkrétním připojení (novém nebo starém) požadavku, ke kterému se přiřadí.

  • waitforConnectionInit: Aktuální požadavek čekal na dokončení inicializace nového připojení. To povede k vyšší latenci.
  • callsPendingReceive: Počet volání čekajících na přijetí před odesláním tohoto hovoru. Vysoké číslo nám může ukázat, že před tímto voláním bylo mnoho volání, což může vést k vyšší latenci. Pokud je toto číslo vysoké, odkazuje na problém blokující vedoucí řádek, který může způsobit jiný požadavek, jako je operace dotazu nebo informačního kanálu, která trvá dlouhou dobu zpracování. Zkuste snížit počet kanálů CosmosClientOptions.MaxRequestsPerTcpConnection.
  • LastSentTime: Čas posledního požadavku odeslaného na tento server. To spolu s lastReceivedTime se dá použít k zobrazení problémů s připojením nebo koncovým bodem. Pokud například existuje mnoho časových limitů příjmu, doba odeslání bude mnohem větší než doba přijetí.
  • lastReceive: Čas posledního požadavku přijatého z tohoto serveru
  • lastSendAttempt: Čas posledního pokusu o odeslání

Velikosti požadavků a odpovědí

  • requestSizeInBytes: Celková velikost požadavku odeslaného do služby Azure Cosmos DB
  • responseMetadataSizeInBytes: Velikost hlaviček vrácených ze služby Azure Cosmos DB
  • responseBodySizeInBytes: Velikost obsahu vráceného ze služby Azure Cosmos DB
"StoreResult": {
    "ActivityId": "bab6ade1-b8de-407f-b89d-fa2138a91284",
    "StatusCode": "Ok",
    "SubStatusCode": "Unknown",
    "LSN": 453362,
    "PartitionKeyRangeId": "1",
    "GlobalCommittedLSN": 0,
    "ItemLSN": 453358,
    "UsingLocalLSN": true,
    "QuorumAckedLSN": -1,
    "SessionToken": "-1#453362",
    "CurrentWriteQuorum": -1,
    "CurrentReplicaSetSize": -1,
    "NumberOfReadRegions": 0,
    "IsValid": true,
    "StorePhysicalAddress": "rntbd://127.0.0.1:10253/apps/DocDbApp/services/DocDbServer92/partitions/a4cb49a8-38c8-11e6-8106-8cdcd42c33be/replicas/1s/",
    "RequestCharge": 1,
    "RetryAfterInMs": null,
    "BELatencyInMs": "0.304",
    "transportRequestTimeline": {
        "requestTimeline": [
            {
                "event": "Created",
                "startTimeUtc": "2022-05-25T12:03:36.3081190Z",
                "durationInMs": 0.0024
            },
            {
                "event": "ChannelAcquisitionStarted",
                "startTimeUtc": "2022-05-25T12:03:36.3081214Z",
                "durationInMs": 0.0132
            },
            {
                "event": "Pipelined",
                "startTimeUtc": "2022-05-25T12:03:36.3081346Z",
                "durationInMs": 0.0865
            },
            {
                "event": "Transit Time",
                "startTimeUtc": "2022-05-25T12:03:36.3082211Z",
                "durationInMs": 1.3324
            },
            {
                "event": "Received",
                "startTimeUtc": "2022-05-25T12:03:36.3095535Z",
                "durationInMs": 12.6128
            },
            {
                "event": "Completed",
                "startTimeUtc": "2022-05-25T12:03:36.8621663Z",
                "durationInMs": 0
            }
        ],
        "serviceEndpointStats": {
            "inflightRequests": 1,
            "openConnections": 1
        },
        "connectionStats": {
            "waitforConnectionInit": "False",
            "callsPendingReceive": 0,
            "lastSendAttempt": "2022-05-25T12:03:34.0222760Z",
            "lastSend": "2022-05-25T12:03:34.0223280Z",
            "lastReceive": "2022-05-25T12:03:34.0257728Z"
        },
        "requestSizeInBytes": 447,
        "responseMetadataSizeInBytes": 438,
        "responseBodySizeInBytes": 604
    },
    "TransportException": null
}

Míra selhání porušuje smlouvu SLA služby Azure Cosmos DB

Kontaktní podpora Azure.

Další kroky