...

Hukommelsespres i Linux-kernen: Konsekvenser for hostingsystemer

Hukommelsespres i Linux-kernen rammer hosting-systemer direkte: Når presset stiger, flyttes CPU-tid og I/O over til ressourcekrævende Reclaim, responstiderne stiger, og risikoen for OOM-fejl øges. Jeg viser tydeligt, hvordan jeg identificerer, måler og afbøder hukommelsespres, så Hosting-Reagere løbende på arbejdsbelastninger.

Centrale punkter

Jeg fokuserer på de afgørende faktorer, der i hostingmiljøer er afgørende for ydeevne og nedbrud. De følgende punkter udgør den røde tråd, som jeg baserer min diagnose og optimering på. Med dette overblik undgår jeg fejlagtige fortolkninger af „fuld RAM“ og identificerer reelle Tryk i god tid.

  • PSI-målinger viser ventetider i stedet for blot belægning og afslører forsinkelser på et tidligt tidspunkt.
  • Swap-belastning indikerer Reclaim-problemer, der forværrer I/O og latenstider.
  • Cgroups-grænser Styring af begrænsning, beskyttelse og OOM-adfærd pr. tjeneste.
  • Cache-fortrængning har en direkte indflydelse på web- og databaseydelsen.
  • Planlægning af kapacitet og tuning sikrer headroom og forhindrer thrashing.

På den måde strukturerer jeg mine analyser fra kernen til applikationen og gennemfører passende tiltag i prioriteret rækkefølge. Fokus forbliver på målbare Effekter, ikke på arbejde på afbetaling.

Hvad betyder »memory pressure« i Linux-kernen?

Memory-Druck betyder, at kernen bruger mærkbar tid på at frigøre hukommelse i stedet for at fortsætte brugerprocessernes arbejde; CPU’en bruger da i stigende grad tid på scanninger, skrivninger og evictions, mens anmodninger venter. Jeg skelner klart mellem „fuld RAM“ og „mangel på brugbar Headroom“: En „fuld“ cache er sund; flaskehalse opstår først, når Reclaim-investeringerne stiger. Kernen scanner inaktive lister og skriver beskidt-sider, sletter filcachen og flytter anonyme sider ud, så snart vandmærkerne overskrides. Det afgørende er den tid, der bruges på disse aktiviteter; den afspejles i opgavernes ventetider og forlængede svartider. En host kan køre stille ved 95 % %-udnyttelse, så længe cachen let kan genvindes, men kan gå i stå kraftigt ved lav udnyttelse, hvis aktive anonyme sider skal fortrænges.

At forstå og måle PSI

Pressure Stall Information (PSI) gør Memory Pressure håndgribeligt, fordi jeg ikke måler belastningen, men forsinkelserne. I /proc/tryk/hukommelse Jeg ser „some“ og „full“: „some“ beskriver perioder, hvor mindst én opgave venter på hukommelse, mens „full“ angiver perioder, hvor alle opgaver står i kø. Eksempel: „some avg10=4.67“ betyder, at der i de sidste 10 sekunder var 4,67 % af tiden, hvor der opstod afbrydelser på grund af hukommelsesflaskehalse; „full avg10=0.30“ indikerer sjældne fuldstændige afbrydelser. Jeg sammenholder stigende „some“-værdier tidligt med responstider og skalerer, finjusterer eller aflaster, inden der opstår alvorlige OOM-fejl. Denne tilgang forhindrer mig i at lade mig vildlede af tilsyneladende „høj ledig“ RAM, da ledige sider uden hurtig Reclaim-udnytter muligheden kun i begrænset omfang.

Målt variabel Vejledende værdi Symptom Handling
PSI-hukommelse (nogle) (avg10) > 2–3 % vedvarende Svarstiderne stiger Kontroller RAM-headroom, finjuster Cgroup-grænser
PSI-hukommelse fuld (avg10) > 0,1 % mærkbart Korte dødtider Identificer årsagen, stop thrashing
MemAvailable < 10 % af RAM'en Lille buffer Aflaste cache/arbejdsbelastning, planlægge kapacitet
vmstat mandag/søndag konstant > 0 Swap-tryk Tilpas Swappiness/Swap, beskyt Hotset

Symptomer i hostingmiljøer

På travle servere ser jeg først spidsbelastninger i latenstiden, mens CPU-belastningen tilsyneladende forbliver moderat; kernen kører i »reclaim«-sløjfer, I/O hober sig op, og anmodninger står i kø. Den gennemsnitlige belastning stiger, selvom kernerne ser ud til at være ledige, fordi mange opgaver blokerer på hukommelsen eller I/O; dette er et tydeligt tegn på øget Tryk. Vedvarende si/so-værdier i vmstat viser, at systemet aktivt udfører swapping, hvilket bremser TLS-håndtryk, dynamisk indhold og forespørgselsstier. Hvis dette ikke løses, går systemet i thrashing: CPU’en bruger størstedelen af tiden på paging og swapping i stedet for at udføre nyttigt arbejde. I den eskalerende situation griber OOM-killer ind og afslutter processer med høj score; en målrettet Analyse af OOM-Killer hjælper mig med at opdage mønstre og fejlkonfigurationer.

Relevans for hosting-workloads og cgroups

I fællesdriftede miljøer er det nok med enkelte ressourcekrævende applikationer til at øge ventetiderne for mange kunder; cgroups mindsker virkningerne, men de kan ikke redde et system, der er forkert dimensioneret Forekomster. I VPS- og cloud-instanser fører begrænset RAM eller en dårlig swap-strategi hurtigere til belastningsspidser; isolering beskytter andre, men ikke ens egen tjeneste. Databaser er afhængige af store bufferpuljer; hvis Reclaim fortrænger disse, eller swap træder i kraft, stiger forespørgselstiderne, og gennemløbshastigheden falder markant. Containerorkestreringer bruger memory.low, memory.high og memory.max til at beskytte vigtige tjenester, dæmpe fastlåsninger og i nødstilfælde afslutte dem målrettet. Jeg vælger derfor bevidst grænser og overvåger PSI pr. tjeneste for at kunne gribe ind i tide og sikre reserver til kritiske Arbejdsbyrder skal holdes fri.

Overvågningsstrategi og måleparametre

Jeg tjekker MemAvailable, Buffers og Cached for at få et overblik over, hvor meget hukommelse der kan frigøres på kort sigt; rene MemFree-værdier kan let være vildledende. Samtidig kigger jeg på vmstat: Vedvarende si/so-værdier tyder på swap-pres, som sætter I/O i højt gear og øger latenstiderne; for baggrundsinformation om Udnyttelse af swaps Jeg bruger gennemprøvede diagnosemønstre. PSI giver mig den manglende brik, fordi „some“ og „full“ kvantificerer reelle forsinkelser; jeg udløser alarmer ved tærskelværdier og skelner mellem belastningsspidser og kroniske flaskehalse. Tidsserier via sar eller observability-stakken synliggør mønstre og hjælper mig med at bekræfte resultaterne af finjusteringen. dmesg afslører OOM-hændelser, der peger på hårde grænser eller fejlkonfigurationer; på den måde opbygger jeg et sammenhængende billede ud fra kernelperspektivet, I/O-adfærd og Anvendelse.

Typiske arbejdsbelastninger under pres

Webservere som Nginx eller Apache leverer indhold langsommere, når Reclaim og Swap kører i baggrunden; Keep-Alive-forbindelser forbliver åbne længere, hvilket forværrer køerne. PHP- og Python-stakke optager RAM gennem framework-caches, JIT-komponenter og sessionsdata; ved fortrængning pendler disse data mellem RAM og lagerplads og forlænger svarstiderne markant. Databaser mister hastighed, så snart bufferpuljer krymper, eller dele ender på swap; selv en lille ekstra latenstid pr. I/O løber op, når der er mange Forespørgsler. Caching-tjenester som Redis eller Memcached er afhængige af RAM-hit; hvis nøgleområder ender på swap, forsvinder fordelen, og risikoen for at blive afbrudt under belastning stiger. I alle tilfælde giver PSI- og swap-metrikker de tydeligste tegn på, at hukommelsen er blevet en flaskehals, og ikke CPU.

Systemoptimering og kerneparametre

Jeg starter med vm.swappiness: En moderat reduceret indstilling forhindrer overdreven brug af swap uden at blokere nødvendig genvinding af plads; jeg måler konsekvent effekterne med PSI. Derefter optimerer jeg vm.dirty_ratio og relaterede grænseværdier, så jeg ikke udløser lange flush-bølger og alligevel ikke fremprovokerer en voldsom skrivning af små data; begge dele har mærkbare Effekter på ventetider. I Cgroups v2 indstiller jeg memory.low til kritiske tjenester, memory.high til begrænsning ved overbelastning og memory.max som en fast grænse med kontrollerbare OOM-tilstande. Jeg er særlig opmærksom på NUMA-topologier: Der kan opstå lokal belastning, selvom der globalt set stadig er ledig RAM; proces- og hukommelsesbinding afbøder sådanne faldgruber. Til sidst tjekker jeg sidecache-adfærd; unødvendig fortrængning sænker hit-raterne og koster direkte tid ved web- og DB-arbejdsbelastninger, hvorved Optimering af sidecachen giver nyttige indsigter.

Et indgående kig på Reclaim-stier

For at kunne vælge de rette foranstaltninger skelner jeg mellem kswapd og Direkte genvinding. kswapd fungerer asynkront, når vandmærkerne underskrides; den er relativt skånsom, så længe der findes tilstrækkelig cache, der let kan genvindes. Direct Reclaim griber synkront ind i eksekveringskontekster, når tråde har akut brug for sider – det er her, de forsinkelser opstår, som brugerne kan mærke. Jeg observerer, om frigørelsen primært rammer filcache eller anonyme sider: Hvis kernen primært fortrænger filcache, stiger antallet af cache-misses; hvis den fortrænger anonym hukommelse (f.eks. heap), er der risiko for hårde stop og swap-aktivitet. Moderne working-set-mekanismer tager højde for refault-afstande for at beholde nyttige sider længere; hvis jeg alligevel ser mange gentagne refaults, ved jeg, at hotsets er større end den tilgængelige Headroom er blevet.

Derudover tager jeg højde for komprimering og defragmentering: kcompactd forsøger at skabe sammenhængende områder, f.eks. til store tildelinger eller THP. Hvis komprimeringen halter bagefter, ser jeg øget CPU-udnyttelse i kcompactd, stigende ventetider og øget andel af „fuld“ PSI ved belastningstoppe. I sådanne tilfælde er det ofte mere fornuftigt at sænke trykket eller justere THP-politikkerne i stedet for blot at give „mere swap“.

Swap-strategier i detaljer

Swap er ikke en fjende, men et værktøj – men hvis det bruges forkert, kan det forværre ventetiden. Jeg skelner mellem:

  • Ingen swap: Sikker mod swap-forsinkelser, men risikabel ved spidsbelastninger – OOM-fejl opstår tidligere, og Reclaim har ingen reservebuffer.
  • Moderat swap på en hurtig SSD: Godt til at flytte sjældent anvendte, anonyme sider til swap; beskytter hotsets i RAM, hvis swappiness og cgroup-grænser er indstillet fornuftigt.
  • zswap/zram: Komprimering aflaster I/O; egnet til værter med lavere I/O-belastning eller som buffer mod kortvarige belastningsspidser. Jeg tjekker CPU-kapaciteten og komprimeringsgraden for at undgå, at systemet bliver bremset af CPU’en.

Jeg indstiller ikke swappiness til et generelt lavt niveau; ved arbejdsbelastninger med en stor filcache er det fornuftigt at have en lidt højere swappiness for at skubbe kolde, anonyme sider væk og holde filcachen stabil. Kritiske tjenester (f.eks. databaser) beskytter jeg med `memory.low` og om nødvendigt ved at låse deres hotsets i RAM, så swap ikke rammer de forkerte områder. Det afgørende er, at vmstat mandag/søndag og PSI falder konsekvent, når jeg justerer strategien; ellers foretager jeg en korrektion.

THP, komprimering og fragmentering

Gennemsigtige store sider (THP) De sparer TLB-hits og hjælper CPU-tunge, hukommelseskrævende applikationer. Under belastning medfører de dog komprimeringsarbejde; „always“ kan i så fald føre til store afbrydelser. Jeg bruger „madvise“ målrettet til arbejdsbelastninger, der drager fordel heraf (f.eks. visse in-memory-motorer), og for latenstfølsomme web-stacks foretrækker jeg at deaktivere THP målrettet eller kun aktivere det via madvise. Derudover observerer jeg vm.compaction_proactiveness og undersøg, om proaktiv komprimering blot udskyder stalden eller rent faktisk reducerer den. Hvis THP-siderne ofte bliver skåret i stykker, eller hvis komprimeringen kører for varmt, tyder det på, at der er for lidt Headroom eller uhensigtsmæssige fordelingsmønstre i applikationen.

NUMA-fælder og lokal belastning

På NUMA-værter er den globale „ledige RAM“ vildledende: Et socket kan være under pres, mens et andet forbliver uudnyttet. Jeg tjekker NUMA-statistikker og forankrer processer lokalt (CPU-/hukommelsesbinding), så hotsets forbliver tæt på regnebelastningen. Direct Reclaim på en node på trods af globale reserver indikerer NUMA-ubalancer; her hjælper interleaved-allokeringer til bredt spredte tjenester eller streng binding til monolitiske arbejdsbelastninger. PSI pr. cgroup kombineret med NUMA-statistikker viser mig, om en enkelt node genererer køerne.

Foranstaltninger tæt på anvendelsen

Jeg analyserer hukommelsesprofiler med ps, top, htop og profileringsværktøjer for at finde de virkelige hukommelsesslugere og lækager; i den forbindelse holder jeg øje med, hvordan hotsets ændrer sig over tid. Jeg vælger applikationscacher bevidst: Er de for store, skaber det pres; er de for små, går hastighed tabt; jeg justerer med udgangspunkt i PSI og responstider, ikke på mavefornemmelse. Når der opfanges belastningssignaler, kan applikationen frivilligt frigive mindre kritiske cacher eller midlertidige data; på den måde reducerer jeg afbrydelser uden at røre ved globale grænser. Jeg tilpasser startparametre og GC-tuning (f.eks. for JVM’er) således, at working sets holdes pænt inden for RAM’en; aggressive allokeringsmønstre afbøder jeg ved hjælp af batching. Jeg holder også øje med build-artefakter og debug-symboler, for oversete rester koster skjulte omkostninger Hukommelse og øger risikoen for senere stall.

Cgroups v2-finesser og OOM-strategier

Med Cgroups v2 adskiller jeg beskyttelse, begrænsning og hårde grænser tydeligt: hukommelse.lav reserverer headroom til kritiske tjenester; den øvrige Reclaim tildeles mindre vigtige grupper. hukommelse.høj begrænser ydeevnen ved overskridelse gennem målrettet begrænsning og tvinger applikationer til at frigive hukommelse, før systemet påvirkes negativt. hukommelse.max er den sidste forsvarslinje – overskrides den, betyder det OOM inden for de fastlagte rammer. Jeg indstiller PSI pr. cgroup, så alarmer udløses dér, hvor der opstår fastlåsninger; den globale PSI forbliver stabil, mens en enkelt tjeneste bryder sammen – det er netop dette mønster, jeg ønsker at identificere. Sammen med OOM-prioriteter fastlægger jeg klare regler for, hvad der skal ofres: uvigtige batch-workere lukkes ned først, mens kerne-API’er bevarer deres Headroom.

Virtualisering: Ballooning, KSM og Overcommit

I virtualiserede miljøer står jeg over for et dobbelt pres: Gæsten ser tilsyneladende ledig RAM, mens hypervisoren via Ballonflyvning fjerner. Dette spil øger Reclaim-omkostningerne for begge parter. Jeg måler PSI i gæsten og sammenholder det med hypervisor-metrikker; hvis PSI stiger ved ballooning-hændelser, har VM’en brug for mere garanteret kapacitet eller bedre cgroup-politikker i værten. KSM sparer RAM ved at deduplicere identiske sider, men belaster CPU’en; i hosting-opsætninger med mange ensartede VM’er kan det være en fordel, så længe den ekstra CPU-belastning ikke truer SLO’erne. Overcommit (f.eks. aggressiv tildeling af mange små VM'er) planlægger jeg kun med faste SLO-reserver og strengt hukommelse.lav til systemer, hvor ventetiden er afgørende.

Arkitektoniske valg i forbindelse med hosting

Jeg satser på horisontal fordeling, så de enkelte instanser udsættes for færre belastningsspidser; skalerbare puljer dæmper udsving og holder latenstiderne på et lavere niveau. Jeg adskiller rollerne tydeligt: Databaser, applikationer og caching får hver deres egne ressourcepuljer, så reclaim-processer ikke skaber uventede bivirkninger på tværs af systemgrænser. Jeg vælger storage med fokus på skrivelatens, da dirty page flushes har direkte indflydelse på svartiderne; en hurtig sti reducerer reclaim-tiderne mærkbart. I klynger planlægger jeg RAM-reserver pr. node og styrer via scheduler-politikker, så belastning og hukommelsesforbrug forbliver jævnt fordelt. Jeg automatiserer skalering med PSI-tærskelværdier, så stigende „some“-værdier udløser handlinger, inden det kommer til fuldstændige nedbremsninger og Dræb-begivenheder.

Kapacitetsplanlægning og headroom-modeller

Jeg definerer headroom på en målbar måde: Jeg sørger for tilstrækkelige reserver, så „some“-PSI under normale spidsbelastninger forbliver under definerede tærskelværdier, og „full“ praktisk talt ikke forekommer. Til dette bruger jeg percentiler (f.eks. 99. percentil af den timelige belastning) og planlægger 10–30 % ekstra RAM afhængigt af arbejdsbelastningens volatilitet. Databaser får større faste reserver, mens web-frontends skaleres mere dynamisk. Jeg kalibrerer rebound-tider: Hvor hurtigt falder PSI og si/so efter en spidsbelastning? Forbliver de forhøjede, er det et tegn på for små reserver eller en uhensigtsmæssig swap-/dirty-strategi. På den måde bliver kapacitetsplanlægning en løbende proces i stedet for en årlig skøn.

Alarm og SLO-styret tuning

Jeg kobler PSI sammen med bruger-SLO’er: Hvis „some avg10“ stiger samtidig med API-latenserne, griber jeg ind. Jeg inddeler alarmer i „gul“ (vedvarende 2–3 % „some“, „full“ tæt på 0) og „rød“ (over 5 % „some“ eller „full“ > 0,1 %). cgroup-baserede alarmer hjælper med at isolere den »støjende minoritet«. Derudover udløser jeg alarmer ved stigende dirty-køer og skrivningsventetider, så jeg kan udjævne dirty-bølger i tide. Målet er, at optimeringstiltag (swappiness, memory.high, cache-størrelser) skal være observerbare og reversible; jeg implementerer ændringer trinvist og sammenligner før/efter ved hjælp af de samme målinger.

Trin-for-trin-diagnose i hverdagen

Først tjekker jeg `free -h` og `MemAvailable`: Hvis værdien falder markant, leder jeg efter cacher, der med fordel kan frigives, og efter tjenester med voksende hotsets. Derefter kører jeg `vmstat` med korte intervaller for at identificere si/so-tendenser; vedvarende swapping bekræfter presset og fører mig til I/O-stien. Derefter læser jeg /proc/pressure/memory og analyserer „some“ og „full“ over 10, 60 og 300 sekunder; stigende gennemsnitsværdier knytter jeg direkte til observerede latenstider. dmesg viser mig OOM-spor og afslører, hvilke processer der senest har udløst eller været ramt af hukommelseskriser; herfra udleder jeg grænser og prioriteter for Cgroups. Ud fra alt dette danner jeg en hypotese, gennemfører små finjusteringer, verificerer via PSI og holder øje med Svartid på et øjeblik.

Runbooks og typiske årsagskæder

Der er nogle mønstre, jeg støder på igen og igen:

  • Backup- eller scanningsopgaver fortrænger sidecachen: Pludselig falder cache-hit-raterne, og web/DB bliver langsommere. Foranstaltning: Begræns jobbene (I/O-prioritet), flyt tidsvinduet, indstil »memory.high« for job-cgroupen, og beskyt sidecache-budgettet for de kritiske tjenester.
  • Sikkerhedshuller i worker-processer: Langsomt stigende anonym hukommelse, PSI „some“ stiger i løbet af flere timer. Foranstaltning: Identificer lækagen, indfør politikker for automatisk genstart/genbrug, fastsæt hukommelsesgrænser, så lækager ikke udgør en risiko for hele værten.
  • THP-relaterede stall-tilfælde: kcompactd-belastningen stiger under trafikspidser. Foranstaltning: Indstil THP til „madvise“, tilpas de berørte tjenester, kontroller komprimeringsparametrene, øg headroom.
  • NUMA-lokal udskrivning: En socket thrasher, selvom der er ledig global RAM. Løsning: Korrigér affiniteterne, brug interleave til bredt spredte arbejdsbelastninger, juster belastningsfordelingen i scheduleren.
  • Swap på langsomme diske: Hvis dette stiger, eksploderer svartiderne. Foranstaltning: Flyt swap til hurtigere lagerplads, vurder zswap/zram, finjuster swappiness og cgroup-politikker.

Hvert runbook afsluttes med en validering: Falder „some/full“, og stabiliserer latenstiderne sig? Hvis ikke, var antagelsen forkert eller ufuldstændig – så fortsætter jeg med at iterere.

Værktøjer og sporing i driften

Ud over de klassiske værktøjer fokuserer jeg på en mere dybdegående analyse: Jeg overvåger forholdet mellem sidecache og anon, sidefejlfrekvenser, refault-mønstre og writeback-køer. eBPF- og tracing-metoder viser mig præcist, hvor ventetiderne opstår – for eksempel langs reclaim-stierne, i writeback eller ved allokering af store blokke. For mig er det vigtigt med en ressourcebesparende instrumentering, der er egnet til produktion: korte aktiveringsvinduer, sampling i stedet for kontinuerlig registrering og en klar sammenhæng med applikationsmetrikker. På den måde finder jeg årsagerne, før jeg begynder at justere parametre i stor skala.

Hovedpunkter og næste skridt

Memory Pressure beskriver den tid, der går tabt på grund af hukommelsesmangel, ikke blot optaget RAM; jeg måler den med PSI, opdager tendenser tidligt og handler på baggrund af data. Hvis man ser MemAvailable, vmstat si/so, PSI og dmesg i sammenhæng, finder man de egentlige årsager til latenstop og thrashing. Ved hjælp af swappiness-, dirty- og cgroup-tuning reducerer jeg målrettet systemstop og sikrer vigtige tjenester deres Headroom. På arkitekturniveau dæmper horisontal fordeling, klart afgrænsede roller og hurtige lagringsstier konsekvenserne af enhver belastningsspids. I sidste ende er det afgørende, at jeg løbende kobler diagnose og modforanstaltninger sammen: måle, justere, måle igen – indtil ydeevnen og Stabilitet passer igen.

Aktuelle artikler

Serverrack med Linux-systemer og visualiseret lagerudnyttelse
Server og virtuelle maskiner

Sådan forstår du OOM Killer: Når Linux afslutter processer

Find ud af, hvordan OOM Killer i Linux fungerer, når der er mangel på hukommelse, hvordan den afslutter processer, og hvordan du som administrator i hostingmiljøer kan undgå out-of-memory-problemer ved hjælp af søgeordet »oom killer linux«.

Administratoren analyserer Journalctl-logfiler på en Linux-server i datacentret
Administration

Effektiv brug af journalctl: Fejlanalyse på Linux-servere

Lær, hvordan du bruger `journalctl` til effektiv fejlanalyse på Linux-servere. Ved hjælp af filtre for tid, tjeneste og prioritet kan du analysere Linux-logfiler på en struktureret måde og optimere din fejlfinding på serveren.