...

OOM Score en OOM Score Adjust uitgelegd in de context van hosting

Ik leg het uit OOM-score en OOM Score Adjust als concrete regelinstrumenten bij het beheer van de hostingomgeving: u bepaalt welke processen de Linux OOM-killer bij een tekort aan geheugen beëindigt en welke hij beschermt. Zo behoud ik de controle wanneer RAM schaars wordt en zorg ervoor dat essentiële diensten online blijven.

Centrale punten

Om je snel een overzicht te geven, vat ik de belangrijkste punten kort samen.

  • Prioriteit bij schaarste: de OOM-score bepaalt welk proces als eerste moet worden beëindigd.
  • Fijne controle met oom_score_adj: van -1000 (beschermen) tot +1000 (opofferen).
  • Dynamiek in plaats van een vaste waarde: de waarde verandert afhankelijk van de belasting en de configuratie.
  • Praktijk hosten: Bescherm kritieke diensten, beëindig liever niet-kritieke workers.
  • Oorzaken Oplossen: limieten, cgroups en RAM-planning controleren.

Hoe de Linux OOM-killer werkt

Bij hoge opslagdruk besluit de Linux-kernel welke processen hij beëindigt om het systeem responsief te houden. Ik zie daarbij hoe de Kernel aan elk proces een soort „Badness“ toekent, die sterk afhankelijk is van het huidige geheugengebruik. Als er onvoldoende RAM of swapruimte beschikbaar is, grijpt de OOM-killer in en beëindigt het proces met de hoogste score. Dit mechanisme voorkomt vastlopen, maar is geen vervanging voor een gedegen capaciteitsplanning op host- en serviceniveau. Ik bekijk de beslissing in het OOM-logboek en stel vast of een service opviel door een tekort aan geheugen of door een verkeerde configuratie.

De OOM-score begrijpen: dynamiek en schaal

Ik controleer de OOM-score van een proces in /proc/PID/oom_score en bekijk zo hoe kwetsbaar het op dit moment is. De schaal loopt in de praktijk van 0 tot 1000: hoe dichter bij 1000, hoe groter de kans dat het proces ten prooi valt aan de killer. Deze waarde geeft een momentopname weer, omdat piekbelastingen, cgroup-limieten en cachegroottes voortdurend veranderen. Daarom beoordeel ik de score nooit op zichzelf, maar altijd in de context van werkgeheugen, swap, overcommit en parallelle processen. Wie de score regelmatig bekijkt, herkent typische patronen en kan knelpunten voorzien voordat ze diensten uit de running halen.

De OOM-score doelgericht inzetten

Met oom_score_adj Ik pas de beoordeling van een proces actief aan van -1000 tot +1000. Als ik -1000 instel, bescherm ik het proces volledig, terwijl hoge positieve waarden het bewust kwetsbaar maken. Ik ga hier zuinig mee om, want te veel beschermde processen beperken de speelruimte van de OOM-killer. Typische kandidaten voor lage waarden zijn SSH, monitoring, reverse-proxy-frontends en gevoelige databasecontrollers. Achtergrondtaken, rapportageprogramma’s of kortstondige workers krijgen eerder een hogere instelling, zodat de gebruikersinterface blijft reageren als het krap wordt.

Prioriteiten stellen bij hosting

In productieve omgevingen stel ik duidelijke Prioriteiten tussen frontend, API, database en batchverwerking. Ik bepaal eerst welke diensten vanuit het oogpunt van de gebruiker actief moeten blijven en stel voor deze diensten een geschikte OOM-aanpassing in. In systemd stel ik hiervoor OOMScoreAdjust= in het service-unit-bestand in en documenteer ik het doel van elke waarde. Wie diensten sowieso via systemd beheert, kan processen stroomlijnen; een eerste stap hiertoe is systemd bij hosting. Zo neem ik maatregelen om storingen te voorkomen in plaats van ze aan het toeval over te laten, en zorg ik ervoor dat de gebruikersbegeleiding betrouwbaar online blijft.

Cgroups, containers en limieten

Ik zal nooit de cgroups, want containers en diensten bevinden zich in hun eigen resource-omgevingen. Een proces met een gematigde OOM-score kan toch afbreken als zijn cgroup een krappe geheugenlimiet heeft en het proces die limiet tijdelijk overschrijdt. Daarom controleer ik de limieten in cgroup v2 en stem ik harde en zachte limieten af op de belastingprofielen. Wie multi-tenancy of shared hosting aanbiedt, profiteert van zorgvuldig ingestelde quota’s en accounting; meer achtergrondinformatie vindt u cgroup v2 bij hosting. Als de onderlinge afstemming klopt, werken de OOM-afstelling en de limieten als een goed op elkaar afgestemd paar stelschroeven.

Diagnose en monitoring bij OOM-gebeurtenissen

Als er iets gebeurt, heb ik duidelijke Signalen en herhaalbaarheid bij de analyse. Ik analyseer dmesg, journald en /var/log/kern.log, sla de OOM-regels op en noteer de PID van het slachtoffer, samen met de oom_score en oom_score_adj. Voor routinecontroles gebruik ik scripts die de grootste geheugenverbruikers weergeven en waarschuwingsdrempels activeren. Wie zich hier verder in wil verdiepen, vindt een gestructureerde aanpak in de OOM-Killer-analyse. In permanente opstellingen neem ik statistieken zoals RSS, cache, swap-in/out en containerlimieten op in de monitoring, zodat ik trends tijdig kan herkennen.

Tabel met handige tips voor beheerders

Ik gebruik het volgende overzicht als beknopt Gids, wanneer ik rollen prioriteer en aanpassingen documenteer. De kolom „Motivering“ laat zien waarom een dienst bescherming of opofferingsbereidheid krijgt. Ik pas de cijfers aan het project aan, maar de richtlijn helpt bij het snel nemen van beslissingen. Wie de tabel als uitgangspunt gebruikt, krijgt meer duidelijkheid bij post-mortems en bij wijzigingsverzoeken. Belangrijk blijft: ik houd altijd een buffer in het totale systeem aan, zodat het zelden nodig is om functies volledig te schrappen.

Component Typische bestemming Voorbeeld oom_score_adj Reden
SSH-Daemon Schutters -500 tot -900 Zorg voor toegang voor ingrepen, zelfs bij knelpunten.
Reverse proxy (nginx/HAProxy) Schutters -300 tot -700 Inkomend verkeer verwerken, foutpagina’s weergeven.
DB-Controller/primaire instantie Schutters -200 tot -600 Verbindingen in stand houden, toegang tot gegevens waarborgen.
PHP-FPM/applicatie-workers Neutraal tot bereid tot opoffering 0 tot +300 Er kunnen veel parallelle workers uitvallen.
Batch/Back-up/Rapporten Bereid om offers te brengen +300 tot +800 Kan worden uitgesteld zonder gevolgen voor de gebruiker.
Indexeerder/wachtrijverwerker Bereid om offers te brengen +200 tot +600 Je kunt even pauzeren; je kunt het later inhalen.

WordPress- en PHP-workers op de juiste manier beperken

Bij WordPress let ik op Werknemer-Aantal, memory_limit en omvangrijke bewerkingen zoals beeldverwerking of importen. Ik stel PHP-FPM zo in dat het aantal actieve processen in verhouding staat tot het RAM-geheugen en geen lawine veroorzaakt. In de database tel ik de buffer- en cachegroottes bij elkaar op en houd ik nog wat speling over, zodat pieken niet alles blokkeren. Ik houd OpCache, de objectcache en de afbeeldingsoptimalisator in de gaten, omdat deze het geheugengebruik snel opdrijven. Zo zorg ik ervoor dat korte piekbelastingen niet meteen ten koste gaan van de belangrijke frontend-processen.

Praktijk: beleidsregels en handleidingen

Ik houd mijn Beleid beknopt en uitvoerbaar, zodat het team in geval van nood niet aarzelt. Dit omvat: het definiëren van beschermde processen, het benoemen van slachtofferrollen, het toevoegen van OOMScoreAdjust= aan systemd-units en het documenteren van de waarden in de repository. Ik test het effect met tools en testbelasting totdat de volgorde van de slachtoffers aansluit bij de doelstellingen. Daarna schrijf ik een playbook waarin logs, alarmering en eerste maatregelen worden beschreven. Zo blijft de reactie consistent, zelfs als nieuwe collega’s het overnemen.

# Voorbeeldfragment voor een systemd-unit
[Service]
OOMScoreAdjust=-400
# Opnieuw laden en herstarten:
# systemctl daemon-reload && systemctl restart nginx

# Continu controleren:
cat /proc/$(pidof nginx)/oom_score
cat /proc/$(pidof nginx)/oom_score_adj

# Tijdelijk verhogen/verlagen (root):
echo 300 | sudo tee /proc//oom_score_adj

Veelvoorkomende fouten en tegenmaatregelen

Veel problemen ontstaan omdat Grenzen kloppen niet: te veel PHP-workers, te grote DB-caches en geen ruimte voor piekbelasting. Dan grijpt de OOM-killer regelmatig in, terwijl een paar kleine aanpassingen al voldoende zouden zijn. Ik pas eerst het aantal workers aan, meet het effect en breid het RAM-geheugen pas uit als de behoefte daar duidelijk om vraagt. Ook het instellen van veel processen op -1000 is schadelijk, omdat de kernel speelruimte nodig heeft. Ik stel prioriteiten met gezond verstand, zodat het systeem in geval van nood op een geordende manier kan reageren.

Overcommit, swap en geheugengebruik

Ik stel mijn Overcommit-strategie bewust instellen, want dit bepaalt hoe snel een systeem in de OOM-zone terechtkomt. Met vm.overcommit_memory=0 (heuristiek) werk ik vaak stabiel, omdat de kernel de commit-limiet inschat op basis van het gebruik en de geschiedenis. Het wordt strenger met vm.overcommit_memory=2 in combinatie met vm.overcommit_ratio, waarmee de maximaal toegestane virtuele toewijzing wordt gedefinieerd. Wie vm.overcommit_memory=1 zonder meer instelt, loopt het risico dat geheugenreserveringen wel slagen, maar later bij het toewijzen hard mislukken – een veelvoorkomende oorzaak van OOM-incidenten onder belasting.

Ik kalibreer Wissel zodat het bufferruimte biedt, maar geen latency-killer wordt. Een gematigde vm.swappiness houdt het werkgeheugen vrij voor veelgebruikte paden, terwijl zelden gebruikte pagina’s worden verplaatst. Zswap of zram kan ik gebruiken als elastische buffer wanneer I/O traag is – dat verlaagt het OOM-risico, maar kost CPU-kracht. Ook de ‘waterpeilen’ zijn belangrijk: vm.min_free_kbytes moet voldoende hoog zijn, zodat de kernel tijdig geheugen kan terugwinnen. Wie te krap berekent, dwingt het systeem tot hectische terugwinning en veroorzaakt padlogica die tot OOM leidt.

# Voorbeeld: conservatieve overcommit en gematigd swappen
sysctl -w vm.overcommit_memory=2
sysctl -w vm.overcommit_ratio=90
sysctl -w vm.swappiness=30
# Voor tests permanent vastleggen in /etc/sysctl.d/

Systemd-opties naast OOMScoreAdjust

Naast OOMScoreAdjust gebruik ik systemd om Opslaggeleidingsplanken direct op de dienst in te stellen. Met MemoryMax= stel ik een harde limiet in (cgroup memory.max), MemoryHigh= remt zacht af bij hoge belasting en MemorySwapMax= beperkt het gebruik van de swapruimte. MemoryLow= en MemoryMin= geven bij hoge belasting prioriteit aan het cachegeheugen van een dienst, zodat belangrijke processen minder snel worden afgebremd. Samen met OOMPolicy= bepaal ik wat systemd bij OOM op unit-niveau onderneemt (bijv. alleen de dienst stoppen of hele afhankelijkheden beëindigen). In Slices groepeer ik rollen – web-frontend, batch, DB – en leid ik uniforme regels af, zodat individuele uitschieters het geheel niet destabiliseren.

Ik houd er rekening mee dat bescherming nooit absoluut is: zelfs processen met -1000 kunnen in uitzichtloze situaties moeten wijken. Daarom hanteer ik ruime, maar realistische Minima (MemoryLow/Min) alleen voor een zeer klein aantal kernservices en controleer of de som van alle toewijzingen onder de fysiek beschikbare geheugencapaciteit blijft. Zo voorkom ik dat goedbedoelde beschermingsmechanismen de OOM-killer verblinden.

Kubernetes en containerorkestratie

In orkestraties zoals Kubernetes speelt OOM-logica op verschillende niveaus een rol. Ik gebruik Verzoeken en Grenzen zodat pods in de gewenste QoS-klasse vallen: Guaranteed biedt de beste bescherming, Burstable vangt schommelingen op, BestEffort is het meest kwetsbaar. De kubelet wijst de daaruit voortvloeiende OOMScoreAdjust-waarden automatisch toe – ik plan dus op basis van resource-specificaties in plaats van handmatige afstemmingswaarden in de containers. Als een container zijn `memory.limit` bereikt, wordt hij binnen zijn cgroup beëindigd, zelfs als de host nog ruimte over heeft; dit is geen klassieke host-OOM, maar een gerichte zelfbescherming van de limiet.

Ik houd rekening met native geheugenaandelen buiten de heap-configuraties (bijvoorbeeld bij JVM/Node), zodat containers niet onverwachts tegen de limiet aanlopen. Daarnaast bereken ik pod-buffers voor pieken en plan ik node-overcommit slechts met mate, zodat evictions zeldzaam blijven. Als cgroup v2 actief is, gebruik ik memory.oom.group doelgericht, zodat in geval van nood een hele procesgroep op een geordende manier wordt afgebroken, in plaats van afzonderlijke workers in een zombie-pod achter te laten. Dit houdt het systeem schoon en maakt het herstel voorspelbaar.

Diagnostische diepgang: SMaps, PSI en reproduceerbare tests

Voor diepgaande analyses maak ik gebruik van /proc-Inzichten en drukstatistieken. /proc/PID/status toont VmRSS, VmSwap en threads; /proc/PID/smaps_rollup geeft een overzicht van aandeelcategorieën zoals Anon, File en Shmem, zonder dat ik me in details verlies. Zo kan ik zien of de paginacache misleidend is of dat anonieme pagina’s (echte werklast) toenemen. Met /proc/pressure/memory meet ik PSI-signalen, oftewel hoeveel tijd het systeem verliest door actieve reclaim of stalls. Ik geef een waarschuwing bij deze waarden, lang voordat OOM toeslaat – ideaal om automatisch tegenmaatregelen (throttling, schaalvergroting, vermindering van het aantal workers) in gang te zetten.

# Relevante momentopnames
journalctl -k -g "Out of memory|oom-killer"
cat /proc/pressure/memory
grep -E "VmRSS|VmSwap|Threads" /proc//status
cat /proc//smaps_rollup

# OOM reproduceren (testomgeving!)
stress-ng --vm 2 --vm-bytes 80% --timeout 30s

Speciale gevallen: JVM, Node.js en PHP in containers

JVM-Diensten vereisen aandacht, omdat naast de heap ook metaspace, thread-stacks, direct buffers en het gedrag van de native allocator een rol spelen. Ik stel de configuratie container-vriendelijk in met MaxRAMPercentage en stel een heap in die ruimte laat voor deze componenten. Bij hoge parallelliteit beperk ik thread-pools, omdat veel kleine stacks pijnlijk veel ruimte innemen. Voor Node.js pas ik –max-old-space-size aan de containerlimiet aan om harde kills te voorkomen. En bij PHP-FPM Ik bereken pm.max_children op basis van het RAM-geheugen, het gemiddelde verbruik per verzoek en memory_limit – plus een reserve voor caches en de webserver. Zo voorkom ik sluipende lawines die pas bij pieken zichtbaar worden.

Ik houd de Allocator-strategie Let op: glibc met veel arena’s kan bij workloads met veel threads het geheugen fragmenteren en het geheugengebruik opdrijven. Voor bepaalde diensten leveren jemalloc of tcmalloc consistentere pieken op; ik test dit gericht, documenteer het effect en rol het op gecontroleerde wijze uit. Daarnaast beperk ik tmpfs-mappen in de container, zodat uploads of tijdelijke bestanden niet ongemerkt het RAM-geheugen opslokken.

Tmpfs, Huge Pages en paginacache

tmpfs wordt vaak over het hoofd gezien: zonder maximale grootte groeit het tot een bepaald percentage van het RAM-geheugen, en plotseling is er elders geen ruimte meer. Ik koppel tmpfs met een bewust opgegeven `size=`-waarde, vooral bij build- of upload-paden. Transparante grote pagina's (THP) Fragmentatie en latentie spelen een rol; voor diensten waarbij latentie cruciaal is, gebruik ik vaak „madvise“, zodat alleen geschikte toewijzingen hiervan profiteren. KSM kan gegevens dedupliceren en opslagruimte besparen, maar kost wel CPU-vermogen – handig op ontwikkelingshosts; in prestatiepaden controleer ik het effect en de overhead.

De Paginacache is geen „verspild“ geheugen; het versnelt de I/O. Als ik het te agressief verdring of drop-caches als permanente maatregel gebruik, verplaats ik de kosten naar latentiepieken. Het is beter om geheugendoelstellingen per rol te definiëren en via cgroup-mechanismen (memory.high / memory.max) een eerlijke verdeling af te dwingen. Zo blijven hotsets van de belangrijke diensten in het RAM en komen OOM-situaties minder vaak voor.

Samenvatting voor het dagelijks leven

Ik gebruik de OOM-score als barometer voor gevaar en stel met oom_score_adj de juiste volgorde van de slachtoffers in. Diensten die van invloed zijn op gebruikers bescherm ik, verplaatsbare taken maak ik geschikt om opgeofferd te worden, en ik documenteer elke waarde op een traceerbare manier. Ik plan cgroup-limieten, het aantal workers en cachegroottes als één geheel, zodat pieken niet uit de hand lopen. Logbestanden, monitoring en een beknopt draaiboek zorgen ervoor dat ik OOM-incidenten snel herken en gericht oplos. Met deze discipline blijft de host betrouwbaar en voorkom ik onaangename verrassingen tijdens productieve nachten.

Huidige artikelen