Scenario voor het afstemmen van prestaties: Meerdere back-endservices

In dit artikel wordt beschreven hoe een ontwikkelingsteam metrische gegevens gebruikt om knelpunten te vinden en de prestaties van een gedistribueerd systeem te verbeteren. Het artikel is gebaseerd op de werkelijke belastingstests die zijn uitgevoerd voor een voorbeeldtoepassing. De toepassing is afkomstig van de Azure Kubernetes Service (AKS)-basislijn voor microservices,samen met een Visual Studio belastingstestproject dat wordt gebruikt om de resultaten te genereren.

Dit artikel maakt deel uit van een reeks. Lees het eerste deel hier.

Scenario: roep meerdere back-endservices aan om informatie op te halen en de resultaten vervolgens samen te brengen.

Dit scenario omvat een toepassing voor dronelevering. Clients kunnen een query uitvoeren REST API meest recente factuurgegevens op te halen. De factuur bevat een overzicht van de leveringen, pakketten en het totale dronegebruik van de klant. Deze toepassing maakt gebruik van een microservicearchitectuur die wordt uitgevoerd op AKS en de informatie die nodig is voor de factuur wordt verdeeld over verschillende microservices.

In plaats van dat de client elke service rechtstreeks aanroept, implementeert de toepassing het gatewayaggregatiepatroon. Met dit patroon maakt de client één aanvraag naar een gatewayservice. De gateway roept de back-endservices op zijn beurt parallel aan en aggregeert vervolgens de resultaten in één nettolading met één antwoord.

Diagram met het aggregatiepatroon van de gateway

Test 1: Basislijnprestaties

Om een basislijn vast te stellen, is het ontwikkelteam begonnen met een stapsgewijs geladen test, die de belasting van één gesimuleerde gebruiker naar maximaal 40 gebruikers laadt, gedurende een totale duur van 8 minuten. In het volgende diagram, dat afkomstig is Visual Studio, worden de resultaten weergegeven. De paarse lijn toont de gebruikersbelasting en de oranje lijn toont doorvoer (gemiddelde aanvragen per seconde).

Graph van Visual Studio belastingstestresultaten

De rode lijn aan de onderkant van de grafiek laat zien dat er geen fouten zijn geretourneerd naar de client, wat erg is. De gemiddelde doorvoer piekt echter ongeveer halverwege de test en daalt vervolgens voor de rest, zelfs als de belasting blijft toenemen. Dit geeft aan dat de back-end het niet bij kan houden. Het patroon dat hier wordt gezien, is gebruikelijk wanneer een systeem resourcelimieten begint te bereiken nadat een maximum is bereikt, de — doorvoer aanzienlijk daalt. Resource-problemen, tijdelijke fouten of een toename in het aantal uitzonderingen kunnen allemaal bijdragen aan dit patroon.

Laten we eens kijken naar de bewakingsgegevens om te leren wat er in het systeem gebeurt. De volgende grafiek is afkomstig uit Application Insights. Het toont de gemiddelde duur van de HTTP-aanroepen van de gateway naar de back-endservices.

Graph http-aanroepduur

In dit diagram ziet u dat één bewerking in het bijzonder, , gemiddeld veel langer duurt GetDroneUtilization met een orde van — grootte. De gateway voert deze aanroepen parallel uit, zodat de traagste bewerking bepaalt hoe lang het duurt voordat de hele aanvraag is voltooid.

De volgende stap is duidelijk dieper in de bewerking op zoek naar GetDroneUtilization knelpunten. Een mogelijkheid is uitputting van resources. Mogelijk heeft deze specifieke back-endservice geen CPU of geheugen meer. Voor een AKS-cluster is deze informatie beschikbaar in de Azure Portal via de functie Azure Monitor voor containers. In de volgende grafieken wordt het resourcegebruik op clusterniveau weergegeven:

Graph van het gebruik van AKS-knooppunt

In deze schermopname worden zowel het gemiddelde als het maximum weergegeven. Het is belangrijk om meer dan alleen het gemiddelde te bekijken, omdat het gemiddelde pieken in de gegevens kan verbergen. Hier blijft het gemiddelde CPU-gebruik onder de 50%, maar er zijn een paar pieken tot 80%. Dat is bijna de capaciteit, maar nog steeds binnen toleranties. Iets anders veroorzaakt het knelpunt.

In het volgende diagram wordt de werkelijke oorzaak weergegeven. In dit diagram ziet u HTTP-antwoordcodes uit de back-enddatabase van de leveringsservice, die in dit geval Cosmos DB. De blauwe lijn vertegenwoordigt succescodes (HTTP 2xx), terwijl de groene lijn HTTP 429-fouten vertegenwoordigt. Een HTTP 429-retourcode betekent dat Cosmos DB aanvragen tijdelijk worden afgesloten, omdat de aanroeper meer resource-eenheden (RU) verbruikt dan is ingericht.

Graph van beperkt aanvragen

Voor meer inzicht heeft het ontwikkelteam Application Insights gebruikt om de end-to-end telemetrie weer te geven voor een representatieve steekproef van aanvragen. Hier is één exemplaar:

Schermopname van de end-to-end-transactieweergave

In deze weergave ziet u de aanroepen met betrekking tot één clientaanvraag, samen met timing-informatie en antwoordcodes. De aanroepen op het hoogste niveau zijn van de gateway naar de back-endservices. De aanroep GetDroneUtilization van wordt uit uitgebreid om in dit geval aanroepen naar externe afhankelijkheden weer te — geven, Cosmos DB. De aanroep in het rood heeft een HTTP 429-fout geretourneerd.

Let op het grote gat tussen de HTTP 429-fout en de volgende aanroep. Wanneer de Cosmos DB een HTTP 429-fout ontvangt, wordt deze automatisch uitgeschakeld en wordt er gewacht om de bewerking opnieuw uit te voeren. In deze weergave ziet u dat tijdens de 672 ms die bewerking duurde, het grootste deel van die tijd werd gewacht om het opnieuw te Cosmos DB.

Hier is nog een interessante grafiek voor deze analyse. U ziet het RU-verbruik per fysieke partitie versus inrichtende RU's per fysieke partitie:

Graph ru-verbruik per partitie

Om deze grafiek zinvol te maken, moet u begrijpen hoe Cosmos DB partities beheert. Verzamelingen in Cosmos DB kunnen een partitiesleutel hebben. Elke mogelijke sleutelwaarde definieert een logische partitie van de gegevens in de verzameling. Cosmos DB verdeelt deze logische partities over een of meer fysieke partities. Het beheer van fysieke partities wordt automatisch afgehandeld door Cosmos DB. Wanneer u meer gegevens opgeslagen, Cosmos DB logische partities verplaatsen naar nieuwe fysieke partities om de belasting over de fysieke partities te verdelen.

Voor deze belastingstest is de Cosmos DB ingericht met 900 RUs. In de grafiek ziet u 100 RU per fysieke partitie, wat een totaal van negen fysieke partities impliceert. Hoewel Cosmos DB automatisch de sharding van fysieke partities verwerkt, kan de kennis van het aantal partities inzicht geven in de prestaties. Het ontwikkelteam gebruikt deze informatie later, terwijl ze doorgaan met optimaliseren. Waar de blauwe lijn de paarse horizontale lijn passeert, heeft het RU-verbruik de inrichtende RU's overschreden. Dat is het punt waarop Cosmos DB aanroepen begint te bete beperkt.

Test 2: Resource-eenheden verhogen

Voor de tweede belastingstest heeft het team de verzameling Cosmos DB geschaald van 900 RU naar 2500 RU. De doorvoer is toegenomen van 19 aanvragen per seconde naar 23 aanvragen per seconde en de gemiddelde latentie is gedaald van 669 ms naar 569 ms.

Metrisch Test 1 Test 2
Doorvoer (aantal per seconde) 19 23
Gemiddelde latentie (ms) 669 569
Geslaagde aanvragen 9,8 K 11 K

Dit zijn geen enorme voordelen, maar als u de grafiek na een periode ziet, ziet u een vollediger beeld:

Graph van Visual Studio belastingstestresultaten met een consistentere doorvoer.

Waar de vorige test een eerste piek vertoont, gevolgd door een sterke daling, toont deze test een consistentere doorvoer. De maximale doorvoer is echter niet aanzienlijk hoger.

Alle aanvragen voor Cosmos DB een 2xx-status geretourneerd en de HTTP 429-fouten zijn verwijderd:

Graph van Cosmos DB-aanroepen

In de grafiek van RU-verbruik versus inrichtende RU's ziet u dat er veel ruimte is. Er zijn ongeveer 275 RUs per fysieke partitie en de belastingstest piekte op ongeveer 100 verbruikte AANTAL's per seconde.

Graph ru-verbruik versus inrichtende RU's laat zien dat er voldoende ruimte is.

Een andere interessante metriek is het aantal aanroepen naar Cosmos DB per geslaagde bewerking:

Metrisch Test 1 Test 2
Aanroepen per bewerking 11 9

Ervan uitgaande dat er geen fouten zijn, moet het aantal aanroepen overeenkomen met het werkelijke queryplan. In dit geval omvat de bewerking een partitieoverschrijdende query die alle negen fysieke partities raakt. De hogere waarde in de eerste belastingstest weerspiegelt het aantal aanroepen dat een 429-fout heeft geretourneerd.

Deze metrische gegevens zijn berekend door een aangepaste Log Analytics-query uit te voeren:

let start=datetime("2020-06-18T20:59:00.000Z");
let end=datetime("2020-07-24T21:10:00.000Z");
let operationNameToEval="GET DroneDeliveries/GetDroneUtilization";
let dependencyType="Azure DocumentDB";
let dataset=requests
| where timestamp > start and timestamp < end
| where success == true
| where name == operationNameToEval;
dataset
| project reqOk=itemCount
| summarize
    SuccessRequests=sum(reqOk),
    TotalNumberOfDepCalls=(toscalar(dependencies
    | where timestamp > start and timestamp < end
    | where type == dependencyType
    | summarize sum(itemCount)))
| project
    OperationName=operationNameToEval,
    DependencyName=dependencyType,
    SuccessRequests,
    AverageNumberOfDepCallsPerOperation=(TotalNumberOfDepCalls/SuccessRequests)

Kortom, de tweede belastingstest toont verbetering. De bewerking GetDroneUtilization duurt echter nog steeds ongeveer een orde van grootte langer dan de eerstvolgende traagste bewerking. Als u naar de end-to-end-transacties kijkt, wordt uitgelegd waarom:

Schermopname van de tweede belastingstest met een verbetering.

Zoals eerder vermeld, omvat de GetDroneUtilization bewerking een partitieoverschrijdende query om de Cosmos DB. Dit betekent dat Cosmos DB client de query naar elke fysieke partitie moet uitwaateren en de resultaten moet verzamelen. Zoals de end-to-end-transactieweergave laat zien, worden deze query's serieel uitgevoerd. De bewerking duurt zolang de som van alle query's en dit probleem alleen maar erger wordt als de grootte van de gegevens toeneemt en er meer fysieke partities — worden toegevoegd.

Test 3: Parallelle query's

Op basis van de vorige resultaten is een duidelijke manier om de latentie te verminderen, door de query's parallel uit te geven. De Cosmos DB client-SDK heeft een instelling die de maximale mate van parallellisme bepaalt.

Waarde Beschrijving
0 Geen parallellisme (standaard)
> 0 Maximum aantal parallelle aanroepen
-1 De client-SDK selecteert een optimale mate van parallellisme

Voor de derde belastingstest is deze instelling gewijzigd van 0 in -1. De volgende tabel bevat een overzicht van de resultaten:

Metrisch Test 1 Test 2 Test 3
Doorvoer (aantal per seconde) 19 23 42
Gemiddelde latentie (ms) 669 569 215
Geslaagde aanvragen 9,8 K 11.000 20.000
Beperkt aantal aanvragen 2,72 K 0 0

Vanuit de belastingtestgrafiek is niet alleen de totale doorvoer veel hoger (de oranje lijn), maar blijft de doorvoer ook gelijke tred houden met de belasting (de paarse lijn).

Graph van Visual Studio belastingstests toont een hogere algehele doorvoer die gelijke tred houdt met de belasting.

We kunnen controleren of de client Cosmos DB query's parallel maakt door te kijken naar de end-to-end transactieweergave:

Schermopname van de end-to-end-transactieweergave die laat zien Cosmos DB client parallel query's maakt.

Interessant is dat een neveneffect van het verhogen van de doorvoer is dat het aantal verbruikte RUs per seconde ook toeneemt. Hoewel Cosmos DB tijdens deze test geen aanvragen heeft beperkt, was het verbruik dicht bij de inrichtende RU-limiet:

Graph ru-verbruik dicht bij de inrichtende RU-limiet.

Deze grafiek kan een signaal zijn om de database verder uit te schalen. Het blijkt echter dat we de query in plaats daarvan kunnen optimaliseren.

Stap 4: de query optimaliseren

De vorige belastingstest heeft betere prestaties latentie en doorvoer laten zien. De gemiddelde latentie van aanvragen is met 68% verminderd en de doorvoer is met 220% toegenomen. De query voor kruislingse partities is echter een probleem.

Het probleem met query's voor meerdere partities is dat u voor elke partitie betaalt voor RU. Als de query slechts af en toe wordt — uitgevoerd, bijvoorbeeld één keer per — uur, is dit mogelijk niet van belang. Maar wanneer u een leesbelasting ziet die een partitieoverschrijdende query omvat, moet u zien of de query kan worden geoptimaliseerd door een partitiesleutel op te nemen. (Mogelijk moet u de verzameling opnieuw ontwerpen om een andere partitiesleutel te gebruiken.)

Dit is de query voor dit specifieke scenario:

SELECT * FROM c
WHERE c.ownerId = <ownerIdValue> and
      c.year = <yearValue> and
      c.month = <monthValue>

Met deze query worden records geselecteerd die overeenkomen met een bepaalde eigenaar-id en maand/jaar. In het oorspronkelijke ontwerp is geen van deze eigenschappen de partitiesleutel. Hiervoor moet de client de query naar elke fysieke partitie uitwaateren en de resultaten verzamelen. Om de queryprestaties te verbeteren, heeft het ontwikkelteam het ontwerp gewijzigd, zodat de eigenaar-id de partitiesleutel voor de verzameling is. Op die manier kan de query gericht zijn op een specifieke fysieke partitie. (Cosmos DB dit automatisch verwerkt; u hoeft de toewijzing tussen partitiesleutelwaarden en fysieke partities niet te beheren.)

Nadat de verzameling is overschakelt naar de nieuwe partitiesleutel, is het RU-verbruik aanzienlijk verbeterd, wat direct leidt tot lagere kosten.

Metrisch Test 1 Test 2 Test 3 Test 4
AANTAL PER BEWERKING 29 29 29 3.4
Aanroepen per bewerking 11 9 10 1

In de end-to-end-transactieweergave ziet u dat, zoals voorspeld, de query slechts één fysieke partitie leest:

Schermopname van de end-to-end-transactieweergave waarin wordt weergegeven dat de query slechts één fysieke partitie leest.

De belastingstest toont verbeterde doorvoer en latentie:

Metrisch Test 1 Test 2 Test 3 Test 4
Doorvoer (aantal per seconde) 19 23 42 59
Gemiddelde latentie (ms) 669 569 215 176
Geslaagde aanvragen 9,8 K 11.000 20.000 29.000
Beperkt aantal aanvragen 2,72 K 0 0 0

Een gevolg van de verbeterde prestaties is dat het CPU-gebruik van knooppunt zeer hoog wordt:

Graph een hoog CPU-gebruik van knooppunt.

Aan het einde van de belastingstest heeft de gemiddelde CPU ongeveer 90% bereikt en de maximale CPU 100%. Deze metrische gegevens geven aan dat CPU het volgende knelpunt in het systeem is. Als een hogere doorvoer nodig is, is de volgende stap mogelijk het uitschalen van de Leveringsservice naar meer exemplaren.

Samenvatting

Voor dit scenario zijn de volgende knelpunten geïdentificeerd:

  • Cosmos DB aanvragen vanwege onvoldoende inrichten van AANVRAAG's.
  • Hoge latentie veroorzaakt door het uitvoeren van query's op meerdere databasepartities in serie.
  • Inefficiënte partitieoverschrijdende query, omdat de query de partitiesleutel niet bevat.

Daarnaast is het CPU-gebruik geïdentificeerd als een potentieel knelpunt op een hogere schaal. Het ontwikkelteam heeft het volgende bekeken om deze problemen vast te stellen:

  • Latentie en doorvoer van de belastingstest.
  • Cosmos DB fouten en RU-verbruik.
  • De end-to-end-transactieweergave in Application Insight.
  • CPU- en geheugengebruik in Azure Monitor voor containers.

Volgende stappen

Antipatroon voor prestaties controleren