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

PLATÍ PRO: NoSQL

Ve službě Azure Cosmos DB si můžete všimnout pomalých požadavků. Ke zpožděním může docházet 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ů

Nejčastější příčinou pomalých požadavků je omezování 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 frekvencí požadavků vysvětluje, jak zkontrolovat, jestli nejsou požadavky omezené. Článek také popisuje, jak škálovat účet, abyste se těmto problémům v budoucnu vyhnuli.

Návrh aplikací

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

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

Operace s metadaty

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

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

Hromadný režim je režim optimalizovaný pro propustnost určený pro operace s velkým objemem dat, nikoli pro režim optimalizovaný pro latenci. má za cíl nasytit dostupnou propustnost. Pokud při používání hromadného režimu dochází k pomalým požadavkům, ujistěte se, že:

  • Vaše aplikace se zkompiluje v konfiguraci vydané verze.
  • Při ladění aplikace neměříte latenci (nejsou připojené žá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 hromadně by bylo využít 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).
  • Tento vzor 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 s každou verzí mění, 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í. Neanalyzujte řetězec, abyste se vyhnuli změnám způsobujícím chybu. 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 u každé verze sady SDK. Díky tomu je analýza nebezpečná. 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

Vysoké využití procesoru je nejčastější příčinou pomalých požadavků. 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ů mezi oddíly, kdy požadavky můžou pro jeden dotaz provádět více připojení.

K vypršení časových limitů patří diagnostika, která obsahuje například 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 vyšší než 70 procent, bude vypršení časového limitu pravděpodobně způsobeno 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 vyhladovění vláken. V tomto případě je řešením prozkoumat zdroj nebo zdroje hladovění vláken (potenciálně uzamčená vlákna) nebo škálovat počítač nebo počítače na větší velikost prostředků.
  • 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ý úkol, který je ve fondu vláken ve frontě každých 10 sekund. Pokud je doba mezi měřeními delší, znamená to, že asynchronní úlohy není možné zpracovat včas. Nejběžnějším scénářem je, když 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

HttpResponseStats jsou požadavky, které přijdou 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ů nezísleduje 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 požadavků Scénář Popis
Single to all Vypršení časového limitu žádosti nebo HttpRequestExceptions Odkazuje na vyčerpání portů SNAT nebo nedostatek prostředků na počítači pro zpracování požadavku včas.
Jedno nebo malé procento (smlouva SLA není porušena) Vše Jedno nebo malé procento pomalých požadavků může být způsobeno několika různými přechodnými problémy, které by se měly očekávat.
Vše Vše Odkazuje na problém s infrastrukturou nebo sítí.
Porušená smlouva SLA Nedošlo k žádným změnám aplikace a došlo k ukončení smlouvy SLA. 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 požadavků Scénář Popis
Jednoduché 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čas.
Jedno nebo malé procento (smlouva SLA není porušena) Vše Jedno nebo malé procento pomalých požadavků může být způsobeno několika různými přechodnými problémy, které byste měli očekávat.
Vše Vše Problém s infrastrukturou nebo sítí.
Porušení smlouvy SLA Požadavky obsahují několik kódů chyb selhání, například 410 Odkazuje na problém se službou Azure Cosmos DB nebo klientským počítačem.
Porušení smlouvy SLA StorePhysicalAddress jsou stejné, bez stavového kódu selhání. Pravděpodobně došlo k problému se službou Azure Cosmos DB.
Porušení smlouvy SLA StorePhysicalAddress mají stejné ID oddílu, ale různá ID replik bez žádného stavového kódu selhání. Pravděpodobně došlo k problému se službou Azure Cosmos DB.
Porušení smlouvy SLA StorePhysicalAddress je náhodný a neobsahuje stavový kód selhání. Odkazuje na problém s počítačem.

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

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

Časová požadovaná doba

Zobrazení času pro různé fáze odeslání a přijetí požadavku 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 ukončeno z důvodu nečinnosti při používání služby CosmosClientOptions.IdleTcpConnectionTimeout, objem souběžných požadavků překračuje hodnotu CosmosClientOptions.MaxRequestsPerTcpConnection, připojení se ukončilo kvůli chybě sítě nebo aplikace nedodržuje vzor Singleton a neustále se vytvářejí nové instance. 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 nedojde k výše uvedeným problémům.
  • Pipelined příčinou velkého času může být velký požadavek.
  • Transit time je velký, což vede k problému se sítí. Porovnejte toto číslo s BELatencyInMs. Pokud BELatencyInMs je malý, pak se čas strávil v síti, a ne ve službě Azure Cosmos DB.
  • Received Čas je velký může být způsoben problémem s hladověním vlákna. Toto je doba mezi získáním odpovědi 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 parametru 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), ke kterému se žádost 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 proběhlo mnoho volání, což může vést k vyšší latenci. Pokud je toto číslo vysoké, odkazuje to na problém s blokováním hlavního řádku, který může být způsobený jiným požadavkem, jako je dotaz nebo operace informačního kanálu, která trvá dlouhou dobu. Zkuste snížit hodnotu CosmosClientOptions.MaxRequestsPerTcpConnection, abyste zvýšili počet kanálů.
  • LastSentTime: Čas posledního požadavku odeslaného na tento server. Toto spolu s LastReceivedTime můžete použít k zobrazení problémů s připojením nebo koncovým bodem. Pokud například dojde k mnoha vypršením časového limitu příjmu, bude čas odeslání mnohem větší než čas 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 službou 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

Kontaktujte podpora Azure.

Další kroky