Hoofdstuk 1 (link), hoofdstuk 2 (link), hoofdstuk 3 (link) en hoofdstuk 4 (link), nu tijd voor het 5e hoofdstuk, het monitoren, het oplossen van problemen en het optimaliseren met Azure oplossingen.
In dit hoofdstuk worden 3 vaardigheden besproken die je als ontwikkelaar zou moeten hebben. We gaan ze stuk voor stuk langs;
Ontwikkel code om schaalbaarheid van apps en diensten te ondersteunen.
In Azure kun je zaken laten op- en afschalen, afhankelijk van het aantal gebruikers wat je diensten gebruikt. Je hebt 2 richtingen, verticaal: meer geheugen, meer CPU resources. Je gaat naar een grotere virtuele machine met meer resources. Dit valt onder "scaling up and down". Maar tijdens het opschalen moet het systeem wel gestopt worden. Horizontaal: hierbij worden nieuwe instanties van jouw applicatie aangemaakt (of verwijderd) en ga je dus in de breedte. Dit type opschalen valt onder "scaling in and out" en hoort bij autoschalen.
Voor autoscaling kun je een aantal regels gebruiken, time-based: als het alleen de eerste week van de maand druk is kun je instellen dat er meer resources zijn in die periode en in de overige weken een lager aantal. Metric-based: met tresholds geeft je aan bij welke waarde van belasting van een CPU, geheugen er iets gedaan moet worden. Custom-based: je kunt in je applicatie zelf een metric maken, en via Application Insight beschikbaar maken voor deze regel.
Deze mechanismes kun je niet overal gebruiken, deze zijn beschikbaar voor: Azure virtual machines: je kunt hiermee scale sets instellen. Alle VM in een scale set worden beschouwd als 1 groep. Azure Service Fabric: in een cluster maak je verschillende node-types aan. Een andere VM scale set ondersteunt elk nodetype wat jij aangeeft. Azure App Service: je kunt instanties van de App Service toevoegen of verwijderen. Azure Cloud Services: hiermee kun je resources toevoegen of verwijderen van de rollen in Azure Cloud Services.
Als je regels maakt voor "scale out", die blijven actief. Dus je moet ook zelf je regels maken om later de "scale in" weer uit te voeren.
Natuurlijk zijn er ook "best practices" en die kun je hier nalezen: link. En ook voor het bouwen van je applicatie, om het beste gebruik te maken van deze schaalmogelijkheid, zijn er tips: link.
Je code moet met kortstondige fouten om kunnen gaan
- Detecteren en classificeren van fouten: je applicatie moet kunnen detecteren of het hier om een korte, langdurige of "fatale" fout gaat.
- Opnieuw proberen indien van toepassing: afhankelijk van je actie en code moet je een nieuwe poging doen. Ook moet je bijhouden hoe vaak je het al opnieuw geprobeerd hebt.
- Implementeer een toepasselijke "probeer-opnieuw" strategie: bepaal hier hoe vaak je het opnieuw gaat proberen, hoeveel tijd hier tussen zit en wat er moet gebeuren als het uiteindelijk nog niet lukt.
Ondersteuning hierbij kan komen van:
- De SDK, misschien heeft deze zelf al retry-mogelijkheden, ga het dan niet zelf bouwen.
- Controleer of de actie wel opnieuw geprobeerd moet/kan worden. Dat doe je op basis van: je snapt het volledige effect van de actie, je snapt de voorwaarden van de "opnieuw-proberen" actie en je kunt deze voorwaarden valideren.
- Stel het juiste maximum aantal en tijdsintervallen in. Een netwerk-verzoek wat een minuut heeft om een time-out te krijgen en wat je dan 3x aan gaat roepen met een vertraging van 5 minuten zorgt dat je call 18 minuten langer gaat duren als het fout blijft gaan. Wil je zolang wachten?
Voor die intervallen zijn verschillende strategieën beschikbaar:
- exponential back-off: je start met 3 seconden, 9 seconden, 27, 81 seconden.
- incremental intervals: je telt elke keer de tijd ertussen erbij, dus 3 seconden, 5 seconden (+2), 8 seconden (+3), 13 seconden (+5 (2+3)), 21 seconden (+8 (3+5))
- regular intervals: elke keer dezelfde interval, deze methode wordt afgeraden.
- immediate interval: direct opnieuw proberen, nuttig bij netwerk "spikes". Maar 1x uit te voeren, daarna overstappen op andere strategie.
- randomization: als je parallelle processen hebt die opnieuw hun call moeten uitvoeren, moet je deze willekeurig laten starten. Deze kunnen zelf met een andere van de bovenstaande strategieën hun aanroepen uitvoeren.
Voorkom het gebruik van anti-patterns, ga dus niet op duizenden plaatsen in je code retry-acties opstarten. Gebruik ook geen eindeloze retry-acties, laat het eindigen of gebruik een circuit-breaker om de flow te stoppen. En gebruik de immediate retry echt maar 1x.
Je moet je strategie (natuurlijk) wel testen. Dat doe je door kortstondige, langdurige en fatale fouten te injecteren.
Beheers je strategie. Dat doe je niet door die intervallen hard-coded toe te voegen, maar in Azure een policy aan te maken waar je die waardes kunt onderhouden.
Log alle fouten. Iets wat een keer voorkomt hoeft niet erg te zijn. Maar je weet pas of iets een éénmalige fout was of dat het vaker voorkomt als het gelogd wordt.
Ook hier weer een aantal tips, guidelines voor het afhandelen van kortstondige fouten: link en link. En een paar patterns, retry pattern en circuit-pattern.
Integreer caching en CDN in je applicatie
Een applicatie bestaat uit dynamische en statische inhoud. Statische inhoud kun je naar meerdere servers kopiëren, zodat deze dichter bij de bezoeker is en sneller opgevraagd kan worden. Dynamische content kan in cache geplaatst worden, zodat niet elke keer een (zware) database query uitgevoerd hoeft te worden.
Redis is een open-source cache systeem wat ook in Azure beschikbaar is. Het biedt de mogelijkheden om als datastructuur in het geheugen gebruikt te worden, database cache of een dienst die berichten heen en weer stuurt. Je hebt in Azure 3 verschillende prijsklassen beschikbaar:
- Basic: de versie met de minste mogelijkheden, die het traagst is en het minst aantal mogelijkheden heeft (en dus ook geen SLA). Deze gebruik je dus alleen voor ontwikkeling en test.
- Standard: 2 nodes, primary-secondary gerepliceerde cache, beheerd door Microsoft, SLA van 99.9 procent.
- Premium: de enterprise versie, cluster beheerd door Microsoft. Alle mogelijkheden, draait op snelle hardware. SLA van 99.9 procent.
Wel iets om op te letten: je kunt wel opschalen naar een hogere versie, maar niet weer afschalen!
Afhankelijk van de inrichting van jouw applicatie zijn er verschillende structuren die je kunt volgen;
- cache-aside: gegevens opvragen uit een database is "duur". De hele database in het geheugen laden is "niet te doen". Dus de meest opgevraagde data, die zet je in het geheugen. Als die data in de database aangepast wordt, wordt ook de cache bijgewerkt.
- content caching: veel delen van websites zijn statisch, een header, een footer. Door dit te cachen hoef je een deel niet continu dynamisch op te bouwen en spaar je resources.
- user session caching: soms moet een gebruiker veel data beschikbaar hebben en dat is te veel om in een cookie te stoppen (want die gaat continu over de lijn). Door dat in de cache te bewaren kun je zorgen voor betere performance.
- job en message queuing: je kunt langdurige taken door Azure Cache for Redis laten afhandelen, waarmee je jouw applicatie ontlast.
- distributed transactions: een transactie is een actie waarbij een aantal onderdelen gezamenlijk of allemaal lukken of allemaal falen. Azure Cache for Redis implementeert dit.
Je kunt met verschillende talen werken, zoals ASP.NET, .NET, .NET Core, Node.js, Java, Python.
Meer informatie over Redis is hier te vinden: basics, transacties en keys-values.
Met een CDN kun je kiezen tussen de Azure CDN of die van Verizon of Akamai. Uitleg over CDN en caching kun je hier nalezen: link. Er wordt nog de opmerking gemaakt dat je voor Dynamic Site Acceleration niet bij de Azure CDN moet zijn, maar bij de dienst Azure Front Door Service.
Bestanden in de cache van een CDN krijgen een TTL, een "time to live". Als de aanroep hier binnen valt, krijg je dit bestand terug. Als die tijd verstreken is, wordt het cache-bestand vergeleken met het originele bestand. Is dat gelijk, dan wordt de tijd opnieuw ingesteld, is de afbeelding anders, dan wordt de nieuwe afbeelding in de cache gezet (met bijbehorende TTL). De waarde hiervoor is op verschillende manieren in te stellen:
- je stelt niets in, default CDN configuratie: standaard maakt Azure er 7 dagen van.
- caching rules: hiermee kun je zelf de tijden configureren op basis van map, type bestand. En ook delen juist niet laten cachen.
- web.config bestanden: hiermee kun je zelf de TTL van die map instellen. in tag system.webServer de tag staticContent met de tag clientCache (met attributen cacheControlMode="UseMaxAge", cacheControlMaxAge="3.00:00:00"), in dit voorbeeld dus 3 dagen.
- via code: je kunt in code met Response.Cache.SetExpires, Response.Cache.SetCacheability, Response.Cache.SetLastModified dit beïnvloeden.
Als je Azure Cache voor Redis gebruikt moet je ook daar een TTL instellen op waardes van de in-memory database. Anders verloopt de cache nooit!
// 5 uren
_cache.StringSet(key, Serialize(value), new TimeSpan(5, 0, 0));
Naast het instellen/gebruiken van die tijdslimiet, kun je het ook beïnvloeden door het bestand uit de cache te halen.
Om iets uit de Redis cache te halen gebruik je KeyDelete() om een enkele sleutel te verwijderen. Met FlushAllDatabases() leeg je alles.
Het legen van de CDN kan alleen via de portal met de Purge knop bij je CDN profiel.
Richt je applicatie in om monitoring en logging te ondersteunen
Met Application Insights kun je jouw applicatie monitoren. Wat kun je ermee zien?
- request rates, response times en failure rates: hier kun je zien wanneer welke pagina's opgevraagd worden en hoe lang de server erover doet om die aan te bieden.
- dependency rates, response times en failure rates: als je applicatie afhankelijk is van externe diensten (bijvoorbeeld Google, Twitter), daar kun je de performance ook van zien.
- exceptions: hier kun je de fouten terug zien. Ook de bijbehorende stacktrace. En ook statistieken om een algemeen beeld te krijgen.
- page views en load performance: je krijg hier ook terug hoe de browsers het inladen beoordelen.
- ajax calls: hier worden de tijden van ajax calls bijgehouden. Ook zie je hier de fouten.
- user en sessie aantallen: je kunt zien hoeveel gebruikers je applicatie gebruiken.
- performance counters: CPU, geheugengebruik, netwerkbelasting.
- host diagnostics: informatie over je applicatie als deze in een Docker of Azure omgeving draait.
- diagnostic trace logs: in je code kun je zaken "loggen" naar een trace log, dat kun je hier bekijken.
- custom events en metrieken: hier kun je jouw eigen zaken monitoren. Dus bijvoorbeeld voor een webshop hoeveel mensen de check-out doorlopen hebben, bij online spellen de scores, etc.
Als je meer wilt weten over het maken van je eigen events en metrieken, dat kun je hier nalezen: link.
Een iets lichtere applicatie is de Azure Monitor. Hiermee kun je zaken bijna in real-time volgen. Belasting van het systeem, aantal gebruikers. Je kunt data filteren met behulp van een soort SQL, de Kusto query language. Meer informatie daarover kun je hier vinden: link.
Het boek komt nog met het voorbeeld van het implementeren van Insight Web Tests en Alerts. Bijvoorbeeld door te zorgen dat je een notificatie krijgt als de website een HTTP statuscode 502 terug geeft. Je kunt een URL ping test doen (is de URL te bereiken), een Multi-step web test, je kunt de stappen opnemen in een tekstbestand en die in Application Insights gebruiken (dit schijn je alleen te kunnen maken met Visual Studio Enterprise), Custom Track Availability Test, door de methode TrackAvailability() te gebruiken kun je een test maken.
Meer informatie over alerts kun je hier nalezen: link.