Prestandatips för Azure Cosmos DB och .NET

GÄLLER FÖR: NoSQL

Azure Cosmos DB är en snabb, flexibel distribuerad databas som skalar sömlöst med garanterad svarstid och dataflödesnivåer. Du behöver inte göra större arkitekturändringar eller skriva komplex kod för att skala databasen med Azure Cosmos DB. Det är lika enkelt att skala upp och ned som att göra ett enda API-anrop. Mer information finns i etablera containerdataflöde eller etablera databasdataflöde.

Eftersom Azure Cosmos DB nås via nätverksanrop kan du göra optimeringar på klientsidan för att uppnå högsta prestanda när du använder SQL .NET SDK.

Om du försöker förbättra databasens prestanda bör du överväga de alternativ som visas i följande avsnitt.

Värdrekommendationer

Aktivera skräpinsamling på serversidan

Att minska frekvensen för skräpinsamling kan i vissa fall vara till hjälp. I .NET anger du gcServer till true.

Skala ut klientarbetsbelastningen

Om du testar på höga dataflödesnivåer, eller med priser som är större än 50 000 enheter för begäranden per sekund (RU/s), kan klientprogrammet bli en flaskhals för arbetsbelastningen. Det beror på att datorn kan begränsa processor- eller nätverksanvändningen. Om du når den här punkten kan du fortsätta att push-överföra Azure Cosmos DB-kontot ytterligare genom att skala ut dina klientprogram över flera servrar.

Kommentar

Hög CPU-användning kan orsaka ökad svarstid och timeout-undantag för begäranden.

Metadataåtgärder

Kontrollera inte att en databas och/eller container finns genom att anropa Create...IfNotExistsAsync och/eller Read...Async i den heta sökvägen och/eller innan du utför en objektåtgärd. Valideringen bör endast utföras vid programstart när det är nödvändigt, om du förväntar dig att de ska tas bort (annars behövs det inte). Dessa metadataåtgärder genererar extra svarstid från slutpunkt till slutpunkt, har inget serviceavtal och egna separata begränsningar som inte skalas som dataåtgärder.

Loggning och spårning

I vissa miljöer är .NET DefaultTraceListener aktiverat. DefaultTraceListener medför prestandaproblem i produktionsmiljöer som orsakar höga cpu- och I/O-flaskhalsar. Kontrollera och kontrollera att DefaultTraceListener är inaktiverat för ditt program genom att ta bort det från TraceListeners i produktionsmiljöer.

De senaste SDK-versionerna (större än 3.23.0) tar automatiskt bort det när de identifierar det, med äldre versioner kan du ta bort det genom att:

if (!Debugger.IsAttached)
{
    Type defaultTrace = Type.GetType("Microsoft.Azure.Cosmos.Core.Trace.DefaultTrace,Microsoft.Azure.Cosmos.Direct");
    TraceSource traceSource = (TraceSource)defaultTrace.GetProperty("TraceSource").GetValue(null);
    traceSource.Listeners.Remove("Default");
    // Add your own trace listeners
}

Nätverk

Anslutningsprincip: Använd direktanslutningsläge

Standardanslutningsläget för .NET V3 SDK är direkt med TCP-protokollet. Du konfigurerar anslutningsläget när du skapar instansen CosmosClient i CosmosClientOptions. Mer information om olika anslutningsalternativ finns i artikeln om anslutningslägen .

CosmosClient client = new CosmosClient(
  "<nosql-account-endpoint>",
  tokenCredential
  new CosmosClientOptions
  {
      ConnectionMode = ConnectionMode.Gateway // ConnectionMode.Direct is the default
  }
);

Tillfällig portöverbelastning

Om du ser en hög anslutningsvolym eller hög portanvändning på dina instanser kontrollerar du först att klientinstanserna är singletons. Med andra ord bör klientinstanserna vara unika för programmets livslängd.

När den körs i TCP-protokollet optimeras klienten för svarstid med hjälp av de långvariga anslutningarna. Detta står i kontrast till HTTPS-protokollet, som avslutar anslutningarna efter två minuters inaktivitet.

I scenarier där du har gles åtkomst, och om du ser ett högre antal anslutningar jämfört med åtkomst i gatewayläge, kan du:

För prestanda kan du samla klienter i samma Azure-region

När det är möjligt placerar du alla program som anropar Azure Cosmos DB i samma region som Azure Cosmos DB-databasen. Här är en ungefärlig jämförelse: anrop till Azure Cosmos DB inom samma region avslutas inom 1 millisekunder (ms) till 2 ms, men svarstiden mellan USA:s västra och östra kust är mer än 50 ms. Den här svarstiden kan variera från begäran till begäran, beroende på vilken väg begäran tar när den skickas från klienten till Azures datacentergräns.

Du kan få lägsta möjliga svarstid genom att se till att det anropande programmet finns inom samma Azure-region som den etablerade Azure Cosmos DB-slutpunkten. En lista över tillgängliga regioner finns i Azure-regioner.

Samordna klienter i samma region.

Öka antalet trådar/uppgifter

Eftersom anrop till Azure Cosmos DB görs via nätverket kan du behöva variera graden av samtidighet för dina begäranden så att klientprogrammet ägnar minimal tid åt att vänta mellan begäranden. Om du till exempel använder .NET-aktivitetsparallellt bibliotek skapar du i ordningen hundratals aktiviteter som läser från eller skriver till Azure Cosmos DB.

Aktivera accelererat nätverk för att minska svarstiden och CPU-jitter

Vi rekommenderar att du följer anvisningarna för att aktivera accelererat nätverk i windows (klicka för instruktioner) eller Linux (klicka för instruktioner) på den virtuella Azure-datorn för att maximera prestandan.

Utan accelererat nätverk kan I/O som överförs mellan din virtuella Azure-dator och andra Azure-resurser i onödan dirigeras via en värd och en virtuell växel mellan den virtuella datorn och dess nätverkskort. Att ha värden och den virtuella växeln infogade i datasökvägen ökar inte bara svarstiden och jitter i kommunikationskanalen, utan stjäl även CPU-cykler från den virtuella datorn. Med accelererat nätverk gränssnittar den virtuella datorn direkt med nätverkskortet utan mellanhänder. All information om nätverksprinciper som hanterades av värden och den virtuella växeln hanteras nu i maskinvaran på nätverkskortet. värden och den virtuella växeln kringgås. Vanligtvis kan du förvänta dig lägre svarstid och högre dataflöde, samt mer konsekvent svarstid och minskad CPU-användning när du aktiverar accelererat nätverk.

Begränsningar: Accelererat nätverk måste stödjas på det virtuella datoroperativsystemet och kan bara aktiveras när den virtuella datorn stoppas och frigörs. Det går inte att distribuera den virtuella datorn med Azure Resource Manager. App Service har inget accelererat nätverk aktiverat.

Mer information finns i Windows- och Linux-instruktionerna.

SDK-användning

Installera den senaste SDK:en

Azure Cosmos DB SDK:er förbättras ständigt för att ge bästa möjliga prestanda. Information om de senaste SDK:erna och granska förbättringar finns i Azure Cosmos DB SDK.

Använda stream-API:er

.NET SDK V3 innehåller stream-API:er som kan ta emot och returnera data utan serialisering.

Mellannivåprogram som inte använder svar direkt från SDK men vidarebefordrar dem till andra programnivåer kan dra nytta av stream-API:erna. Exempel på dataströmhantering finns i exempel på objekthantering .

Använda en Singleton Azure Cosmos DB-klient under programmets livslängd

Varje CosmosClient instans är trådsäker och utför effektiv anslutningshantering och adresscachelagring när den körs i direktläge. För att möjliggöra effektiv anslutningshantering och bättre SDK-klientprestanda rekommenderar vi att du använder en enda instans per AppDomain under programmets livslängd för varje konto som ditt program interagerar med.

Information om program med flera klienter som hanterar flera konton finns i de relaterade metodtipsen.

När du arbetar med Azure Functions bör instanser också följa de befintliga riktlinjerna och underhålla en enda instans.

Undvik blockeringsanrop

Azure Cosmos DB SDK bör utformas för att bearbeta många begäranden samtidigt. Asynkrona API:er gör det möjligt för en liten pool med trådar att hantera tusentals samtidiga begäranden genom att inte vänta på blockeringsanrop. I stället för att vänta på att en långvarig synkron uppgift ska slutföras kan tråden fungera på en annan begäran.

Ett vanligt prestandaproblem i appar som använder Azure Cosmos DB SDK blockerar anrop som kan vara asynkrona. Många synkrona blockeringsanrop leder till utsvulten trådpool och försämrade svarstider.

Gör inte så här:

  • Blockera asynkron körning genom att anropa Task.Wait eller Task.Result.
  • Använd Task.Run för att göra ett synkront API asynkront.
  • Hämta lås i vanliga kodsökvägar. Azure Cosmos DB .NET SDK är mest högpresterande när det är konstruerat för att köra kod parallellt.
  • Anropa Task.Run och vänta omedelbart på det. ASP.NET Core kör redan appkod på vanliga trådpoolstrådar, så att anropa Task.Run resulterar endast i extra onödig schemaläggning av trådpooler. Även om den schemalagda koden skulle blockera en tråd förhindrar Task.Run inte det.
  • Använd inte ToList() Container.GetItemLinqQueryable<T>() där blockeringsanrop används för att tömma frågan synkront. Använd ToFeedIterator() för att tömma frågan asynkront.

Gör:

  • Anropa Azure Cosmos DB .NET API:er asynkront.
  • Hela anropsstacken är asynkron för att dra nytta av asynkrona/väntande mönster.

En profilerare, till exempel PerfView, kan användas för att hitta trådar som ofta läggs till i trådpoolen. Händelsen Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start anger en tråd som lagts till i trådpoolen.

Inaktivera innehållssvar vid skrivåtgärder

För arbetsbelastningar som har tunga nyttolaster anger du EnableContentResponseOnWrite alternativet för begäran till false. Tjänsten returnerar inte längre den skapade eller uppdaterade resursen till SDK:n. Eftersom programmet har objektet som skapas behöver det normalt inte tjänsten för att returnera det. Huvudvärdena är fortfarande tillgängliga, till exempel en begärandeavgift. Om du inaktiverar innehållssvaret kan du förbättra prestandan eftersom SDK:n inte längre behöver allokera minne eller serialisera svarets brödtext. Det minskar också användningen av nätverksbandbredd för att ytterligare hjälpa prestanda.

ItemRequestOptions requestOptions = new ItemRequestOptions() { EnableContentResponseOnWrite = false };
ItemResponse<Book> itemResponse = await this.container.CreateItemAsync<Book>(book, new PartitionKey(book.pk), requestOptions);
// Resource will be null
itemResponse.Resource

Aktivera massoptimera för dataflöde i stället för svarstid

Aktivera Mass för scenarier där arbetsbelastningen kräver en stor mängd dataflöde, och svarstiden är inte lika viktig. Mer information om hur du aktiverar massfunktionen och vilka scenarier den ska användas för finns i Introduktion till masssupport.

Öka System.Net MaxConnections per värd när du använder gatewayläge

Azure Cosmos DB-begäranden görs via HTTPS/REST när du använder gatewayläge. De omfattas av standardanslutningsgränsen per värdnamn eller IP-adress. Du kan behöva ange MaxConnections ett högre värde (från 100 till 1 000) så att klientbiblioteket kan använda flera samtidiga anslutningar till Azure Cosmos DB. I .NET SDK 1.8.0 och senare är standardvärdet för ServicePointManager.DefaultConnectionLimit 50. Om du vill ändra värdet kan du ange Documents.Client.ConnectionPolicy.MaxConnectionLimit ett högre värde.

Öka antalet trådar/uppgifter

Se Öka antalet trådar/uppgifter i avsnittet Nätverk i den här artikeln.

Frågeåtgärder

Information om frågeåtgärder finns i prestandatipsen för frågor.

Indexeringsprincip

Utesluta sökvägar som inte används från indexering för att få snabbare skrivning

Med Azure Cosmos DB-indexeringsprincipen kan du också ange vilka dokumentsökvägar som ska inkluderas eller undantas från indexering med hjälp av indexeringssökvägar (IndexingPolicy.IncludedPaths och IndexingPolicy.ExcludedPaths).

Indexering av endast de sökvägar du behöver kan förbättra skrivprestanda, minska RU-avgifter för skrivåtgärder och minska indexlagringen för scenarier där frågemönstren är kända i förväg. Det beror på att indexeringskostnaderna korrelerar direkt med antalet indexerade unika sökvägar. Följande kod visar till exempel hur du undantar ett helt avsnitt av dokumenten (ett underträd) från indexering med hjälp av jokertecknet "*":

var containerProperties = new ContainerProperties(id: "excludedPathCollection", partitionKeyPath: "/pk" );
containerProperties.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" });
containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/nonIndexedContent/*");
Container container = await this.cosmosDatabase.CreateContainerAsync(containerProperties);

Mer information finns i Azure Cosmos DB-indexeringsprinciper.

Genomflöde

Mät och justera för lägre RU/s-användning

Azure Cosmos DB erbjuder en omfattande uppsättning databasåtgärder. Dessa åtgärder omfattar relations- och hierarkiska frågor med UDF-filer (Universal Disk Format), lagrade procedurer och utlösare, som alla körs på dokumenten i en databassamling.

Kostnaderna för var och en av dessa åtgärder varierar beroende på processor, I/O och minne som krävs för att slutföra åtgärden. I stället för att tänka på och hantera maskinvaruresurser kan du betrakta en enhet för begäran som ett enda mått för de resurser som krävs för att utföra olika databasåtgärder och hantera en programbegäran.

Dataflödet etableras baserat på antalet enheter för programbegäran som angetts för varje container. Enhetsförbrukning för begäran utvärderas som en enhet per sekund-hastighet. Program som överskrider den etablerade enheten för begäranden för sin container begränsas tills priset sjunker under den etablerade nivån för containern. Om ditt program kräver en högre dataflödesnivå kan du öka dataflödet genom att etablera ytterligare enheter för programbegäran.

En frågas komplexitet påverkar hur många enheter för programbegäran som används för en åtgärd. Antalet predikat, predikatens natur, antalet UDF-filer och storleken på källdatauppsättningen påverkar alla kostnaden för frågeåtgärder.

Om du vill mäta omkostnaderna för en åtgärd (skapa, uppdatera eller ta bort) kontrollerar du rubriken x-ms-request-charge (eller motsvarande RequestCharge egenskap i ResourceResponse<T> eller FeedResponse<T> i .NET SDK) för att mäta antalet enheter för begäranden som förbrukas av åtgärderna:

// Measure the performance (Request Units) of writes
ItemResponse<Book> response = await container.CreateItemAsync<Book>(myBook, new PartitionKey(myBook.PkValue));
Console.WriteLine("Insert of item consumed {0} request units", response.RequestCharge);
// Measure the performance (Request Units) of queries
FeedIterator<Book> queryable = container.GetItemQueryIterator<ToDoActivity>(queryString);
while (queryable.HasMoreResults)
    {
        FeedResponse<Book> queryResponse = await queryable.ExecuteNextAsync<Book>();
        Console.WriteLine("Query batch consumed {0} request units", queryResponse.RequestCharge);
    }

Den avgift för begäran som returneras i det här huvudet är en bråkdel av ditt etablerade dataflöde (det vill: 2 000 RU/s). Om den föregående frågan till exempel returnerar 1 000 1 KB-dokument är kostnaden för åtgärden 1 000. Så inom en sekund respekterar servern bara två sådana begäranden innan den hastighetsbegränsar senare begäranden. Mer information finns i Enheter för begäran och kalkylatorn för begärandeenheten.

Hantera hastighetsbegränsning/begärandefrekvens för stor

När en klient försöker överskrida det reserverade dataflödet för ett konto sker ingen prestandaförsämring på servern och ingen användning av dataflödeskapacitet utöver den reserverade nivån. Servern avslutar begäran i förebyggande syfte med RequestRateTooLarge (HTTP-statuskod 429). Den returnerar ett x-ms-retry-after-ms-huvud som anger hur lång tid, i millisekunder, som användaren måste vänta innan begäran görs igen.

    HTTP Status 429,
    Status Line: RequestRateTooLarge
    x-ms-retry-after-ms :100

SDK:erna fångar alla implicit det här svaret, respekterar det server-angivna återförsökshuvudet och försöker begära igen. Om inte ditt konto används samtidigt av flera klienter kommer nästa återförsök att lyckas.

Om du har fler än en klient som kumulativt fungerar konsekvent över begärandefrekvensen räcker det kanske inte med det standardantal för återförsök som för närvarande är inställt på 9 internt av klienten. I det här fallet genererar klienten en CosmosException med statuskod 429 till programmet.

Du kan ändra standardantalet för återförsök genom att RetryOptions ange på instansen CosmosClientOptions . Som standard returneras CosmosException med statuskod 429 efter en kumulativ väntetid på 30 sekunder om begäran fortsätter att fungera över begärandefrekvensen. Det här felet returneras även om det aktuella antalet återförsök är mindre än det maximala antalet återförsök, oavsett om det aktuella värdet är standardvärdet 9 eller ett användardefinierat värde.

Det automatiserade återförsöksbeteendet hjälper till att förbättra återhämtning och användbarhet för de flesta program. Men det kanske inte är det bästa beteendet när du utför prestandamått, särskilt när du mäter svarstiden. Den klient observerade svarstiden ökar om experimentet når serverbegränsningen och gör att klient-SDK:t tyst försöker igen. För att undvika svarstidstoppar under prestandaexperiment mäter du den avgift som returneras av varje åtgärd och ser till att begäranden fungerar under den reserverade begärandefrekvensen.

Mer information finns i Enheter för begäran.

Design för mindre dokument för högre dataflöde

Begärandeavgiften (dvs. kostnaden för bearbetning av begäran) för en angiven åtgärd korrelerar direkt med dokumentets storlek. Åtgärder på stora dokument kostar mer än åtgärder för små dokument.

Nästa steg

Ett exempelprogram som används för att utvärdera Azure Cosmos DB för scenarier med höga prestanda på några klientdatorer finns i Prestanda- och skalningstestning med Azure Cosmos DB.

Mer information om hur du utformar ditt program för skalning och höga prestanda finns i Partitionering och skalning i Azure Cosmos DB.