Prestandatips för Azure Cosmos DB Async Java SDK v2
GÄLLER FÖR: NoSQL
Viktigt!
Det här är inte den senaste Java SDK:t för Azure Cosmos DB! Du bör uppgradera projektet till Azure Cosmos DB Java SDK v4 och sedan läsa prestandatipsguiden för Azure Cosmos DB Java SDK v4. Följ anvisningarna i guiden Migrera till Azure Cosmos DB Java SDK v4 och Guiden Reactor vs RxJava för uppgradering.
Prestandatipsen i den här artikeln gäller endast för Azure Cosmos DB Async Java SDK v2. Mer information finns i Felsökningsguiden för Azure Cosmos DB Async Java SDK v2, Maven-lagringsplatsen och Azure Cosmos DB Async Java SDK v2.
Viktigt!
Den 31 augusti 2024 dras Azure Cosmos DB Async Java SDK v2.x tillbaka. SDK och alla program som använder SDK fortsätter att fungera. Azure Cosmos DB upphör helt enkelt att tillhandahålla ytterligare underhåll och support för denna SDK. Vi rekommenderar att du följer anvisningarna ovan för att migrera till Azure Cosmos DB Java SDK v4.
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 eller ett SDK-metodanrop. 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 Azure Cosmos DB Async Java SDK v2.
Så om du frågar "Hur kan jag förbättra mina databasprestanda?" bör du överväga följande alternativ:
Nätverk
Anslutningsläge: Använd direktläge
Hur en klient ansluter till Azure Cosmos DB har viktiga konsekvenser för prestanda, särskilt när det gäller svarstid på klientsidan. ConnectionMode är en nyckelkonfigurationsinställning som är tillgänglig för att konfigurera klienten ConnectionPolicy. För Azure Cosmos DB Async Java SDK v2 är de två tillgängliga ConnectionModes:
Gatewayläge stöds på alla SDK-plattformar och det är det konfigurerade alternativet som standard. Om dina program körs i ett företagsnätverk med strikta brandväggsbegränsningar är gatewayläget det bästa valet eftersom det använder https-standardporten och en enda slutpunkt. Prestandaavvägningen är dock att Gateway-läget innebär ytterligare ett nätverkshopp varje gång data läse eller skrivs till Azure Azure Cosmos DB. På grund av detta ger direktläget bättre prestanda på grund av färre nätverkshopp.
ConnectionMode konfigureras under konstruktionen av DocumentClient-instansen med parametern ConnectionPolicy.
Async Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)
public ConnectionPolicy getConnectionPolicy() {
ConnectionPolicy policy = new ConnectionPolicy();
policy.setConnectionMode(ConnectionMode.Direct);
policy.setMaxPoolSize(1000);
return policy;
}
ConnectionPolicy connectionPolicy = new ConnectionPolicy();
DocumentClient client = new DocumentClient(HOST, MASTER_KEY, connectionPolicy, null);
Samla klienter i samma Azure-region för prestanda
När det är möjligt placerar du alla program som anropar Azure Cosmos DB i samma region som Azure Cosmos DB-databasen. För en ungefärlig jämförelse slutförs anrop till Azure Cosmos DB inom samma region inom 1–2 ms, men svarstiden mellan USA:s västra och östra kust är >50 ms. Den här svarstiden kan sannolikt variera från begäran till begäran beroende på vilken väg begäran tar när den skickas från klienten till Gränsen för Azure-datacenter. Den lägsta möjliga svarstiden uppnås genom att säkerställa 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.
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 sidorna Azure Cosmos DB Async Java SDK v2 Viktig information 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 AsyncDocumentClient-instans är trådsäker och utför effektiv anslutningshantering och cachelagring av adresser. För att möjliggöra effektiv anslutningshantering och bättre prestanda av AsyncDocumentClient rekommenderar vi att du använder en enda instans av AsyncDocumentClient per AppDomain under programmets livslängd.
Justera ConnectionPolicy
Som standard görs Azure Cosmos DB-begäranden i direktläge via TCP när du använder Azure Cosmos DB Async Java SDK v2. Internt använder SDK en särskild arkitektur för direktläge för att dynamiskt hantera nätverksresurser och få bästa möjliga prestanda.
I Azure Cosmos DB Async Java SDK v2 är direktläge det bästa valet för att förbättra databasprestandan med de flesta arbetsbelastningar.
- Översikt över direktläge
Arkitekturen på klientsidan som används i direktläge möjliggör förutsägbar nätverksanvändning och multiplexerad åtkomst till Azure Cosmos DB-repliker. Diagrammet ovan visar hur Direktläge dirigerar klientbegäranden till repliker i Azure Cosmos DB-serverdelen. Arkitekturen för direktläge allokerar upp till 10 kanaler på klientsidan per DB-replik. En kanal är en TCP-anslutning som föregås av en begärandebuffert, som är 30 förfrågningar djup. Kanalerna som tillhör en replik allokeras dynamiskt efter behov av replikens tjänstslutpunkt. När användaren utfärdar en begäran i direktläge dirigerar TransportClient begäran till rätt tjänstslutpunkt baserat på partitionsnyckeln. Begärandekön buffrar begäranden före tjänstslutpunkten.
Konfigurationsalternativ för ConnectionPolicy för direktläge
Använd följande rekommenderade konfigurationsinställningar nedan som ett första steg. Kontakta Azure Cosmos DB-teamet om du stöter på problem med det här specifika ämnet.
Om du använder Azure Cosmos DB som referensdatabas (d.v.s. databasen används för många punktläsningsåtgärder och några skrivåtgärder) kan det vara acceptabelt att ange idleEndpointTimeout till 0 (det vill s. v.s. ingen tidsgräns).
Konfigurationsalternativ Standardvärde bufferPageSize 8192 connectionTimeout "PT1M" idleChannelTimeout "PT0S" idleEndpointTimeout "PT1M10S" maxBufferCapacity 8388608 maxChannelsPerEndpoint 10 maxRequestsPerChannel 30 receiveHangDetectionTime "PT1M5S" requestExpiryInterval "PT5S" requestTimeout "PT1M" requestTimerResolution "PT0.5S" sendHangDetectionTime "PT10S" shutdownTimeout "PT15S"
Programmeringstips för direktläge
Läs felsökningsartikeln Azure Cosmos DB Async Java SDK v2 som baslinje för att lösa eventuella SDK-problem.
Några viktiga programmeringstips när du använder direktläge:
Använd multitrådning i ditt program för effektiv TCP-dataöverföring – När du har gjort en begäran bör ditt program prenumerera på att ta emot data i en annan tråd. Detta tvingar inte oavsiktliga "halv duplex"-åtgärder och efterföljande begäranden blockeras i väntan på den tidigare begärans svar.
Utför beräkningsintensiva arbetsbelastningar i en dedikerad tråd – Av liknande skäl som i föregående tips är åtgärder som komplex databehandling bäst placerade i en separat tråd. En begäran som hämtar in data från ett annat datalager (till exempel om tråden använder Azure Cosmos DB- och Spark-datalager samtidigt) kan få ökad svarstid och vi rekommenderar att du skapar ytterligare en tråd som väntar på ett svar från det andra datalagret.
- Den underliggande nätverks-I/O:n i Azure Cosmos DB Async Java SDK v2 hanteras av Netty. Se de här tipsen för att undvika kodningsmönster som blockerar Netty I/O-trådar.
Datamodellering – Azure Cosmos DB SLA förutsätter att dokumentstorleken är mindre än 1 KB. Att optimera datamodellen och programmeringen för att gynna mindre dokumentstorlek leder vanligtvis till minskad svarstid. Om du behöver lagring och hämtning av dokument som är större än 1 KB är den rekommenderade metoden att dokument länkar till data i Azure Blob Storage.
Justera parallella frågor för partitionerade samlingar
Azure Cosmos DB Async Java SDK v2 stöder parallella frågor, vilket gör att du kan köra frågor mot en partitionerad samling parallellt. Mer information finns i kodexempel som rör arbete med SDK:erna. Parallella frågor är utformade för att förbättra frågesvarstiden och dataflödet över deras seriella motsvarighet.
JusteringsuppsättningMaxDegreeOfParallelism:
Parallella frågor fungerar genom att köra frågor mot flera partitioner parallellt. Data från en enskild partitionerad samling hämtas dock seriellt med avseende på frågan. Använd därför setMaxDegreeOfParallelism för att ange antalet partitioner som har maximal chans att uppnå den mest högpresterande frågan, förutsatt att alla andra systemvillkor förblir desamma. Om du inte känner till antalet partitioner kan du använda setMaxDegreeOfParallelism för att ange ett högt tal, och systemet väljer minimum (antal partitioner, användarindata) som maximal grad av parallellitet.
Det är viktigt att observera att parallella frågor ger de bästa fördelarna om data fördelas jämnt över alla partitioner med avseende på frågan. Om den partitionerade samlingen partitioneras på ett sådant sätt att alla eller de flesta data som returneras av en fråga är koncentrerade till några partitioner (en partition i värsta fall), skulle frågans prestanda flaskhalsas av dessa partitioner.
JusteringsuppsättningMaxBufferedItemCount:
Parallell fråga är utformad för att prefetch resultat medan den aktuella batchen med resultat bearbetas av klienten. Prefetching hjälper till med övergripande svarstidsförbättringar för en fråga. setMaxBufferedItemCount begränsar antalet fördefinierade resultat. Genom att ange setMaxBufferedItemCount till det förväntade antalet returnerade resultat (eller ett högre tal) kan frågan få maximal nytta av prefetching.
Prefetching fungerar på samma sätt oavsett MaxDegreeOfParallelism, och det finns en enda buffert för data från alla partitioner.
Implementera backoff vid getRetryAfterInMilliseconds-intervall
Under prestandatestningen bör du öka belastningen tills en liten mängd begäranden begränsas. Om begränsningen är begränsad bör klientprogrammet backa för det serverspecifika återförsöksintervallet. Om du respekterar backoffen ser du till att du ägnar minimal tid åt att vänta mellan återförsöken.
Skala ut din klientarbetsbelastning
Om du testar på höga dataflödesnivåer (>50 000 RU/s) kan klientprogrammet bli flaskhalsen på grund av att datorn begränsar 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.
Använda namnbaserad adressering
Använd namnbaserad adressering, där länkar har formatet
dbs/MyDatabaseId/colls/MyCollectionId/docs/MyDocumentId
, i stället för SelfLinks (_self), som har formatetdbs/<database_rid>/colls/<collection_rid>/docs/<document_rid>
för att undvika att hämta ResourceIds för alla resurser som används för att skapa länken. Eftersom dessa resurser återskapas (eventuellt med samma namn) kanske cachelagringen inte hjälper.Justera sidstorleken för frågor/läsfeeds för bättre prestanda
När du utför en massläsning av dokument med hjälp av läsflödesfunktioner (till exempel readDocuments) eller när du utfärdar en SQL-fråga returneras resultatet på ett segmenterat sätt om resultatuppsättningen är för stor. Som standard returneras resultaten i segment på 100 objekt eller 1 MB, beroende på vilken gräns som uppnås först.
Om du vill minska antalet nätverksresor som krävs för att hämta alla tillämpliga resultat kan du öka sidstorleken med begäranderubriken x-ms-max-item-count till upp till 1 000. Om du bara behöver visa några få resultat, till exempel om ditt användargränssnitt eller program-API bara returnerar 10 resultat per tid, kan du också minska sidstorleken till 10 för att minska dataflödet som förbrukas för läsningar och frågor.
Du kan också ange sidstorleken med metoden setMaxItemCount.
Använd Lämplig Scheduler (Undvik att stjäla IO Netty-trådar i händelseloopen)
Azure Cosmos DB Async Java SDK v2 använder netty för att inte blockera I/O. SDK:n använder ett fast antal I/O Netty-händelselooptrådar (så många processorkärnor som datorn har) för att köra I/O-åtgärder. Det observerbara som returneras av API:et genererar resultatet på en av de delade I/O-händelseloopens netty-trådar. Därför är det viktigt att du inte blockerar den delade I/O-händelseloopens Netty-trådar. Att utföra processorintensivt arbete eller blockera åtgärder i I/O-händelseloopens nättråd kan orsaka dödläge eller avsevärt minska SDK-dataflödet.
Följande kod kör till exempel ett processorintensivt arbete på händelseloopens I/O netty-tråd:
Async Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)
Observable<ResourceResponse<Document>> createDocObs = asyncDocumentClient.createDocument( collectionLink, document, null, true); createDocObs.subscribe( resourceResponse -> { //this is executed on eventloop IO netty thread. //the eventloop thread is shared and is meant to return back quickly. // // DON'T do this on eventloop IO netty thread. veryCpuIntensiveWork(); });
När resultatet har tagits emot om du vill utföra processorintensivt arbete med resultatet bör du undvika att göra det på händelseloopens I/O netty-tråd. Du kan i stället ange en egen Scheduler för att tillhandahålla en egen tråd för att köra ditt arbete.
Async Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)
import rx.schedulers; Observable<ResourceResponse<Document>> createDocObs = asyncDocumentClient.createDocument( collectionLink, document, null, true); createDocObs.subscribeOn(Schedulers.computation()) subscribe( resourceResponse -> { // this is executed on threads provided by Scheduler.computation() // Schedulers.computation() should be used only when: // 1. The work is cpu intensive // 2. You are not doing blocking IO, thread sleep, etc. in this thread against other resources. veryCpuIntensiveWork(); });
Baserat på typen av arbete bör du använda lämplig befintlig RxJava Scheduler för ditt arbete. Läs här
Schedulers
.Mer information finns på GitHub-sidan för Azure Cosmos DB Async Java SDK v2.
Inaktivera nettys loggning
Netty-biblioteksloggning är pratsam och måste stängas av (det räcker kanske inte att ignorera inloggningen i konfigurationen) för att undvika ytterligare CPU-kostnader. Om du inte är i felsökningsläge inaktiverar du nettys loggning helt och hållet. Så om du använder log4j för att ta bort de ytterligare CPU-kostnader som uppstår från
org.apache.log4j.Category.callAppenders()
netty lägger du till följande rad i din kodbas:org.apache.log4j.Logger.getLogger("io.netty").setLevel(org.apache.log4j.Level.OFF);
Resursgräns för öppna OS-filer
Vissa Linux-system (till exempel Red Hat) har en övre gräns för antalet öppna filer och därmed det totala antalet anslutningar. Kör följande för att visa de aktuella gränserna:
ulimit -a
Antalet öppna filer (nofile) måste vara tillräckligt stort för att ha tillräckligt med utrymme för din konfigurerade storlek på anslutningspoolen och andra öppna filer i operativsystemet. Den kan ändras för att tillåta en större storlek på anslutningspoolen.
Öppna filen limits.conf:
vim /etc/security/limits.conf
Lägg till/ändra följande rader:
* - nofile 100000
Indexeringsprincip
Utesluta sökvägar som inte används från indexering för att få snabbare skrivning
Med Azure Cosmos DB:s indexeringsprincip kan du ange vilka dokumentsökvägar som ska inkluderas eller undantas från indexering med hjälp av Indexeringssökvägar (setIncludedPaths och setExcludedPaths). Användningen av indexeringssökvägar kan ge bättre skrivprestanda och lägre indexlagring för scenarier där frågemönstren är kända i förväg, eftersom indexeringskostnaderna är direkt korrelerade med antalet indexerade unika sökvägar. Följande kod visar till exempel hur du undantar ett helt avsnitt av dokumenten (även kallat ett underträd) från indexering med jokertecknet "*".
Async Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)
Index numberIndex = Index.Range(DataType.Number); numberIndex.set("precision", -1); indexes.add(numberIndex); includedPath.setIndexes(indexes); includedPaths.add(includedPath); indexingPolicy.setIncludedPaths(includedPaths); collectionDefinition.setIndexingPolicy(indexingPolicy);
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, inklusive relationsfrågor och hierarkiska frågor med UDF:er, lagrade procedurer och utlösare – som alla körs på dokumenten i en databassamling. Den kostnad som hör till var och en av dessa operationer varierar baserat på vilken CPU, vilka IO-resurser och hur mycket minne som krävs för att slutföra operationen. I stället för att tänka på och hantera maskinvaruresurser kan du betrakta en enhet för begäran (RU) 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 begäranden som angetts för varje container. Enhetsförbrukning för begäran utvärderas som en hastighet per sekund. Program som överskrider den etablerade enhetsfrekvensen för begäranden för containern begränsas tills priset sjunker under den etablerade nivån för containern. Om programmet kräver ett högre dataflöde kan du öka dataflödet genom att etablera ytterligare enheter för begäranden.
Komplexiteten i en fråga påverkar hur många enheter för begäran som förbrukas 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 för att mäta antalet enheter för begäranden som förbrukas av dessa åtgärder. Du kan också titta på motsvarande RequestCharge-egenskap i ResourceResponse<T> eller FeedResponse<T>.
Async Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)
ResourceResponse<Document> response = asyncClient.createDocument(collectionLink, documentDefinition, null, false).toBlocking.single(); response.getRequestCharge();
Den begärandeavgift som returneras i det här huvudet är en bråkdel av ditt etablerade dataflöde. Om du till exempel har etablerat 2 000 RU/s och om föregående fråga returnerar 1 000 1 KB-dokument är kostnaden för åtgärden 1 000. Därför respekterar servern bara två sådana begäranden inom en sekund innan efterföljande begäranden begränsas. 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) och returnerar rubriken x-ms-retry-after-ms som anger hur lång tid, i millisekunder, som användaren måste vänta innan begäran försöker 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 inte räcker. I det här fallet genererar klienten en DocumentClientException med statuskod 429 till programmet. Standardantalet för återförsök kan ändras med setRetryOptions på ConnectionPolicy-instansen. 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. Detta inträffar även om det aktuella antalet återförsök är mindre än det maximala antalet återförsök, oavsett om det är standardvärdet 9 eller ett användardefinierat värde.
Även om det automatiserade återförsöksbeteendet hjälper till att förbättra återhämtning och användbarhet för de flesta program, kan det komma till odds när prestandamått utförs, särskilt när svarstiden mäts. 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.
Designa för mindre dokument för högre dataflöde
Begärandeavgiften (kostnaden för bearbetning av begäran) för en viss åtgärd är direkt korrelerad till dokumentets storlek. Åtgärder på stora dokument kostar mer än åtgärder för små dokument.
Nästa steg
Mer information om hur du utformar ditt program för skalning och höga prestanda finns i Partitionering och skalning i Azure Cosmos DB.