Ik laat zien hoe linux dirty en de ‘dirty background ratio’ gebruiken om de paginacache te regelen en zo de schrijfdoorvoer, latentie en gegevensbeveiliging te beïnvloeden. Zo stel je concrete drempelwaarden in die de flusher op tijd activeren, blokkades voorkomen en de schrijfprestaties van je workloads verbeteren.
Centrale punten
Om te beginnen zal ik de belangrijkste punten kort samenvatten, voordat ik dieper op de materie inga.
- Ongepaste pagina's slaat Writes op in het RAM en bundelt veel kleine toegangsverzoeken tot efficiëntere I/O-bewerkingen.
- vuile_achtergrond_verhouding start Flusher-threads op de achtergrond en beperkt zo onopgemerkt de hoeveelheid vuil.
- vuile_ratio remt schrijfprocessen af wanneer de harde drempelwaarde wordt overschreden.
- Relatie Beide waarden zijn bepalend voor latentiepieken, doorvoersnelheid en buffergrootte.
- Bytes-varianten (dirty_bytes) bieden op grote servers een nauwkeurigere, absolute controle.
Dirty Pages begrijpen
Wanneer een proces gegevens schrijft, komen deze eerst terecht in de Pagina cache en worden gemarkeerd als „dirty“ totdat de kernel ze naar de opslagmedia kan doorschrijven. Dit bufferen versnelt de werking van applicaties, omdat RAM sneller reageert dan welke SSD of HDD dan ook en kleine schrijfbewerkingen samenkomen tot grote, sequentiële overdrachten. Ik houd daarbij altijd in gedachten hoeveel „vuil“ ik toestaat, want te veel buffering kan wachtrijen verlengen of bij crashes het risico op meer onbeveiligde gegevens vergroten. Wie de werking begrijpt, neemt betere beslissingen over writeback, latentie en opslagdruk. Een kort achtergrondartikel over de Writeback-cache helpt om dit mechanisme duidelijk te begrijpen.
Gegevensbeveiliging, fsync en crashvensters
De grenswaarden beïnvloeden niet alleen de prestaties, maar ook je risicomarge. Ik schat dit met een eenvoudige vuistregel: de maximale hoeveelheid onzekere gegevens gedeeld door de duurzame doorvoersnelheid van het apparaat geeft ruwweg de tijd aan die nodig is totdat de buffer leeg is. Voorbeeld: als ik 4 GB ‘dirty’ gegevens toestaat en het doelmedium een snelheid van 500 MB/s haalt, duurt het volledig wegschrijven ongeveer 8 seconden. In die tijd kunnen bij een stroomstoring of kernel-paniek de meest recente schrijfbewerkingen ontbreken.
Toepassingen kunnen het venster via fsync() of fdatasync() verkleinen, want deze oproepen dwingen het bestandssysteem om gegevens (en, afhankelijk van de journaling-modus, ook metagegevens) naar het medium te schrijven. Dat kost meer, maar is essentieel voor databases of journals. Ik zorg ervoor dat mijn ‘dirty’-limieten aansluiten bij het synchronisatiegedrag: frequente fsync()-Bezoekers profiteren van een lagere vuile_ratio, zodat de kernel niet extra afremt als er toch al regelmatig wordt opgeslagen. Omgekeerd mag ik bij logs waarin veel wordt toegevoegd en die zelden worden geleegd, grotere buffers toestaan – altijd met het oog op het aanvaardbare verliesrisico.
Ook barrières en schrijfvolgordes zijn belangrijk: moderne bestandssystemen maken gebruik van FUA/Flush-commando’s om de caches van de controller correct te legen. Op media zonder Power-Loss-Protection vergroten grote buffers het risico; met PLP of schrijfcachebeveiliging zijn grotere buffers vaak aanvaardbaar.
Dirty Background Ratio: de zachte drempelwaarde
Met vuile_achtergrond_verhouding Hiermee geef ik aan vanaf welk percentage van de beschikbare opslagruimte flusher-threads op de achtergrond beginnen te schrijven. Deze waarde blokkeert geen toepassingen, maar start stilletjes de opruimwerkzaamheden, zodat de buffer niet uit de hand loopt. Lage waarden zorgen voor vaker, maar gelijkmatiger schrijven op de achtergrond en vlakken latentiepieken af. Hogere waarden laten meer buffering toe, wat bij grote sequentiële schrijfbewerkingen de doorvoer verhoogt, maar bij plotselinge flushing aanzienlijke I/O-pieken kan veroorzaken. Standaardwaarden liggen doorgaans rond de tien procent, maar ik pas de grens aan afhankelijk van het medium, de werklast en de veiligheidseisen.
Dirty Ratio: de harde rem
De parameter vuile_ratio geeft de grens aan waarboven de kernel schrijvende processen afremt totdat er voldoende pagina’s zijn teruggeschreven. Deze harde grens beschermt het geheugen tegen een stortvloed van niet-persistente gegevens en heeft daarmee direct invloed op applicaties zodra deze meer gegevens willen produceren. Bij databases stel ik de waarde eerder laag in, zodat query's constante responstijden behouden en er geen lange flush-fasen ontstaan. Voor back-uptaken gebruik ik daarentegen ruimere buffers om grote blokken efficiënt over te dragen. Gangbare standaardwaarden variëren tussen twintig en veertig procent, maar ik pas dit bereik altijd aan de specifieke belasting aan.
Samenwerking en typische relaties
Beide grenswaarden werken als Tandem en ontplooien hun effect pas samen. Ik houd dirty_background_ratio altijd lager dan dirty_ratio, zodat de kernel op tijd op de achtergrond start en de harde rem zelden in werking treedt. Als vuistregel kies ik vaak een kwart tot de helft van de harde limiet, dus bijvoorbeeld 5–10 op 20. Zo start Writeback vroeg genoeg, zonder de doorvoer onnodig te verlagen. Wie deze verhouding niet aanhoudt, krijgt te maken met ofwel te vroege beperking, ofwel te laat achtergrondwerk met merkbare latentiepieken.
Regeling per apparaat en bloklaag-fijnheid
Naast de algemene limieten is het de moeite waard om ook naar het apparaatniveau te kijken. Linux verdeelt de ‘dirty load’ over zogenaamde Ondersteunde apparaten (bdi). In /sys/class/block//bdi/ vind ik parameters zoals max_ratio, die bepalen hoeveel van het wereldwijd toegestane ‘dirty-budget’ een afzonderlijk apparaat mag gebruiken. Op systemen met zowel trage als snelle schijven beperk ik de trage schijven, zodat ze geen knelpunt vormen.
Ook van belang is de beperking op blokniveau via /sys/block//queue/wbt_lat_usec (Writeback Throttling). Hiermee streef ik een doellatentie na; de kernel remt de schrijfbelasting af wanneer deze de doeltijd overschrijdt. Bij SATA-HDD's stel ik graag conservatieve waarden in om de interactiviteit te waarborgen. Op zeer snelle NVMe-schijven schakel ik de doellatentie uit of verhoog ik deze, zodat de controller zijn parallelliteit ten volle kan benutten. De I/O-scheduler (mq-deadline, BFQ, none) kies ik op basis van de situatie: BFQ helpt bij interactieve systemen met een gemengde belasting, terwijl geen of dat mq-deadline bij pure doorvoertaakjes op NVMe vaak het beste werkt.
De onderlinge samenwerking is cruciaal: Is vuile_achtergrond_verhouding laag, maar omdat het apparaat via WBT agressief wordt beperkt, ontstaan er toch zichtbare opstoppingen. Daarom kalibreer ik beide niveaus samen: globale ‘dirty’-limieten voor de buffergrootte en de block-layer voor latentiebescherming.
Ratio versus bytes: standaardwaarden en varianten
Op systemen met veel RAM Procentuele waarden lopen al snel op tot grote absolute grootheden. Dan stel ik liever absolute bovengrenzen in met `dirty_bytes` en `dirty_background_bytes`, om de bufferomvang bijvoorbeeld duidelijk te beperken tot 2–8 GB. Dit ontkoppelt de regeling van sterk fluctuerende geheugencapaciteiten en houdt de hoeveelheid niet-persistente gegevens berekenbaar. De keuze blijft dynamisch: voor kleine servers met weinig RAM zijn percentages vaak volstrekt voldoende. Wie over een hoge capaciteit beschikt, kan met bytewaarden vaak beter plannen.
| Parameters | Dat betekent | Standaardinstellingen | Wanneer moet je dit aanpassen? | Tip |
|---|---|---|---|---|
| vm.vuile_achtergrond_verhouding | Start van de Achtergrond-flush in procenten | ≈ 10% | Bij schommelingen in de latentie of bij zeer snelle SSD’s/NVMe’s | Lager = gelijkmatiger latentie, hoger = meer buffer |
| vm.dirty_ratio | Hard Drosselgrens in procenten | ≈ 20–40% | Bij databases lager, bij back-ups hoger | Te hoog → Mogelijke blokkades bij het doorspoelen |
| vm.vuile_achtergrond_bytes | Start van de achtergrond-flush in Bytes | Uitgeschakeld wanneer Ratio wordt gebruikt | Veel RAM, vaste bufferdoelen | Schakelt Ratio-parameters uit |
| vm.dirty_bytes | Strenge limiet voor de lijster in Bytes | Uitgeschakeld wanneer Ratio wordt gebruikt | Veel RAM, een vast te stellen bovengrens | Schakelt Ratio-parameters uit |
Workload-scenario's en aanbevelingen
Sequentiële schrijfbelastingen zoals Back-ups profiteren van grote buffers en matig schrijven op de achtergrond, omdat de kernel in grote blokken naar het medium kan schrijven. Ik stel hier de `dirty_ratio` vaak in tussen 30 en 40 procent en de `dirty_background_ratio` tussen 10 en 20 procent. Databases en kleine random-I/O-toepassingen gedijen bij voorspelbare latentie, daarom kies ik voor 10–15 procent ‘hard’ en 3–5 procent ‘zacht’. Voor gemengde web- en app-servers blijkt 15–20 procent hard en 5–10 procent zacht een goed compromis te zijn. Deze marges gelden als uitgangspunt; daarna telt de gemeten realiteit van je systeem.
Aspecten van het bestandssysteem en koppelingsopties
Het writeback-traject eindigt in het bestandssysteem – de strategie daarvan is bepalend voor de latentie en de beveiliging. Ext4 met data=geordend (Standaard) schrijft gebruiksgegevens vóór journal-commits; data=writeback verlaagt de latentie, maar brengt oude gegevens in gevaar na crashes. De parameter verbinden= (seconden) bepaalt hoe vaak het logboek wordt opgeslagen. Kortere intervallen verminderen gegevensverlies, maar vergen meer I/O. XFS maakt gebruik van een uitgekiend logboekontwerp; grote logbsgrootte en een goede uitlijning helpen bij doorvoertaken. Btrfs bundelt schrijfbewerkingen via ‘copy-on-write’ – dit stabiliseert de latentie, maar kan bij kleine willekeurige schrijfbewerkingen en SSD’s met beperkte capaciteit tot fragmentatie leiden. Opties zoals nodatacow kunnen helpen bij bepaalde paden of gerichte defragmentatie wanneer er pieken in de latentie optreden.
Ik houd er bovendien rekening mee relatime/noatime (beperkt het aantal schrijfbewerkingen op metadata), luiheid (mtime/atime blijven langer behouden) en journaling-barrières. Juist bij RAID-controllers of in VM’s is de juiste cache-semantiek van cruciaal belang: verkeerd ingestelde schrijfcaches doen al het werk aan ‘dirty tuning’ teniet.
Direct I/O, O_SYNC en het gedrag van de toepassing
Niet elke aanvraag gaat via de paginacache. Met O_DIRECT of O_SYNC/O_DSYNC Bepaalde processen omzeilen delen van de cache of vereisen onmiddellijke persistentie. Databases schrijven doorgaans een WAL/redo-log synchroon en gegevensgebieden asynchroon. Ik stel ‘dirty’-drempels met name af voor asynchrone paden, terwijl ik voor synchrone paden lage latentie garandeer via snelle journals (NVMe, speciale LUN). Wanneer applicaties zeer vaak fsync() bij het oproepen zijn grote buffers niet erg nuttig – de latentie hangt dan sterker af van de controller, de wachtrijdiepte en de I/O-scheduler dan van vuile_ratio.
Praktische tuning stap voor stap
Voordat ik iets verander, controleer ik de werkelijke waarden met sysctl vm.dirty_ratio en sysctl vm.dirty_background_ratio, om de uitgangssituatie vast te leggen. Voor kortdurende tests noteer ik de waarden direct na /proc/sys/vm/bijvoorbeeld echo 15 > /proc/sys/vm/dirty_ratio en echo 5 > /proc/sys/vm/dirty_background_ratio. Als de aanpassing blijvend is, sla ik deze op in /etc/sysctl.conf of /etc/sysctl.d/*.conf. Wijzigingen breng ik aan met sysctl -p onmiddellijk, zodat ik het effect snel kan meten. Wie zich verder verdiept in het onderwerp systeemregels, profiteert van praktische tips over de Sysctl-afstemming op productieservers.
Waarden afleiden: rekenvoorbeelden
Ik begin graag met concrete specificaties. Voorbeeld 1: web-/app-server met 64 GB RAM, NVMe. Het doel is een lage latentie. Ik gebruik dirty_background_bytes=1073741824 (1 GB) en dirty_bytes=3221225472 (3 GB). Bij een duurzame NVMe-doorvoersnelheid van 2 GB/s betekent dit ongeveer 0,5–1,5 seconden om te legen – prima voor interactieve belasting. Voorbeeld 2: back-upknooppunt met 128 GB RAM, snelle SATA-RAID met 800 MB/s. Ik kies dirty_background_ratio=10, dirty_ratio=35. In absolute cijfers is dat ongeveer 12,8 GB en 44,8 GB; het duurt 16–56 seconden om de RAID leeg te maken. Dat is prima, want de taak is niet interactief.
Voorbeeld 3: Databaseserver met 256 GB RAM, apart journaal op NVMe, gegevens op SSD-array. Ik stel een absolute limiet in om uitschieters te voorkomen: dirty_background_bytes=2147483648 (2 GB), dirty_bytes=8589934592 (8 GB). Hierdoor blijft de grootte van het crashvenster voorspelbaar en worden abrupte vertragingen bij checkpoints beperkt.
Writeback-timing en aanverwante parameters
Naast de grenswaarden zijn ook van invloed Timer het writeback-gedrag en daarmee de gebruikerservaring van de applicaties. Met vm.dirty_writeback_centiseconden stel ik het interval in waarin de kernel-flusher wordt geactiveerd, terwijl vm.dirty_expire_centisecs bepaalt hoe oud ‘dirty pages’ maximaal mogen worden. Kortere intervallen zorgen voor frequentere, maar kleinere flushes; langere intervallen besparen I/O-aanroepen, maar brengen het risico met zich mee dat er grotere bundels ontstaan. Ik pas deze waarden alleen aan als metingen daadwerkelijke nadelen aantonen, zoals te zeldzame flushes op snelle NVMe-schijven. Wie hier methodisch te werk gaat, voorkomt schommelingen tussen te ijverige en te trage writeback-activiteit.
Monitoring en fijnafstelling
Na aanpassingen merk ik het volgende op continu de kengetallen om successen en bijwerkingen zichtbaar te maken. In /proc/meminfo controleer ik „Dirty“ en „Writeback“ om de buffercapaciteit en actieve flushes te bekijken. Tools zoals iostat, sar of atop geven me inzicht in doorvoer, wachtrijen en latentietrends. Dit artikel biedt een goede inleiding tot statistieken over I/O-wachttijd analyseren. Pas op basis van deze gegevens pas ik de limieten in kleine stapjes aan – door ze te verlagen of te verhogen – om te voorkomen dat er onverwachte neveneffecten optreden.
Containers, cgroups en eerlijke verdeling
In containeromgevingen delen workloads dezelfde kernelmechanismen. Cgroup-Writeback zorgt ervoor dat ‘dirty pages’ aan de veroorzaker worden toegewezen. Ik gebruik de I/O-controllers van de cgroups (blkcg) om de bandbreedte of IOPS per container te beperken wanneer individuele tenants te agressief bufferen. Absolute bytelimieten op hostniveau (vuile bytes) voorkomen dat één enkele gast het hele Dirty-budget opslokt. Daarnaast beperk ik de opslagruimte via geheugen.max, zodat Writeback niet pas reageert bij een globale druk. Het doel blijft: geen gastbelasting mag leiden tot hostbrede beperkingen van de vuile_ratio afdwingen.
Hostingomgevingen en VM's
In multi-tenant-omgevingen en VM’s let ik op Overboeking van RAM en I/O, omdat procentuele limieten daar andere gevolgen hebben. Absolute limieten in bytes kunnen voorkomen dat individuele gasten te veel buffer opbouwen en hun buren vertragen. Ik houd rekening met opslagdeduplicatie, ballooning en controllercaches, omdat deze de buffereffecten overstemmen. Voor managed servers loont het als de aanbieder zinvolle standaardinstellingen hanteert, zodat klanten constante responstijden ervaren. Wie zijn eigen knooppunten beheert, profiteert van duidelijk gedefinieerde profielinstellingen per workloadklasse.
Veelvoorkomende misverstanden en struikelblokken
- „Meer buffer = steeds meer doorvoer.“ Dit klopt niet bij workloads met veel willekeurige gegevens of apparaten met een kleine wachtrijdiepte. Te grote buffers veroorzaken flush-pieken en wachtrijen.
- „dirty_ratio heeft geen invloed op het aantal reads.“ Indirect wel: agressieve writeback-fasen verdringen cachepagina’s en verhogen de leeslatenties.
- „Bytes en ratio vullen elkaar aan.“ Nee. Als je Bytes-varianten gebruikt, heffen deze de bijbehorende Ratio-varianten op. Blijf eenduidig.
- „fsync() maakt “dirty limits’ irrelevant.“ Nee. Regelmatige synchronisaties verkleinen weliswaar het risicovenster, maar de rest van de belasting valt nog steeds onder de grenswaarden.
- „Een snelle gegevensdrager lost alles op.“ Niet als de Block-Layer de snelheid beperkt (WBT) of als het bestandssysteem niet optimaal is gekoppeld.
- „Drop_caches is een tuning-tool.“ Het leegmaken van de cache leidt tot vertekende metingen en verergert pieken in de latentie. In de productieomgeving vermijd ik dit.
Probleemoplossing: typische symptomen en oplossingen
Stapelen Pieken in latentie, stel ik eerst de achtergronddrempelwaarde lager in, zodat flushers eerder beginnen en er minder vaak grote schrijfpieken ontstaan. Als applicaties af en toe vastlopen, is de harde limiet meestal te hoog of kan het opslagmedium de ontstane flush-pieken niet aan. In dergelijke gevallen verlaag ik de dirty_ratio, controleer ik de readahead-instellingen en bekijk ik de journaling-opties van het bestandssysteem. Bij zeer snelle NVMe-hardware verhoog ik stapsgewijs de achtergronddrempel, om de doorvoer niet kunstmatig te beperken. Na elke wijziging baseer ik me op de meetresultaten, niet op mijn onderbuikgevoel.
Korte balans voor de praktijk
Met weinig Stelschroeven Hiermee bepaal ik hoe Linux schrijfgegevens in de buffer opslaat, wanneer de flushers starten en wanneer de kernel het systeem afremt. De ‘Dirty Background Ratio’ zorgt voor een soepele opschoning, terwijl de ‘Dirty Ratio’ het RAM-gebruik strenger beperkt. De verhouding tussen beide waarden bepaalt of je systeem eerder gericht is op gelijkmatige latenties of op maximale doorvoer. Ik documenteer de standaardinstellingen, breng in kleine stapjes wijzigingen aan en evalueer de meetresultaten consequent. Zo ontstaat een configuratie die de werklast, het medium en het risico op een verstandige manier in evenwicht brengt en in de praktijk merkbaar sneller werkt.


