Prestandatips för Azure Cosmos DB och .NET SDK v2
GÄLLER FÖR: NoSQL
Azure Cosmos DB är en snabb och flexibel distribuerad databas som skalas sömlöst med garanterad svarstid och dataflöde. 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 hur du etablerar containerdataflöde eller hur du etablerar databasdataflöde. Men eftersom Azure Cosmos DB nås via nätverksanrop finns det optimeringar på klientsidan som du kan göra 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 följande alternativ:
Uppgradera till .NET V3 SDK
.NET v3 SDK släpps. Om du använder .NET v3 SDK läser du prestandaguiden för .NET v3 för följande information:
- Standardvärdet för TCP-direktläge
- Stöd för Stream API
- Stöd för anpassad serialiserare för att tillåta System.Text.JSON användning
- Integrerat batch- och massstöd
Värdrekommendationer
Aktivera skräpinsamling på serversidan (GC)
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 (mer än 50 000 RU/s) kan klientprogrammet bli flaskhalsen på grund av att datorn överskrider 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 samling 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 2.16.2) 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.Documents.DefaultTrace,Microsoft.Azure.DocumentDB.Core");
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 V2 SDK är gateway. Du konfigurerar anslutningsläget under instansens DocumentClient
konstruktion med hjälp av parametern ConnectionPolicy
. Om du använder direktläge måste du också ange Protocol
med hjälp av parametern ConnectionPolicy
. Mer information om olika anslutningsalternativ finns i artikeln om anslutningslägen .
Uri serviceEndpoint = new Uri("https://contoso.documents.net");
string authKey = "your authKey from the Azure portal";
DocumentClient client = new DocumentClient(serviceEndpoint, authKey,
new ConnectionPolicy
{
ConnectionMode = ConnectionMode.Direct, // ConnectionMode.Gateway is the default
ConnectionProtocol = Protocol.Tcp
});
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 i stället för HTTPS-protokollet, som avslutar anslutningarna efter 2 minuters inaktivitet.
I scenarier där du har gles åtkomst och om du ser ett högre antal anslutningar jämfört med åtkomsten till gatewayläge kan du:
- Konfigurera egenskapen ConnectionPolicy.PortReuseMode till
PrivatePortPool
(gäller med framework-versionen>= 4.6.1 och .NET Core version >= 2.0): Med den här egenskapen kan SDK använda en liten pool med tillfälliga portar för olika Azure Cosmos DB-målslutpunkter. - Konfigurera egenskapen ConnectionPolicy.IdleConnectionTimeout måste vara större än eller lika med 10 minuter. De rekommenderade värdena är mellan 20 minuter och 24 timmar.
Anropa OpenAsync för att undvika startfördröjning vid första begäran
Som standard har den första begäran högre svarstid eftersom den måste hämta adressroutningstabellen. När du använder SDK V2 anropar OpenAsync()
du en gång under initieringen för att undvika den här startfördröjningen för den första begäran. Samtalet ser ut så här: await client.OpenAsync();
Kommentar
OpenAsync
genererar begäranden om att hämta adressroutningstabellen för alla containrar i kontot. För konton som har många containrar men vars program kommer åt en delmängd av dem skulle OpenAsync
det generera en onödig mängd trafik, vilket skulle göra initieringen långsam. Därför kanske det inte är användbart att använda OpenAsync
i det här scenariot eftersom det gör programstarten långsammare.
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 slutförs inom 1 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 i samma Azure-region som den etablerade Azure Cosmos DB-slutpunkten. En lista över tillgängliga regioner finns i Azure-regioner.
Eftersom anrop till Azure Cosmos DB görs via nätverket kan du behöva variera graden av parallellitet mellan 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 rekommenderar vi att du aktiverar accelererat nätverk på virtuella klientdatorer. Se Skapa en virtuell Windows-dator med accelererat nätverk eller Skapa en virtuell Linux-dator med accelererat nätverk.
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. Se Azure Cosmos DB SDK-sidorna för att fastställa de senaste SDK:erna och granska förbättringar.
Använda en Singleton Azure Cosmos DB-klient under programmets livslängd
Varje DocumentClient
instans är trådsäker och utför effektiv anslutningshantering och adresscachelagring vid drift 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.
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 ToList()
DocumentClient.CreateDocumentQuery(...)
där blockeringsanrop används för att synkront tömma frågan. Använd AsDocumentQuery() 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.
Ö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 utsätts för standardanslutningsgränsen per värdnamn eller IP-adress. Du kan behöva ange MaxConnections
ett högre värde (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 till ett högre värde.
Implementera backoff vid återförsökEfter intervall
Under prestandatestningen bör du öka belastningen tills en liten mängd begäranden begränsas. Om begäranden begränsas bör klientprogrammet säkerhetskopiera vid begränsning för det serverspecifika återförsöksintervallet. Om du respekterar backoffen kan du tillbringa en minimal tid på att vänta mellan återförsöken.
Stöd för återförsöksprinciper ingår i dessa SDK:er:
- Version 1.8.0 och senare av .NET SDK för SQL och Java SDK för SQL
- Version 1.9.0 och senare av Node.js SDK för SQL och Python SDK för SQL
- Alla versioner av .NET Core SDK:er som stöds
Mer information finns i RetryAfter.
I version 1.19 och senare av .NET SDK finns det en mekanism för att logga ytterligare diagnostikinformation och felsöka svarstidsproblem, som du ser i följande exempel. Du kan logga diagnostiksträngen för begäranden som har en högre läsfördröjning. Den insamlade diagnostiksträngen hjälper dig att förstå hur många gånger du har fått 429 fel för en viss begäran.
ResourceResponse<Document> readDocument = await this.readClient.ReadDocumentAsync(oldDocuments[i].SelfLink);
readDocument.RequestDiagnosticsString
Cachelagrade dokument-URI:er för kortare svarstid för läsning
Cachelagra dokument-URI:er när det är möjligt för bästa läsprestanda. Du måste definiera logik för att cachelagra resurs-ID:t när du skapar en resurs. Sökningar baserade på resurs-ID:t är snabbare än namnbaserade sökningar, så cachelagring av dessa värden förbättrar prestandan.
Öka antalet trådar/uppgifter
Se Öka antalet trådar/uppgifter i nätverksavsnittet 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 i eller undantas från indexering med hjälp av indexeringssökvägar (IndexingPolicy.IncludedPaths och IndexingPolicy.ExcludedPaths). Indexeringssökvägar kan förbättra skrivprestanda 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. Den här koden visar till exempel hur du exkluderar ett helt avsnitt av dokumenten (ett underträd) från indexering med hjälp av jokertecknet "*":
var collection = new DocumentCollection { Id = "excludedPathCollection" };
collection.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" });
collection.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/nonIndexedContent/*");
collection = await client.CreateDocumentCollectionAsync(UriFactory.CreateDatabaseUri("db"), collection);
Mer information finns i Azure Cosmos DB-indexeringsprinciper.
Genomflöde
Mät och justera för lägre användning av enheter för begäranden/sekund
Azure Cosmos DB erbjuder en omfattande uppsättning databasåtgärder. Dessa åtgärder omfattar relations- och hierarkiska frågor med UDF:er, lagrade procedurer och utlösare, som alla körs på dokumenten i en databassamling. Kostnaden 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. Istället för att tänka på och hantera maskinvaruresurser kan du tänka på en begäransenhet som det enda måttet på de resurser som krävs för att utföra olika databasoperationer och göra en programbegäran.
Dataflödet etableras baserat på antalet enheter för programbegäran som angetts för varje container. Förbrukning av begärandeenhet utvärderas som en hastighet per sekund. 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:er 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
ResourceResponse<Document> response = await client.CreateDocumentAsync(collectionSelfLink, myDocument);
Console.WriteLine("Insert of document consumed {0} request units", response.RequestCharge);
// Measure the performance (Request Units) of queries
IDocumentQuery<dynamic> queryable = client.CreateDocumentQuery(collectionSelfLink, queryString).AsDocumentQuery();
while (queryable.HasMoreResults)
{
FeedResponse<dynamic> queryResponse = await queryable.ExecuteNextAsync<dynamic>();
Console.WriteLine("Query batch consumed {0} request units", queryResponse.RequestCharge);
}
Den begärandeavgift som returneras i den här rubriken är en bråkdel av ditt etablerade dataflöde (det vill: 2 000 RU:er/sekund). 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 hedrar servern bara två sådana begäranden innan hastighetsbegränsningen för 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 kanske standardantalet för återförsök som för närvarande är inställt på 9 internt av klienten kanske inte räcker. I det här fallet genererar klienten en DocumentClientException med statuskod 429 till programmet.
Du kan ändra standardantalet för återförsök genom att RetryOptions
ange på instansen ConnectionPolicy
. Som standard returneras DocumentClientException 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 returnerar även när 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 viss å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.