Vi har brukt Proxmox VE i mange år, og det er ingen overdrivelse å si at vi er begeistret for løsningen. Det er en komplett plattform med åpen kildekode for administrasjon av server-virtualisering, og funksjonene gir oss den fleksibiliteten vi er avhengige av i det daglige. Ikke minst gjør detaljgraden at vi kan gå skikkelig i dybden når det oppstår problemer.
Den 3. september 2026 var vi ekstra glade for denne muligheten, fordi alle nodene i en av Proxmox-klyngene våre uventet omstartet nesten samtidig.
Ja, du leste riktig. Hele klyngen gikk ned.
Dette var en klynge som var designet nettopp for å tåle svikt i én enkelt node, så vi måtte finne ut hva som hadde skjedd.
Vår umiddelbare prioritet var å få tjenestene opp igjen. Vi deaktiverte High Availability (HA) og fikk de berørte tjenestene tilbake på nett på noen få timer, før vi fortsatte arbeidet med å finne årsaken til hendelsen.
I løpet av prosessen var vi innom Proxmox HA, Corosync, KNET, nettverkslaget i Linux og til slutt mottakskøene på et 25 GbE nettverksgrensesnitt. Underveis fant vi flere ting som så ut som mulige årsaker, og ganske mange av dem viste seg å være reelle problemer.
Det som til slutt ble tydelig var hvordan én nettverkshendelse hadde spredt seg gjennom flere lag i systemet, helt til selve kommunikasjonen mellom klyngene ble påvirket.
Det avdekket også en svakhet i måten vi hadde skilt klyngekommunikasjonen fra kundetrafikken på, og som følge av dette endrer vi nå arkitekturen.
Vi mener at feilsøkingsprosessen og konklusjonen er verdt å dele, både på grunn av det som skjedde og på grunn av det vi lærte om hvordan feil kan spre seg i et miljø med høy tilgjengelighet.
Hvorfor startet hele klyngen på nytt?
Hver fysisk server er en node som fungerer som en hypervisor og stiller prosessortid, minne og nettverkstilgang til rådighet for de virtuelle maskinene. Flere noder som samarbeider danner et klynge.
Vår første mistanke var at feilen skyldtes High Availability (HA) og fencing.
HA overvåker nodene og håndterer gjenoppretting når maskinvare eller tjenester svikter. Før klyngen kan handle må imidlertid medlemmene enes om hvilke av dem som fortsatt er til stede.
Dette gjøres ved hjelp av quorum: det kreves et flertall av stemmene før en gruppe noder får lov til å treffe beslutninger. Dette forhindrer at to adskilte deler av en klynge begge tror at de har kontrollen.
Fencing håndterer en node som ikke lenger kan delta på en pålitelig måte. På en HA-node med en aktiv watchdog kan tap av quorum over lengre tid føre til at watchdog-tiden utløper, og dette vil tvinge frem en omstart. Dette hindrer noden i å fortsette å kjøre en virtuell maskin som en annen node kanskje er i ferd med å starte et annet sted.
At én node omstarter seg selv under slike forhold kan derfor bety at systemet fungerer akkurat slik det er ment.
Normalt sett ville vi forvente at en feil ser omtrent slik ut:
Sunn klynge
|
+-- En node blir ustabil
|
+-- Den aktuelle noden blir ekskludert eller avskjermet
|
`-- Resten av klyngen beholder quorum
og fortsetter normal drift
Klyngen vår hadde tilstrekkelig redundans til å tåle svikt i den aktuelle hypervisoren. I dette tilfellet startet imidlertid alle nodene på nytt. Feilen skyldtes altså åpenbart ikke at én node hadde forsvunnet.
Corosync oppførte seg merkelig
Det neste vi undersøkte var Corosync. Corosync er det som gjør at nodene utveksler statusinformasjon og blir enige om medlemskap i klyngen, mens KNET overfører disse meldingene og overvåker tilkoblingen mellom dem.
Loggene viste ustabil Corosync-kommunikasjon rundt én bestemt node. KNET rapporterte om tilkoblingsfeil, og det virket som om de ulike klyngemedlemmene ikke alltid var enige om hvem som kunne kommunisere med hvem.
Vi opplevde både pakketap, der deler av nettverkstrafikken aldri kom fram, og asymmetrisk tilkobling, der én node kan “høre” en annen, men kommunikasjonen i motsatt retning ikke nødvendigvis fungerer.
Klyngeprogramvare har mye vanskeligere for å håndtere denne typen delvis svikt enn en fullstendig frakobling. Hvis en server forsvinner helt er situasjonen ganske klar. Hvis den derimot fortsatt er til stede og fortsetter å utveksle noe trafikk, mens andre meldinger går tapt, kan ulike medlemmer av klyngen ende opp med ulike oppfatninger av hva som skjer.
Her var det at vi virkelig måtte dykke ned i dybden.
Vi så ikke skogen for bare trær
På dette tidspunktet beveget feilsøkingen seg bort fra klyngeprogramvaren og inn i nettverkslaget i Linux.
Vi jobbet oss gjennom Corosync og KNET, deretter tilkoblingssporing, fordeling av avbrudd, NUMA-topologi, softirqs og måten nettverkskortet fordelte innkommende trafikk på.
Det var en kilde til frustrasjon at hvert lag ga oss noe interessant å undersøke og vurdere som potensiell underliggende årsak.
Vi klarte å gjenskape betydelige pakketap mellom medlemmene i klyngen. Nettverkskortet rapporterte et stort antall RX-misser og forkastede pakker i mottaksringen. Det hjalp å øke størrelsen på mottaksringen, men problemet forsvant ikke.
I løpet av én test forkastet en enkelt mottakskø mer enn 500 000 pakker på ti sekunder.
På det tidspunktet visste vi hvor pakkene forsvant, men vi forsto fortsatt ikke hva som la så stor belastning på grensesnittet.
Til slutt så vi på grafene for switch-portene.
Det var to tall som umiddelbart fanget oppmerksomheten:
- Rundt 22 Gbit/s innkommende trafikk på et grensesnitt med en nominell kapasitet på 25 GbE.
- Én oppgave på hypervisoren som til tider mottok nær to millioner pakker per sekund.
Oi.
Plutselig var det ganske mye av det vi hadde sett som begynte å gi mer mening.
Ironisk nok fungerte nettverket helt utmerket
Det er en litt morsom grunn til at dette ikke var opplagt fra starten av: resten av nettverket vårt brydde seg nemlig ikke noe særlig om det.
Trafikken passerte gjennom svitsjene og ruterne våre uten å forårsake noen nevneverdig nettverkshendelse. Nettverket leverte ganske enkelt trafikken til mottaker som normalt.
Problemet befant seg på ankomststedet.
25 GbE-grensesnittet på hypervisoren og nettverksstakken på verten ble belastet så tungt at pakker begynte å bli forkastet. Corosync-kommunikasjonen brukte det samme fysiske grensesnittet og noen av de samme underliggende ressursene, og dermed ble også klyngetrafikken påvirket.
Da vi fjernet den problematiske trafikken, ble sammenhengen mellom belastningen på grensesnittet og ustabiliteten i Corosync straks mer åpenlys.
Selve hendelsesforløpet var det viktigste
At et nettverksgrensesnitt får problemer når det blir konfrontert med svært stor trafikk, er i seg selv ikke noe veldig overraskende teknisk funn.
Det som var mest interessant for oss var hvordan problemet hadde spredt seg gjennom systemet:
Ekstrem trafikk til én oppgave
↓
Hypervisor-grensesnittet utsettes for stor belastning
↓
Pakker begynner å gå tapt
↓
Corosync-kommunikasjonen svekkes
↓
Klyngemedlemmene får ikke lenger et oversiktlig bilde av helheten
↓
HA / watchdog-atferd følger
↓
Alle nodene i klyngen omstartes
Vi holder fortsatt på med å kartlegge den nøyaktige HA- og watchdog-sekvensen som førte til at alle nodene omstartet, så vi ønsker ikke å uttrykke større sikkerhet om den siste delen enn vi faktisk har.
På dette tidspunktet visste vi imidlertid nok til å identifisere den underliggende årsaken. Trafikk som påvirket én enkelt kundes virtuelle maskin hadde klart å forstyrre kommunikasjonen som klyngen var avhengig av for å forstå sin egen tilstand.
For oss var dette den viktigste erkjennelsen vi tok med oss fra hendelsen. Et problem i det brukerrettede nettverket hadde fått lov til å nå hele klyngens kontrollplan.
Hvorfor kunne ikke VLAN-et beskytte Corosync?
Kundetrafikken og klyngetrafikken var allerede skilt fra hverandre ved hjelp av virtuelle lokale nettverk (VLAN-er).
Sett fra et nettverkskonfigurasjons-perspektiv var de to trafikktypene adskilt. Fysisk sett var de imidlertid fortsatt avhengige av det samme nettverksgrensesnittet, de samme mottakskøene og deler av den samme prosesseringskapasiteten.
Hendelsen gjorde det veldig tydelig hva som skiller logisk separasjon fra separasjon basert på mulige feilkilder.
Et VLAN kan holde to typer trafikk logisk adskilt selv om de deler utstyr. Men hvis det fysiske grensesnittet som ligger til grunn for begge VLAN-ene begynner å miste pakker, kan ikke VLAN-et i seg selv beskytte Corosync.
Vi hadde separert trafikken, men vi hadde ikke sørget for at de to nettverkene kunne feile uavhengig av hverandre.
Det endrer vi på nå.
Planlagte systemforbedringer
Vi gjennomfører flere endringer som følge av denne hendelsen.
Corosync får sine egne fysiske nettverk
Den viktigste endringen er at vi flytter Corosync over på separate fysiske nettverk, med egne grensesnitt og egen nettverksinfrastruktur.
Løsningen vil også omfatte reservenettverk for Corosync, slik at klyngen får en ekstra, uavhengig kommunikasjonsvei dersom den primære skulle svikte.
Corosync trenger ikke voldsomt mye båndbredde. Det som kreves er pålitelig pakkelevering, forutsigbar latens og en rute som ikke påvirkes av hva som måtte skje i det kunderettede nettverket.
Hensikten med endringen er derfor ikke først og fremst å øke kapasiteten, men å fjerne den felles avhengigheten.
Kundetrafikk
|
`-- Kunderettet nettverk
Klyngekommunikasjon
|
+-- Dedikert Corosync-nettverk
|
`-- Uavhengig reserveløsning
Hvis et grensesnitt mot kundene blir overbelastet skal Corosync fortsette å kommunisere via infrastruktur som ikke er berørt av dette. Hvis det primære Corosync-nettverket svikter, skal reservenettverket sørge for at klyngen kan fortsette å kommunisere.
Dette er den modellen vi ønsker.
Signalene var der, men vi så ikke sammenhengen
Det er også et annet, litt pinlig aspekt ved historien.
Overvåkingssystemet vårt oppdaget den uvanlige trafikken og utløste varsler da dette skjedde. Under en pågående hendelse som involverte omstart av klynger, Corosync-feil, tilkoblingsproblemer og pakketap, var det imidlertid mange andre ting som krevde oppmerksomhet.
Vi rettet naturlig nok oppmerksomheten mot det alvorligste symptomet, og begynte med å prøve å finne ut hvorfor en hel HA-klynge nettopp hadde omstartet.
I etterpåklokskapens lys pekte nettverksvarslene allerede på en viktig del av problemet.
Løsningen ligger imidlertid ikke i å generere flere varsler. Når en hendelse allerede er preget av mye støy, kan flere uavhengige varsler gjøre det vanskeligere å forstå hvilke hendelser som faktisk henger sammen.
Derfor endrer vi heller hvordan vi sammenstiller og prioriterer den informasjonen vi allerede samler inn. Hvis en hypervisor plutselig registrerer ekstrem trafikk samtidig som Corosync begynner å rapportere om tilkoblingsproblemer, bør disse hendelsene nå ingeniøren som relaterte signaler, i stedet for som to separate varsler som konkurrerer om oppmerksomheten.
Overvåkingssystemet hadde oppdaget trærne. Vi hadde bare ikke funnet skogen ennå.
Vi tester de styggeste feilene
Hendelsen minnet oss også om at feil i infrastrukturen ikke alltid opptrer på åpenbare måter. Noen ganger er feilene merkelige, uforutsigbare og kaotiske, akkurat som mennesker kan være.
Det er relativt enkelt å teste hva som skjer når en server mister strømmen eller noen trekker ut en nettverkskabel. I slike tilfeller er feilen tydelig, og du kan kontrollere at klyngen reagerer som du forventer.
Det som skjedde her var atskillig mer rotete. En forbindelse kan miste pakker i det stille selv om den fortsatt er oppe, kommunikasjonen kan bli asymmetrisk, og en vert kan være overbelastet uten at den likevel går helt offline.
Slikt er vanskeligere å forutse, men det er også nettopp denne typen situasjoner som et system med høy tilgjengelighet må kunne håndtere.
Derfor skal vi bevisst teste scenarier som omfatter:
- Pakketap mens nettverksforbindelsene fortsatt fungerer
- Asymmetrisk tilkobling mellom klyngemedlemmer
- Overbelastning av kunderettede grensesnitt
- Svikt i det primære Corosync-nettverket
- Fallback mellom uavhengige Corosync-baner
Høy tilgjengelighet skal ikke bare fungere når feilen skyldes at en server går offline eller at en kabel blir koblet fra. Stor trafikk som påvirker én oppgave må holdes isolert, og klyngen må fortsette å kommunisere selv når feilen er fragmentert, asymmetrisk eller vanskelig å tolke.
Hvorfor offentliggjør vi denne informasjonen?
Vi kunne ha fikset problemet i stillhet uten noe mer om og men, eller publisert den vanlige oppsummeringen der vi opplyste at det hadde oppstått en infrastrukturhendelse, at årsaken var identifisert og at korrigerende tiltak var iverksatt.
Det hadde ingen av oss lært særlig mye av.
Å drifte infrastruktur innebærer å håndtere maskinvare som svikter og programvare som av og til byr på overraskelser. Innimellom kan systemene oppføre seg normalt hver for seg, men i samspillet skjer det likevel noe som ingen hadde forutsett.
Det som teller i etterkant er å forstå hva som skjedde, finne svakheten som ble avdekket og endre logikken slik at det samme hendelsesforløpet ikke vil skje igjen.
For oss er prinsippet som følger av denne hendelsen ganske enkelt:
En svikt på kundenivå skal ikke føre til feil på klyngenivå.
Vi endrer arkitekturen i tråd med dette.
Vi er fortsatt glade i Proxmox!
Undersøkelsen bekreftet også en av grunnene til at vi har brukt Proxmox i så lang tid.
Takket være detaljnivået kunne vi starte med et ganske enkelt spørsmål (hvorfor startet hele klyngen på nytt?) og så gå stadig dypere, gjennom Proxmox HA, Corosync og KNET, videre inn i nettverkslaget i Linux og til slutt helt ned til de enkelte mottakskøene på nettverksgrensesnittet.
Denne typen innsikt er svært verdifull når man har ansvaret for infrastruktur som andre bedrifter er avhengige av.
Vi har lært noe nyttig om vår egen arkitektur, og dette vil få direkte innvirkning på hvordan vi utvikler, tester og forbedrer klyngene våre.
Det er også en betydelig enklere lærdom å trekke av hele denne opplevelsen.
Hvis alle nodene i et Proxmox-klynge på mystisk vis har omstartet, og du har brukt flere timer på å undersøke Corosync, KNET, NUMA-topologi, Linux softirqs og mottakskøer på nettverkskortene …
… kanskje du bør ta en titt på grafene for switch-portene?
Det gjør vi garantert neste gang. 🙂
Det tekniske teamet hos ServeTheWorld