ClusterTriage / Blog / Root cause analysis
Eén incident, twee rapporten: hoe mijn AI-assistent een node uit mijn Azure Local-cluster gooide, en wat de RCA ervan maakte
Ik vroeg om een testbestand. Ik kreeg een clusterincident. Daarna vroeg ik om de root cause analysis, geschreven alsof niemand het antwoord kende, en daarna nog een keer voor een lezer die nog nooit van een heartbeat heeft gehoord. Dit is het verhaal van één gebeurtenis van 80 seconden op een Azure Local-labcluster met twee nodes, en waarom dezelfde gebeurtenis twee verschillende rapporten verdient.
De korte versie: een live kernel memory dump bevroor één node 52 seconden lang, het cluster deed precies wat het moest doen en zette die node eruit, en het bewijspakket liet het tot op de seconde zien. De lange versie is nuttiger, want die laat zien hoe je een RCA opbouwt, wat drie heel verschillende lezers eraan hebben, en wat het betekent als degene die het incident veroorzaakte ook het rapport schrijft.
1. Het lab: waarom we een Azure Local-cluster bouwden om stuk te maken
ClusterTriage beoordeelt en analyseert Hyper-V Failover Cluster-, HCI- en Azure Local-omgevingen. De gratis instap is ClusterDown.com (vanaf deze site: klik in het menu op Clusterproblemen?): als een cluster in de problemen zit, draait de klant één script, stuurt één zipbestand terug en krijgt de vijf belangrijkste issues terug, met daarna de mogelijkheid van een volledige root cause analysis.
Zo'n hulpmiddel bouw je niet op theorie. Je hebt clusters nodig die zich misdragen, en je moet bij elke misdraging weten wat er echt gebeurde, zodat je kunt nagaan of het hulpmiddel het vindt. Daarom bouwde ik in september een lab: een Azure Local 2609-cluster met twee nodes, genest op één gehuurde server met een Intel Core i9-13900 en 128 GB geheugen. De buitenste laag is Proxmox, de twee clusternodes zijn virtuele machines met Azure Local, en in een van die nodes draait de Arc Resource Bridge, zelf weer een virtuele machine. Drie lagen virtualisatie, vier virtuele processors per node.
Azure Local die opzet laten accepteren was een project op zich (de validator wil onder meer ECC-geheugen, netwerkkaarten die fysiek lijken en unieke schijfidentiteiten zien), en dat verhaal komt in een ander artikel. Waar het hier om gaat: het cluster was uitgerold, in Azure geregistreerd en draaide. Een prima plek om dingen stuk te maken, zolang je weet wat je stukmaakte.
2. Het verzoek dat een incident werd
Het meeste bouwwerk aan dit lab deed ik samen met Claude, de AI-assistent waarmee ik de ClusterTriage-toolchain bouw. Claude voert de opdrachten uit, ik neem de beslissingen.
Op 1 oktober wilde ik een geheugendump om de dumpdetectie van ClusterDown mee te testen. Daar vroeg ik ook precies om: "maak een test-dumpfile van N01." Claude koos een live kernel dump, het soort dat Windows kan maken zonder de server te laten crashen, met de cmdlet voor opslagdiagnose:
Get-StorageDiagnosticInfo -StorageSubSystemFriendlyName 'Windows Storage on AZL-N01' `
-DestinationPath C:\Temp\LiveDumpTest -IncludeLiveDump
De terugmelding: 4,6 GB geschreven in 124 seconden, de node draait nog, niets gecrasht. Allemaal waar. Ook onvolledig.
Waar we die middag geen van beiden naar keken: tijdens die 124 seconden had het cluster N01 uit het lidmaatschap gezet, een gedeeld volume gepauzeerd, alle clusterrollen naar N02 verplaatst, en had de clusterservice van N01 zichzelf met een fatale fout gestopt. Tachtig seconden later was N01 terug in het cluster, en van buitenaf zag alles er weer normaal uit.
Het kwam pas de volgende dag boven, toen een andere sessie vroeg om de "grondwaarheid" van een gebeurtenis om 06:41 UTC waar de analyse steeds op uitkwam. Claude las de eventlogs en vond overal zijn eigen vingerafdrukken. Het bericht aan mij begon met de bekentenis dat het het incident zelf had veroorzaakt.
Ik vroeg niet om een crash. Ik vroeg om een dump. Het verschil tussen die twee bleek op een kleine, drukke clusternode één heartbeat-instelling te zijn. Dat is de eerste les, en daar komen we op terug.
3. De RCA schrijven alsof niemand het wist
Daarna deed ik iets wat bewust ongemakkelijk is. Ik verzamelde een vers ClusterDown-pakket van het cluster, gaf het aan Claude en vroeg om een root cause analysis met drie regels:
- Je weet de oorzaak niet. Toon hem aan met het bewijs in dit pakket, en met combinaties van bewijs.
- Elke bewering noemt haar bron.
- Zeg wat je mist om een beter rapport te kunnen schrijven.
Het voor de hand liggende probleem: de schrijver kende het antwoord. Dat is geen theoretisch probleem; het is precies de situatie van elke engineer die de RCA schrijft voor een incident in zijn eigen team. De methode moest het rapport dus beschermen tegen zijn schrijver. Claude hield zijn eigen kennis er volledig buiten, ook de delen die het rapport sterker hadden gemaakt, zoals de exacte opdracht die werd gedraaid. Wat het pakket niet kon aantonen, kwam er niet in. De grondwaarheid werd apart vastgelegd, in een eigen bestand, zodat een reviewer de conclusie daarna kon toetsen.
Elke RCA zou zo moeten werken, of de analist nu een mens is of niet. Een rapport dat leunt op wat de schrijver toevallig weet, is een mening. Een rapport dat leunt op bewijs, kan iemand anders nakijken.
4. Wat het bewijs liet zien, tot op de seconde
De probleemomschrijving van de beheerder in het pakket luidde: "Cluster node crashed unexpectedly." Dat was het eerste wat de RCA weerlegde. Beide nodes waren voor het laatst opgestart op 30 september. Er was geen event 41 of 6008, geen blauw scherm en geen crashdump. Er crashte geen node. Een node verloor zijn lidmaatschap. Dat verschil doet ertoe, want het stuurt je naar een heel andere plek om te zoeken.
Dan de tijdlijn. Drie bewijsstukken, uit drie verschillende bronnen, vallen op dezelfde seconden samen:
| Tijd (UTC) | Bron | Wat het zegt |
|---|---|---|
| 06:40:49 | Kernel-LiveDump-kanaal op N01 | "Live Dump Capture Dump Data API started" |
| ~06:40:49,7 | Clusterlog op N02, routehistorie van de heartbeats | Laatste heartbeat-antwoord van N01 (om 06:41:09 vastgelegd als 19,65 seconden oud) |
| 06:41:41 | Kernel-LiveDump-kanaal op N01 | Laatste fase van het vastleggen afgerond |
| 06:41:41,505 | Systeemlog op N02, event 1135 | N01 uit het clusterlidmaatschap verwijderd |
De heartbeats stopten in dezelfde seconde waarin de dump begon. De node werd verwijderd in dezelfde seconde waarin de dump klaar was. Tussen die twee momenten logde N01 niets behalve de voortgang van de dump zelf. En N01 merkte de ontbrekende heartbeats zelf pas om 06:41:55, nadat hij weer wakker was, met een routehistorie waarin de laatste heartbeat 26 seconden oud was. Zo ziet een gepauzeerde server eruit. Een server met een kapot netwerk merkt het probleem terwijl het gebeurt; een bevroren server merkt het pas achteraf, als de klok is verder gesprongen.
De heartbeat-tolerantie van het cluster, uit hetzelfde pakket: 25 gemiste heartbeats van één per seconde. De node was ongeveer 52 seconden stil. Het cluster deed niets fout; het zette een node eruit die niet antwoordde.
Daarna toetste het rapport de alternatieven, een voor een:
- Netwerk: alle drie de netwerken (beheer en twee opslagnetwerken) vielen op hetzelfde moment weg, in beide richtingen, met nul events in het NDIS-kanaal. Zo gedraagt een netwerkstoring zich niet.
- Hardware: nul WHEA-events op beide nodes.
- Opslag: het gepauzeerde volume en de schrijffouten van het bestandssysteem komen allemaal na de verwijdering. Gevolg, geen oorzaak.
- Crash van het besturingssysteem: weerlegd door de opstarttijden en het ontbreken van elke dump of elk crash-event.
- Uitputting van middelen: mogelijk als bijdragende factor (vier processors per node, plus de Arc Resource Bridge-VM op N01), maar niet aan te tonen, want het pakket bevatte geen CPU-historie van die minuut.
En dan het deel dat ik het mooist vind: de vraag die het bewijs niet kon beantwoorden. Wie startte de live dump? Het veld met de vlaggen in het LiveDump-event is niet ingevuld, en er stond geen dumpbestand in de standaardmappen. Juist dat ontbreken was een aanwijzing: een dump die Windows zelf maakt, komt in LiveKernelReports terecht, dus een dump die daar niet staat, is waarschijnlijk bewust aangevraagd, met een eigen bestemming. Het rapport zegt precies dat, gemarkeerd als afleiding, en noemt wat het zou beslechten: audit van procesaanmaak, PowerShell-logging, en het eigen verslag van de beheerder van wat er om 06:40 werd gedraaid.
Het rapport kon mij niet aanwijzen. Ik stond niet in het bewijs. Zo hoort het.
5. Dezelfde gebeurtenis, twee rapporten
Het eerste rapport is het rapport dat een engineer voor engineers schrijft: zes pagina's, elke bewering gekoppeld aan een evidence-ID, zes hypothesen getoetst, rekenwerk met de routehistorie van de heartbeats, een zekerheidsoordeel per conclusie. Het is volledig, en bijna niemand buiten het clusterteam leest verder dan pagina één.
Dus vroeg ik om een tweede versie: voor een gewone serverbeheerder die geen clusterspecialist is, met een managementsamenvatting bovenaan die zijn leidinggevende los kan lezen. Dezelfde gebeurtenis, hetzelfde bewijs, dezelfde conclusie. Drie pagina's.
Een paar verschillen, naast elkaar:
| Technische RCA | Versie voor de beheerder, met managementsamenvatting | |
|---|---|---|
| De oorzaak | "A live kernel memory dump capture suspended the node for about 52 seconds, exceeding the 25-second heartbeat tolerance (SameSubnetThreshold 25, SameSubnetDelay 1000)." | "A full memory snapshot of that server was being taken. While the snapshot is taken, the server is paused. Here for about 50 seconds; the cluster only waits 25." |
| Het bewijs | Evidence-ID's E2304 tot E2445, routehistorie, zes hypothesen | "The timing matches to the second", plus een tabel van wat werd uitgesloten en waarom |
| De open vraag | Ingevulde vlaggen van event 1, Security 4688, PowerShell 4103/4104 | "Who or what asked for that snapshot. That is the real question." |
| Het advies | Vijf aanbevelingen met hun onderbouwing | Suspend-ClusterNode -Drain vóór een dump, direct uit te voeren |
Lees ze allebei en vergelijk zelf (de rapporten zijn in het Engels):
- De technische RCA (pdf, 6 pagina's, 187 KB)
- De versie voor de beheerder, met managementsamenvatting (pdf, 3 pagina's, 113 KB)
Niets werd vereenvoudigd tot iets wat niet klopt. Dat was het moeilijke deel. "Het cluster draait sindsdien normaal" was een mooie zin geweest voor een manager, maar niets in het pakket mat dat, dus het rapport zegt "toen de gegevens de volgende dag werden verzameld, maakten beide servers weer deel uit van het cluster." Eenvoudige taal is geen vrijbrief om het bewijs op te rekken.
Zit uw cluster nu in de problemen? ClusterDown.com geeft u gratis de vijf belangrijkste issues met één script en één zipbestand. Een root cause analysis zoals deze is de volgende stap als u die nodig hebt. Op deze site: klik in het menu op Clusterproblemen?.
Naar ClusterDown.com →6. Waarom elke lezer krijgt wat hij nodig heeft
De manager leest zes korte alinea's en kan drie beslissingen nemen zonder één clusterterm te begrijpen: is er iets verloren gegaan (er crashte geen server; ongeveer anderhalve minuut draaide het cluster op één server), gebeurt het waarschijnlijk opnieuw (klein, tenzij de snapshot automatisch werd gestart, en daarom is uitzoeken wie hem startte actie nummer één), en wat kost het om het te voorkomen (een werkafspraak en mogelijk grotere servers). Geen heartbeat-drempels, geen event-ID's, maar ook geen geruststelling die het bewijs niet draagt.
De beheerder krijgt wat een beheerder echt met een RCA doet: een tijdlijn in gewone woorden, de redenen waarom de voor de hand liggende verdachten zijn uitgesloten (zodat hij morgen niet een netwerkswitch gaat vervangen), een kort lijstje plekken om zelf te kijken, en de exacte opdracht die herhaling voorkomt. Het rapport zegt ook wat het nog van hem nodig heeft, en dat maakt van een lezer een deelnemer.
De engineer krijgt de versie waar hij het op details mee oneens kan zijn. Elke bewering heeft een bron die hij kan openen, elke hypothese heeft haar bewijs voor en tegen, en elke afleiding staat als afleiding gemarkeerd. Denkt hij dat de 52 seconden niet kloppen, dan kan hij het rekenwerk uit de routehistorie overdoen. Een RCA die een sceptische engineer kan nakijken, is meer waard dan een die hij op gezag moet aannemen, zeker als de conclusie ongemakkelijk is.
De drie lezers willen verschillende dingen uit dezelfde feiten. Eén rapport schrijven en hopen dat het alle drie bedient, levert een document op dat de manager niet begrijpt en de engineer niet gelooft.
7. Wat we daarna veranderden
Het incident was klein, maar het veranderde een paar dingen echt.
Eerst draineren, dan dumpen. Een live kernel dump is bedoeld om niet te storen, en op een grote, rustige server is dat misschien ook zo. Op een kleine clusternode kan hij de machine langer bevriezen dan de heartbeat-tolerantie. Hebt u een dump van een clusternode nodig, haal de node er dan eerst uit:
Suspend-ClusterNode -Name AZL-N01 -Drain
# maak de dump
Resume-ClusterNode -Name AZL-N01
Zeg wat een handeling met het cluster doet, niet alleen met de server. "De node blijft draaien" was waar en deed niet ter zake. De vraag die vóór de opdracht gesteld had moeten worden: wat ziet het cluster terwijl dit loopt? Dat geldt voor mensen en voor AI-assistenten.
De grondwaarheid is nu een testcase. Omdat we precies weten wat er om 06:41 gebeurde, is deze gebeurtenis nu een vaste vergelijkingscase voor de analyse van ClusterDown: elke versie van het hulpmiddel moet uitkomen op "een live dump op N01, gestart door een beheerder", en een versie die het netwerk de schuld geeft, heeft een fout.
En nog één ding, voor de toolchain zelf. Voordat het pakket uit dit artikel bestond, kwam de incidentcollector van ClusterDown twee runs achter elkaar terug met nul van de 27 eventkanalen van dit cluster. Per kanaal meten liet zien waarom: op deze nodes had PowerShells Get-WinEvent ongeveer 70 milliseconden per event nodig op de twee SMB-clientkanalen, terwijl dezelfde events direct lezen minder dan een milliseconde kostte. Twee kleine logs slokten het hele tijdbudget op. De collector werd gerepareerd, en het volgende pakket las elke node volledig. Je eigen lab stukmaken is hoe je ontdekt wat je gereedschap doet als het erop aankomt.
Veelgestelde vragen
Hij laat de server niet crashen, maar pauzeert hem wel terwijl het geheugen wordt vastgelegd. Op dit cluster met twee nodes en vier processors per node duurde die pauze ongeveer 52 seconden, twee keer de heartbeat-tolerantie van het cluster. Draineer de node eerst met Suspend-ClusterNode -Drain, dan reageert het cluster niet als hij stil wordt.
Omdat het cluster correct reageerde. Een node die 52 seconden niet antwoordt, hoort als weg te worden behandeld. De drempel verhogen om een zelf veroorzaakte pauze te verbergen, vertraagt ook de reactie op een echte storing.
Alleen als de methode het rapport tegen zijn schrijver beschermt. Hier gold de regel dat niets in het rapport kwam tenzij het bewijspakket het aantoonde, en het bekende antwoord werd apart vastgelegd, zodat een reviewer de conclusie ertegen kon toetsen. Het rapport kon nog steeds niet zeggen wie de dump startte, want dat stond niet in het bewijs. Juist die beperking bewijst dat de regel werd gevolgd.
Een managementsamenvatting boven een technisch rapport laat de beheerder in het midden achter met een document dat voor iemand anders is geschreven. De beheerder heeft de stappen, de lijst van uitgesloten oorzaken en de opdrachten nodig, in gewone woorden. De manager heeft alleen de samenvatting nodig. De engineer heeft het bewijsspoor nodig. Eén document kan de manager en de beheerder samen bedienen; de engineer verdient de volledige versie.
Bij ClusterDown.com, of klik in het menu van deze site op Clusterproblemen?. Eén script, één zipbestand terug, en gratis de vijf belangrijkste issues; een volledige root cause analysis is de volgende stap als u die nodig hebt.