CMD + K
CMD + K
I/O-enheter, disker og RAID
Persistence begynner med maskinvaren: enheter er trege, ofte mekaniske og må håndteres via drivere, avbrudd og DMA. For å forstå filsystemer og crash consistency må du først forstå hvorfor I/O er dyrt og hvordan lagringsenheter faktisk oppfører seg.
- 01Forklare hvorfor disk-I/O har tre tidskomponenter (seek, rotasjon, transfer) og hvilken som dominerer i ulike arbeidsbelastninger
- 02Sammenligne polling, interrupts, DMA og memory-mapped I/O, og forklare når hver strategi gir best ytelse
- 03Beregne effektiv kapasitet og feiltoleranse for RAID 0 og RAID 1 gitt antall disker og rådata-størrelse
- 04Forklare hvorfor SSD-er trenger wear-leveling og erase-before-write, og hvordan det skaper write amplification
Hvorfor I/O er dyrt
Operativsystemet håndterer enheter via flere lag. Generisk OS-kode kaller en device driver, som oversetter til enhetsspesifikke kommandoer. Selve overføringen koster mye CPU-tid hvis man gjør den naivt — derfor er valget mellom polling, interrupts og DMA en av de viktigste designbeslutningene i I/O-stacken.
Den enkleste strategien er polling: CPU-en spør statusregisteret om og om igjen til enheten er klar. Lav latency for raske enheter, men ren sløsing for trege — CPU-en kunne gjort noe nyttig i mellomtiden. Alternativet er i/o-interrupt: enheten varsler CPU-en når den er ferdig, og scheduleren kan kjøre andre prosesser imens. Kostnaden er en interrupt-håndtering med kontekstbytte hver gang, typisk noen mikrosekunder. For ekstreme tilfeller — en stadig flom av små pakker fra et nettverkskort — kan interrupt-overhead alene gjøre systemet ubrukelig (kalt interrupt livelock).
Selv hvordan dataene flyttes betyr noe. programmed i/o (pio) lar CPU-en kopiere byte-for-byte gjennom egne I/O-instruksjoner — billig på spesialhardware, dyrt for stor data fordi CPU-en låses for hele overføringen. memory-mapped i/o mapper enhetsregistre inn i adresseområdet så vanlige load/store-instruksjoner gjør jobben. Og dma kobler enheten direkte til minne: CPU-en setter opp overføringen via en deskriptor, men selve kopieringen foregår uten den. Moderne disker, nettverkskort og GPU-er bruker alle DMA — det er den eneste måten å holde båndbredder på flere GB/s uten å spise hele CPU-en.
Disken som mekanisk apparat
En tradisjonell harddisk har platter som roterer og et hode som svinger inn og ut.
Tre tidskomponenter dominerer hver aksess: seek time, rotational latency og transfer time. Summen gir totaltida som ƒdisk-i/o-tid viser.
Seek og rotasjon er bortkastet — disken gjør ikke nyttig arbeid mens hodet flytter seg eller venter. Transfer er den eneste «produktive» fasen. For tilfeldig I/O på små blokker dominerer seek og rotasjon; for sekvensielle store reads dominerer transfer. Det er hele grunnen til at sekvensiell I/O er mye raskere enn tilfeldig på roterende media.
Gjennomsnittlig rotasjonslatens er enkel matematikk: hodet venter i snitt en halv omdreining, så ƒgjennomsnittlig rotasjonslatens. En 7200 RPM-disk gir ~4.17 ms, en 5400 RPM-disk ~5.5 ms, og en gammel 15000 RPM-serverdisk klarte ~2 ms. Selv den raskeste mekaniske disken er minst hundre ganger tregere enn DRAM.
IOPS — målestokken for tilfeldig I/O
For arbeidsbelastninger som databaser og filservere er ikke båndbredde det mest interessante — antall små aksesser per sekund er det. ƒiops for tilfeldig i/o gir et brukbart anslag. 100 IOPS for en typisk 7200 RPM-disk er ikke uvanlig; en SSD kan klare 10 000 til 100 000+. Forskjellen er ikke teknologi-marketing, det er fysikken: ingen mekanisk del å flytte.
Selve transfer-tida er gitt av ƒtotal disk-io-tid — størrelsen delt på båndbredden. For en 4 KB blokk på en disk som leverer 100 MB/s er transfer ferdig på rundt 40 µs. Men hvis hver aksess også koster 4 ms seek pluss rotasjon, betyr det 99 % venting og 1 % arbeid. Det er den asymmetrien som drypper inn i alle valg lengre opp i stacken.
Disk-scheduling — å minimere bevegelse
Med flere ventende I/O-forespørsler kan OS-et omorganisere køen for å redusere seek. sstf (shortest seek time first) (Shortest Seek Time First) plukker alltid forespørselen nærmest hodet. Det minimerer total seek-tid, men risikerer å sulte forespørsler langt unna, akkurat som SJF kunne sulte lange jobber i CPU-planlegging.
Praktiske algoritmer som SCAN (elevator) og C-SCAN beveger hodet i én retning og betjener forespørslene som ligger på veien. Det balanserer ytelse og fairness. Moderne SSD-er trenger ikke slik scheduling — det er ingen mekanisk seek å spare — men OS-laget bevarer ofte køhåndtering for å pakke aksesser, slå sammen tilstøtende forespørsler (request merging) og redusere overhead.
Et vanlig eksamenstrikk: gitt en sekvens av sektor-forespørsler og en startposisjon for hodet, regn ut totalt antall spor-bevegelser under FCFS, SSTF og SCAN. Tallene avslører at SSTF kan halvere bevegelsen sammenlignet med naiv FCFS, men også at SSTF kan ignorere en forespørsel i utkanten i lang tid hvis nye forespørsler stadig kommer inn nær hodets nåværende posisjon.
SSD-er og flash — annerledes fysikk
En SSD lagrer biter i nand flash-celler. Hver celle holder 1 til 4 bits (SLC, MLC, TLC, QLC) — flere bits per celle betyr billigere lagring og kortere levetid. Det grunnleggende problemet er erase-before-write: en celle må først nullstilles før ny data kan skrives. Sletting skjer på blokk-nivå (mange sider), skriving på side-nivå. Det skaper write amplification: én liten logisk skriving kan trigge mye fysisk arbeid.
For å bevare levetiden gjør SSD-firmware wear leveling — sprer skrivinger over alle blokker så ingen celler slites ut først. Cellene tåler typisk 3 000 til 100 000 P/E-sykluser. Et lite skriveskript på samme logiske sektor om og om igjen havner derfor på ulike fysiske steder. Dette skjuler kompleksiteten fra OS-et, men gjør ytelsen mindre forutsigbar enn på en disk: en lat SSD i en travel periode kan plutselig måtte gjøre intern garbage collection og bremse til 10 % av nominell ytelse.
Filsystemet kan hjelpe SSD-en ved å sende TRIM-kommandoer når blokker frigjøres. Uten TRIM må SSD-en anta at all data fortsatt er gyldig, og kan ikke kopiere så fritt under intern garbage collection. Det er ett av få steder hvor filsystem-laget aktivt må vite hva slags media det ligger på.
RAID — flere disker, ett volum
Et RAID-array kombinerer flere fysiske disker til ett logisk volum med definert balanse mellom kapasitet, ytelse og feiltoleranse. raid 0 striper data over alle diskene uten redundans. Kapasiteten er ƒbrukbar kapasitet i raid 0 — du får alt råstoff brukt — og ytelsen skalerer fordi parallelle aksesser går til ulike disker. Ulempen: én disk-feil mister alt.
raid 1 speiler data mellom to (eller flere) disker. Hver skriving går til begge. Kapasiteten er ƒbrukbar kapasitet i raid 1: omtrent halvparten av råkapasiteten brukes til redundans. Til gjengjeld overlever du en disk-feil uten datatap, og lese-ytelsen kan skalere fordi to disker kan svare på ulike requests parallelt.
RAID 5 og RAID 6 ligger imellom — paritet sprer redundansen over alle disker, slik at bare 1/N (eller 2/N) av kapasiteten ofres. Det er det vanlige valget for serverlagring der både kapasitet og overlevelse betyr noe. Skyggesiden er at hver liten skriving krever en read-modify-write-syklus for å beregne ny paritet, noe som halverer den effektive skrive-IOPS-en sammenlignet med striping uten paritet.
En subtil felle: «RAID er ikke backup». Speiling og paritet beskytter mot diskfeil, men ikke mot bruker-feil («rm -rf»), filsystem-bugs eller crypto-locker. Også en helt vanlig rebuild etter disk-bytte i et stort RAID 5-array kan ta dagevis, og hvis enda en disk faller i mellomtiden, mister du alt.
Hybride strategier i praksis
På moderne, raske SSD-er er den klassiske avveiningen mellom polling og interrupts ikke alltid klar. En NVMe-disk kan levere en I/O på under 10 µs — kortere enn en interrupt-håndtering selv. Derfor brukes ofte hybrid polling/interrupt: poll først en kort stund, og bytt til interrupts hvis enheten ikke er ferdig. Det gir lav latency på raske aksesser og lav CPU-bruk på trege.
Linux har også egne mekanismer som io_uring der applikasjonen og kjernen deler ringbuffere — submissions og completions flyter forbi hverandre uten klassiske syscalls. Det kutter ikke bare interrupt-kostnaden, men også selve overgangen mellom bruker- og kjernemodus, som har blitt en målbar andel av total I/O-tid på de raskeste enhetene.
Sammen tegner dette opp et hierarki som filsystemet bygger videre på: DRAM (~100 ns), SSD (~100 µs), HDD (~10 ms), nettverk (~10 ms+). Hvert hopp er to-tre størrelsesordener — derfor er buffer-cache og smart skriveorden så viktige neste lag opp. Et OS som ikke utnytter caching og batching her, taper raskt en faktor 10–100 på praktisk gjennomstrømning, uavhengig av hvor god scheduler-algoritmen ellers er.