ZFS Grunnleggende: Lagring og ytelse

ZFS Grunnleggende: Lagring og ytelse

Denne våren har vi allerede diskutert noen innledende emner, f.eks. hvordan du sjekker hastigheten på stasjonene dine и hva er RAID. I den andre av dem lovet vi til og med å fortsette å studere ytelsen til ulike multi-disk-topologier i ZFS. Dette er neste generasjons filsystem som nå implementeres overalt: fra eple til Ubuntu.

Vel, i dag er den beste dagen for å bli kjent med ZFS, nysgjerrige lesere. Bare vit at i den ydmyke mening til OpenZFS-utvikler Matt Ahrens, "er det veldig vanskelig."

Men før vi kommer til tallene - og de vil, jeg lover - for alle alternativer for en ZFS-konfigurasjon med åtte disker, må vi snakke om som Generelt lagrer ZFS data på disk.

Zpool, vdev og enhet

ZFS Grunnleggende: Lagring og ytelse
Dette komplette bassengdiagrammet inkluderer tre ekstra vdev-er, en av hver klasse, og fire for RAIDz2

ZFS Grunnleggende: Lagring og ytelse
Det er vanligvis ingen grunn til å lage en pool av uoverensstemmende vdev-typer og størrelser - men det er ingenting som hindrer deg i å gjøre det hvis du vil.

For å virkelig forstå ZFS-filsystemet, må du ta en nærmere titt på den faktiske strukturen. For det første forener ZFS de tradisjonelle nivåene for volum- og filsystemadministrasjon. For det andre bruker den en transaksjonell kopi-på-skriv-mekanisme. Disse funksjonene betyr at systemet er strukturelt svært forskjellig fra konvensjonelle filsystemer og RAID-matriser. Det første settet med grunnleggende byggeklosser å forstå er lagringsbassenget (zpool), virtuell enhet (vdev) og ekte enhet (enhet).

zpool

Zpool-lagringsbassenget er den øverste ZFS-strukturen. Hvert basseng inneholder en eller flere virtuelle enheter. På sin side inneholder hver av dem en eller flere virkelige enheter (enhet). Virtuelle bassenger er selvstendige blokker. Én fysisk datamaskin kan inneholde to eller flere separate bassenger, men hver er helt uavhengig av de andre. Pooler kan ikke dele virtuelle enheter.

Redundansen til ZFS er på virtuell enhetsnivå, ikke på bassengnivå. Det er absolutt ingen redundans på bassengnivå - hvis noen stasjon vdev eller spesiell vdev går tapt, så går hele bassenget tapt sammen med det.

Moderne lagringsbassenger kan overleve tap av en hurtigbuffer eller virtuell enhetslogg - selv om de kan miste en liten mengde skitne data hvis de mister vdev-loggen under et strømbrudd eller systemkrasj.

Det er en vanlig misforståelse at ZFS "data striper" er skrevet over hele bassenget. Dette er ikke sant. Zpool er ikke morsom RAID0 i det hele tatt, den er ganske morsom JBOD med en kompleks variabel distribusjonsmekanisme.

For det meste er postene fordelt på de tilgjengelige virtuelle enhetene i henhold til tilgjengelig ledig plass, så i teorien vil de alle bli fylt samtidig. I senere versjoner av ZFS blir gjeldende vdev-bruk (utnyttelse) tatt i betraktning - hvis en virtuell enhet er betydelig travlere enn en annen (for eksempel på grunn av lesebelastning), vil den midlertidig hoppes over for skriving, til tross for at den har den høyeste ledige plassforhold.

Utnyttelsesdeteksjonsmekanismen innebygd i moderne ZFS skriveallokeringsmetoder kan redusere ventetiden og øke gjennomstrømningen i perioder med uvanlig høy belastning - men det gjør den ikke carte Blanche på ufrivillig blanding av langsomme HDD-er og raske SSD-er i ett basseng. Et slikt ulikt basseng vil fortsatt fungere med hastigheten til den tregeste enheten, det vil si som om den var helt sammensatt av slike enheter.

vdev

Hvert lagringsbasseng består av en eller flere virtuelle enheter (virtuell enhet, vdev). På sin side inneholder hver vdev en eller flere ekte enheter. De fleste virtuelle enheter brukes til enkel datalagring, men det finnes flere vdev-hjelpeklasser, inkludert CACHE, LOG og SPECIAL. Hver av disse vdev-typene kan ha en av fem topologier: enkeltenhet (enkeltenhet), RAIDz1, RAIDz2, RAIDz3 eller speil (speil).

RAIDz1, RAIDz2 og RAIDz3 er spesielle varianter av det de gamle vil kalle RAID med dobbel (diagonal) paritet. 1, 2 og 3 viser til hvor mange paritetsblokker som er tildelt for hver datastripe. I stedet for separate disker for paritet, fordeler virtuelle RAIDz-enheter denne pariteten semi-jevnt over disker. En RAIDz-matrise kan miste like mange disker som den har paritetsblokker; hvis den mister en annen, vil den krasje og ta med seg lagringsbassenget.

I speilvendte virtuelle enheter (speil vdev) lagres hver blokk på hver enhet i vdev. Selv om to-brede speil er det vanligste, kan et hvilket som helst vilkårlig antall enheter være i et speil – tripler brukes ofte i store installasjoner for forbedret leseytelse og feiltoleranse. Et vdev-speil kan overleve enhver feil så lenge minst én enhet i vdev-en fortsetter å fungere.

Enkelt vdevs er iboende farlige. En slik virtuell enhet vil ikke overleve en enkelt feil - og hvis den brukes som lagring eller en spesiell vdev, vil feilen føre til ødeleggelse av hele bassenget. Vær veldig, veldig forsiktig her.

CACHE, LOG og SPESIAL VAer kan opprettes ved å bruke hvilken som helst av topologiene ovenfor - men husk at tap av en SPESIAL VA betyr tap av bassenget, så en redundant topologi anbefales sterkt.

enhet

Dette er sannsynligvis det enkleste begrepet å forstå i ZFS - det er bokstavelig talt en blokkeringsenhet for tilfeldig tilgang. Husk at virtuelle enheter består av individuelle enheter, mens en pool består av virtuelle enheter.

Disker - enten magnetiske eller solid state - er de vanligste blokkenhetene som brukes som byggesteinene til vdev. Imidlertid vil enhver enhet med en deskriptor i /dev gjøre det - så hele maskinvare-RAID-arrayer kan brukes som separate enheter.

En enkel råfil er en av de viktigste alternative blokkenhetene som en vdev kan bygges fra. Test bassenger fra sparsomme filer er en veldig hendig måte å sjekke bassengkommandoer og se hvor mye plass som er tilgjengelig i et basseng eller en virtuell enhet med en gitt topologi.

ZFS Grunnleggende: Lagring og ytelse
Du kan lage en testpool fra sparsomme filer på bare noen få sekunder - men ikke glem å slette hele bassenget og dets komponenter etterpå

La oss si at du vil sette en server på åtte disker og planlegger å bruke 10 TB disker (~9300 GiB) - men du er ikke sikker på hvilken topologi som passer best for dine behov. I eksemplet ovenfor bygger vi en testpool fra sparsomme filer på sekunder – og nå vet vi at en RAIDz2 vdev på åtte 10 TB disker gir 50 TiB brukbar kapasitet.

En annen spesiell klasse av enheter er SPARE (reserve). Hot-swap-enheter, i motsetning til vanlige enheter, tilhører hele bassenget, og ikke til en enkelt virtuell enhet. Hvis en vdev i bassenget mislykkes og en reserveenhet er koblet til bassenget og tilgjengelig, vil den automatisk bli med i den berørte vdev.

Etter tilkobling til den berørte vdev, begynner reserveenheten å motta kopier eller rekonstruksjoner av dataene som skal være på den manglende enheten. I tradisjonell RAID kalles dette rebuilding, mens det i ZFS kalles resilvering.

Det er viktig å merke seg at reserveenheter ikke permanent erstatter defekte enheter. Dette er bare en midlertidig erstatning for å redusere tiden vdev blir degradert. Etter at administratoren har erstattet den mislykkede vdev-en, gjenopprettes redundansen til den permanente enheten, og SPARE kobles fra vdev-en og returneres til å fungere som reserve for hele bassenget.

Datasett, blokker og sektorer

Det neste settet med byggeklosser å forstå på vår ZFS-reise handler mindre om maskinvaren og mer om hvordan selve dataene er organisert og lagret. Vi hopper over noen nivåer her - for eksempel metaslab - for ikke å rote til detaljene samtidig som vi opprettholder en forståelse av den generelle strukturen.

Datasett (datasett)

ZFS Grunnleggende: Lagring og ytelse
Når vi først oppretter et datasett, viser det all tilgjengelig bassengplass. Så setter vi kvoten – og endrer monteringspunktet. Magi!

ZFS Grunnleggende: Lagring og ytelse
Zvol er for det meste bare et datasett strippet for filsystemlaget, som vi erstatter her med et helt normalt ext4-filsystem.

Et ZFS-datasett er omtrent det samme som et standard montert filsystem. Som et vanlig filsystem ser det ved første øyekast ut som "bare en annen mappe". Men akkurat som vanlige monterbare filsystemer, har hvert ZFS-datasett sitt eget sett med grunnleggende egenskaper.

Først av alt kan et datasett ha en tildelt kvote. Hvis satt zfs set quota=100G poolname/datasetname, vil du ikke kunne skrive til den monterte mappen /poolname/datasetname mer enn 100 GiB.

Legger du merke til tilstedeværelsen - og fraværet - av skråstreker i begynnelsen av hver linje? Hvert datasett har sin egen plass i både ZFS-hierarkiet og systemmonteringshierarkiet. Det er ingen innledende skråstrek i ZFS-hierarkiet - du starter med bassengnavnet og deretter banen fra ett datasett til det neste. For eksempel, pool/parent/child for et datasett med navn child under overordnet datasett parent i et basseng med et kreativt navn pool.

Som standard vil datasettets monteringspunkt tilsvare navnet i ZFS-hierarkiet, med en ledende skråstrek – bassenget som heter pool montert som /pool, datasett parent montert i /pool/parent, og det underordnede datasettet child montert i /pool/parent/child. Datasettets systemmonteringspunkt kan imidlertid endres.

Hvis vi spesifiserer zfs set mountpoint=/lol pool/parent/child, deretter datasettet pool/parent/child montert på systemet som /lol.

I tillegg til datasett bør vi nevne volumer (zvols). Et volum er omtrent det samme som et datasett, bortsett fra at det faktisk ikke har et filsystem – det er bare en blokkenhet. Du kan for eksempel lage zvol Med navn mypool/myzvol, formater det deretter med et ext4-filsystem, og monter det filsystemet - du har nå et ext4-filsystem, men med alle sikkerhetsfunksjonene til ZFS! Dette kan virke dumt på en enkelt maskin, men gir mye mer mening som en backend når du eksporterer en iSCSI-enhet.

Blokker

ZFS Grunnleggende: Lagring og ytelse
Filen er representert av en eller flere blokker. Hver blokk lagres på én virtuell enhet. Blokkstørrelsen er vanligvis lik parameteren rekordstørrelse, men kan reduseres til 2^skifthvis den inneholder metadata eller en liten fil.

ZFS Grunnleggende: Lagring og ytelse
Vi virkelig virkelig ikke spøker med den enorme ytelsesstraffen hvis du setter for lite gir

I en ZFS-pool lagres alle data, inkludert metadata, i blokker. Maksimal blokkstørrelse for hvert datasett er definert i egenskapen recordsize (rekordstørrelse). Poststørrelsen kan endres, men dette vil ikke endre størrelsen eller plasseringen av noen blokker som allerede er skrevet til datasettet - det påvirker kun nye blokker etter hvert som de skrives.

Med mindre annet er spesifisert, er gjeldende standard poststørrelse 128 KiB. Det er en litt vanskelig avveining der ytelsen ikke er perfekt, men det er ikke forferdelig i de fleste tilfeller heller. Recordsize kan settes til en hvilken som helst verdi fra 4K til 1M (med avanserte innstillinger recordsize du kan installere enda mer, men dette er sjelden en god idé).

Enhver blokk refererer til dataene til bare én fil - du kan ikke stappe to forskjellige filer i én blokk. Hver fil består av en eller flere blokker, avhengig av størrelsen. Hvis filstørrelsen er mindre enn poststørrelsen, vil den bli lagret i en mindre blokkstørrelse - for eksempel vil en blokk med en 2 KiB-fil kun oppta én sektor på 4 KiB på disken.

Hvis filen er stor nok og krever flere blokker, vil alle poster med denne filen være av størrelse recordsize - inkludert den siste oppføringen, hvorav hoveddelen kan være ubrukt plass.

zvols har ikke en eiendom recordsize — i stedet har de en tilsvarende eiendom volblocksize.

Sektorer

Den siste, mest grunnleggende byggesteinen er sektoren. Det er den minste fysiske enheten som kan skrives til eller leses fra den underliggende enheten. I flere tiår brukte de fleste disker 512-byte sektorer. Nylig er de fleste disker satt til 4 KiB-sektorer, og noen - spesielt SSD-er - har 8 KiB-sektorer eller enda mer.

ZFS-systemet har en egenskap som lar deg stille inn sektorstørrelsen manuelt. Denne eiendommen ashift. Litt forvirrende er shift en kraft av to. For eksempel, ashift=9 betyr en sektorstørrelse på 2^9, eller 512 byte.

ZFS spør operativsystemet for detaljert informasjon om hver blokkenhet når den legges til en ny vdev, og teoretisk sett installerer ashift automatisk riktig basert på den informasjonen. Dessverre lyver mange stasjoner om sektorstørrelsen for å opprettholde kompatibilitet med Windows XP (som ikke var i stand til å forstå stasjoner med andre sektorstørrelser).

Dette betyr at en ZFS-administrator anbefales på det sterkeste å vite den faktiske sektorstørrelsen til enhetene deres og stille inn manuelt ashift. Hvis ashift er satt for lavt, øker antallet lese-/skriveoperasjoner astronomisk. Så, å skrive 512-byte "sektorer" inn i en ekte 4 KiB-sektor betyr å måtte skrive den første "sektoren", deretter lese 4 KiB-sektoren, endre den med en andre 512-byte "sektor", skrive den tilbake til den nye 4 KiB sektor, og så videre for hver oppføring.

I den virkelige verden rammer en slik straff Samsung EVO SSD-er, for hvilke ashift=13, men disse SSD-ene lyver om sin sektorstørrelse, og derfor er standarden satt til ashift=9. Hvis en erfaren systemadministrator ikke endrer denne innstillingen, fungerer denne SSD-en langsommere konvensjonell magnetisk HDD.

Til sammenligning, for for stor størrelse ashift det er praktisk talt ingen straff. Det er ingen reell ytelsesstraff, og økningen i ubrukt plass er uendelig liten (eller null med komprimering aktivert). Derfor anbefaler vi på det sterkeste at selv de stasjonene som bruker 512-byte sektorer installerer ashift=12 eller ashift=13å møte fremtiden med selvtillit.

Eiendom ashift er satt for hver virtuelle vdev-enhet, og ikke for bassenget, som mange feilaktig tror - og endres ikke etter installasjon. Hvis du ved et uhell slår ashift når du legger til en ny vdev i et basseng, har du ugjenkallelig forurenset bassenget med en lavytelsesenhet, og det er vanligvis ikke noe annet valg enn å ødelegge bassenget og starte på nytt. Selv fjerning av vdev vil ikke redde deg fra en ødelagt konfigurasjon ashift!

Kopier-på-skriv-mekanisme

ZFS Grunnleggende: Lagring og ytelse
Hvis et vanlig filsystem trenger å overskrive data, endrer det hver blokk der det er

ZFS Grunnleggende: Lagring og ytelse
Et kopi-på-skriv-filsystem skriver en ny blokkversjon og låser deretter opp den gamle versjonen

ZFS Grunnleggende: Lagring og ytelse
I det abstrakte, hvis vi ignorerer den faktiske fysiske plasseringen av blokkene, blir "datakometen" vår forenklet til en "dataorm" som beveger seg fra venstre til høyre over kartet over tilgjengelig plass

ZFS Grunnleggende: Lagring og ytelse
Nå kan vi få en god ide om hvordan kopier-på-skriv-øyeblikksbilder fungerer - hver blokk kan tilhøre flere øyeblikksbilder, og vil vedvare til alle tilknyttede øyeblikksbilder er ødelagt

Copy on Write (CoW)-mekanismen er det grunnleggende grunnlaget for det som gjør ZFS til et så fantastisk system. Grunnkonseptet er enkelt – hvis du ber et tradisjonelt filsystem om å endre en fil, vil det gjøre akkurat det du spurte om. Hvis du ber et kopi-på-skriv-filsystem om å gjøre det samme, vil det si "ok", men lyve for deg.

I stedet skriver et kopi-på-skriv-filsystem en ny versjon av den modifiserte blokken og oppdaterer deretter filens metadata for å koble fra den gamle blokken og knytte den nye blokken du nettopp skrev til den.

Å løsne den gamle blokken og koble til den nye gjøres i én operasjon, så den kan ikke avbrytes - hvis du slår av etter dette har du en ny versjon av filen, og hvis du slår av tidlig, har du den gamle versjonen . I alle fall vil det ikke være noen konflikter i filsystemet.

Kopier-på-skriv i ZFS skjer ikke bare på filsystemnivå, men også på diskadministrasjonsnivå. Dette betyr at ZFS ikke påvirkes av mellomrom (et hull i RAID) - et fenomen da stripen rakk å bare delvis ta opp før systemet krasjet, med array-skade etter en omstart. Her er stripen skrevet atomisk, vdev er alltid sekvensiell, og Bob er onkelen din.

ZIL: ZFS-intensjonslogg

ZFS Grunnleggende: Lagring og ytelse
ZFS-systemet behandler synkrone skrivinger på en spesiell måte - det lagrer dem midlertidig, men umiddelbart i ZIL før de skrives permanent senere sammen med asynkrone skrivinger.

ZFS Grunnleggende: Lagring og ytelse
Vanligvis blir data skrevet til en ZIL aldri lest igjen. Men det er mulig etter et systemkrasj

ZFS Grunnleggende: Lagring og ytelse
SLOG, eller sekundær LOG-enhet, er bare en spesiell - og helst veldig rask - vdev, der ZIL kan lagres separat fra hovedlageret

ZFS Grunnleggende: Lagring og ytelse
Etter et krasj spilles alle skitne data i ZIL på nytt - i dette tilfellet er ZIL på SLOG, så det spilles av derfra

Det er to hovedkategorier av skriveoperasjoner - synkron (synkron) og asynkron (asynkron). For de fleste arbeidsbelastninger er det store flertallet av skrivingene asynkrone - filsystemet lar dem aggregeres og utstedes i batcher, noe som reduserer fragmentering og øker gjennomstrømningen betydelig.

Synkroniserte opptak er en helt annen sak. Når en applikasjon ber om en synkron skriving, forteller den filsystemet: "Du må overgi dette til ikke-flyktig minne akkurat nåinntil da er det ikke noe annet jeg kan gjøre." Derfor bør synkrone skrivinger forpliktes til disk umiddelbart - og hvis det øker fragmenteringen eller reduserer gjennomstrømningen, så må det være det.

ZFS håndterer synkron skriving annerledes enn vanlige filsystemer - i stedet for umiddelbart å forplikte dem til vanlig lagring, forplikter ZFS dem til et spesielt lagringsområde kalt ZFS Intent Log, eller ZIL. Trikset er at disse postene også forbli i minnet, blir aggregert sammen med normale asynkrone skriveforespørsler, for senere å bli tømt til lagring som helt normale TXG-er (transaksjonsgrupper).

Ved normal drift blir ZIL skrevet til og aldri lest igjen. Når postene fra ZIL etter noen få øyeblikk er forpliktet til hovedlageret i vanlige TXG-er fra RAM, kobles de fra ZIL. Den eneste gangen noe leses fra ZIL er når bassenget importeres.

Hvis ZFS svikter - et operativsystemkrasj eller et strømbrudd - mens det er data i ZIL, vil disse dataene bli lest under neste poolimport (for eksempel når nødsystemet startes på nytt). Alt i ZIL vil bli lest, gruppert i TXG-er, forpliktet til hovedlageret, og deretter løsnet fra ZIL under importprosessen.

En av vdev-hjelpeklassene kalles LOG eller SLOG, den sekundære enheten til LOG. Den har ett formål - å gi bassenget en separat, og helst mye raskere, veldig skrivebestandig vdev for å lagre ZIL, i stedet for å lagre ZIL på hovedvdev-butikken. Selve ZIL-en oppfører seg likt uansett hvor den er lagret, men hvis LOG vdev-en har veldig høy skriveytelse, vil synkronskriving være raskere.

Å legge til en vdev med LOG til bassenget fungerer ikke kan ikke forbedre asynkron skriveytelse - selv om du tvinger alle skrivinger til ZIL med zfs set sync=always, vil de fortsatt være knyttet til hovedlageret i TXG på samme måte og i samme tempo som uten loggen. Den eneste direkte ytelsesforbedringen er latensen til synkrone skrivinger (fordi raskere logg gir raskere operasjoner). sync).

Imidlertid, i et miljø som allerede krever mye synkron skriving, kan vdev LOG indirekte øke hastigheten på asynkron skriving og ikke-bufret lesing. Avlasting av ZIL-oppføringer til en egen vdev LOG betyr mindre strid for IOPS på primærlagring, noe som forbedrer ytelsen til alle lesinger og skrivinger til en viss grad.

Øyeblikksbilder

Kopier-på-skriv-mekanismen er også et nødvendig grunnlag for ZFS-atomiske øyeblikksbilder og inkrementell asynkron replikering. Det aktive filsystemet har et pekertre som markerer alle poster med gjeldende data - når du tar et øyeblikksbilde, lager du ganske enkelt en kopi av dette pekertreet.

Når en post overskrives på det aktive filsystemet, skriver ZFS først den nye blokkversjonen til ubrukt plass. Den kobler deretter den gamle versjonen av blokken fra det gjeldende filsystemet. Men hvis et øyeblikksbilde refererer til den gamle blokken, forblir den fortsatt uendret. Den gamle blokken vil faktisk ikke bli gjenopprettet som ledig plass før alle øyeblikksbilder som refererer til denne blokken er ødelagt!

replikering

ZFS Grunnleggende: Lagring og ytelse
Mitt Steam-bibliotek i 2015 var på 158 GiB og inkluderte 126 927 filer. Dette er ganske nær den optimale situasjonen for rsync - ZFS-replikering over nettverket var "bare" 750 % raskere.

ZFS Grunnleggende: Lagring og ytelse
På samme nettverk er replikering av en enkelt 40 GB Windows 7 virtuell maskinbildefil en helt annen historie. ZFS-replikering er 289 ganger raskere enn rsync - eller "bare" 161 ganger raskere hvis du er kunnskapsrik nok til å kalle rsync med --inplace.

ZFS Grunnleggende: Lagring og ytelse
Når et VM-bilde skaleres, vil rsync problemer skalere med det. 1,9 TiB er ikke så stor for et moderne VM-bilde - men det er stort nok til at ZFS-replikering er 1148 ganger raskere enn rsync, selv med rsyncs --inplace-argument

Når du forstår hvordan øyeblikksbilder fungerer, bør det være lett å forstå essensen av replikering. Siden et øyeblikksbilde bare er et tre med pekere til poster, følger det at hvis vi gjør det zfs send øyeblikksbilde, så sender vi både dette treet og alle poster knyttet til det. Når vi sender dette zfs send в zfs receive på målet skriver den både det faktiske innholdet i blokken og treet med pekere som refererer til blokkene til måldatasettet.

Ting blir enda mer interessant på den andre zfs send. Vi har nå to systemer som hver inneholder poolname/datasetname@1, og du tar et nytt øyeblikksbilde poolname/datasetname@2. Derfor, i det originale bassenget du har datasetname@1 и datasetname@2, og i målpuljen så langt kun det første øyeblikksbildet datasetname@1.

Siden vi har et felles øyeblikksbilde mellom kilden og målet datasetname@1, vi kan gjøre det trinnvis zfs send over det. Når vi sier til systemet zfs send -i poolname/datasetname@1 poolname/datasetname@2, sammenligner den to pekertrær. Eventuelle pekere som bare eksisterer i @2, refererer åpenbart til nye blokker - så vi trenger innholdet i disse blokkene.

På et eksternt system, behandler en inkrementell send like enkelt. Først skriver vi alle nye oppføringer som er inkludert i strømmen send, og legg deretter til pekere til disse blokkene. Voila, det har vi @2 i det nye systemet!

ZFS asynkron inkrementell replikering er en enorm forbedring i forhold til tidligere ikke-øyeblikksbaserte metoder som rsync. I begge tilfeller overføres kun endrede data – men rsync må først lese fra disken alle dataene på begge sider for å sjekke summen og sammenligne den. Derimot leser ZFS-replikering ikke annet enn pekertrær - og eventuelle blokker som ikke er til stede i det delte øyeblikksbildet.

Innebygd kompresjon

Kopier-på-skriv-mekanismen forenkler også det innebygde komprimeringssystemet. I et tradisjonelt filsystem er komprimering problematisk - både den gamle versjonen og den nye versjonen av de modifiserte dataene ligger på samme plass.

Hvis vi vurderer et stykke data i midten av en fil som starter livet som en megabyte med nuller fra 0x00000000 og så videre, er det veldig enkelt å komprimere det til én sektor på disken. Men hva skjer hvis vi erstatter den megabyten med nuller med en megabyte med inkomprimerbare data som JPEG eller pseudo-tilfeldig støy? Uventet vil denne megabyten med data ikke kreve én, men 256 4 KiB-sektorer, og på dette stedet på disken er bare én sektor reservert.

ZFS har ikke dette problemet, ettersom modifiserte poster alltid skrives til ubrukt plass - den opprinnelige blokken opptar bare en sektor på 4 KiB, og den nye posten vil okkupere 256, men dette er ikke et problem - et nylig modifisert fragment fra " midten" av filen vil bli skrevet til ubrukt plass uansett om størrelsen har endret seg eller ikke, så for ZFS er dette en ganske vanlig situasjon.

Native ZFS-komprimering er deaktivert som standard, og systemet tilbyr pluggbare algoritmer – for tiden LZ4, gzip (1-9), LZJB og ZLE.

  • LZ4 er en strømmealgoritme som tilbyr ekstremt rask komprimering og dekompresjon og ytelsesfordeler for de fleste brukstilfeller - selv på ganske trege CPUer.
  • GZIP er en ærverdig algoritme som alle Unix-brukere kjenner og elsker. Den kan implementeres med komprimeringsnivåer 1-9, med komprimeringsforhold og CPU-bruk økende når den nærmer seg nivå 9. Algoritmen egner seg godt for all tekst (eller andre svært komprimerbare) brukstilfeller, men forårsaker ellers ofte CPU-problemer − bruk den med forsiktighet, spesielt på høyere nivåer.
  • LZJB er den originale algoritmen i ZFS. Den er utdatert og skal ikke lenger brukes, LZ4 overgår den på alle måter.
  • DÅRLIG - Nullnivåkoding, Nullnivåkoding. Den berører ikke normale data i det hele tatt, men komprimerer store sekvenser av nuller. Nyttig for fullstendig inkomprimerbare datasett (som JPEG, MP4 eller andre allerede komprimerte formater) siden det ignorerer inkomprimerbare data, men komprimerer ubrukt plass i de resulterende postene.

Vi anbefaler LZ4-komprimering for nesten alle brukstilfeller; ytelsesstraffen når du møter ukomprimerbare data er svært liten, og vekst ytelsen for typiske data er betydelig. Kopiere et virtuell maskinbilde for en ny installasjon av Windows-operativsystemet (nyinstallert OS, ingen data inne ennå) med compression=lz4 passerte 27 % raskere enn med compression=noneI denne testen i 2015.

ARC - adaptiv erstatningsbuffer

ZFS er det eneste moderne filsystemet vi kjenner til som bruker sin egen lesebufringsmekanisme, i stedet for å stole på operativsystemets sidebuffer for å lagre kopier av nylig leste blokker i RAM.

Selv om den opprinnelige cachen ikke er uten problemer - kan ikke ZFS svare på nye minnetildelingsforespørsler like raskt som kjernen, så den nye utfordringen malloc() på minneallokering kan mislykkes hvis den trenger RAM som for øyeblikket er okkupert av ARC. Men det er gode grunner til å bruke din egen cache, i hvert fall foreløpig.

Alle kjente moderne operativsystemer, inkludert MacOS, Windows, Linux og BSD, bruker LRU-algoritmen (Least Recently Used) for å implementere sidebufferen. Dette er en primitiv algoritme som skyver den hurtigbufrede blokken "opp i køen" etter hver lesing, og skyver blokkene "ned i køen" etter behov for å legge til nye cache-misser (blokker som burde vært lest fra disken, ikke fra cachen) opp.

Algoritmen fungerer vanligvis bra, men på systemer med store fungerende datasett fører LRU lett til thrashing - kaster ut ofte nødvendige blokker for å gi plass til blokker som aldri vil bli lest fra cachen igjen.

ARC er en mye mindre naiv algoritme som kan betraktes som en "vektet" cache. Hver gang en bufret blokk leses, blir den litt "tyngre" og vanskeligere å kaste ut - og selv etter at en blokk er kastet ut spores innen et visst tidsrom. En blokk som har blitt kastet ut, men som deretter må leses tilbake i cachen, vil også bli "tyngre".

Sluttresultatet av alt dette er en cache med mye høyere treffforhold, forholdet mellom cache-treff (lesinger utført fra cachen) og cache-misser (leses fra disk). Dette er en ekstremt viktig statistikk - ikke bare blir cache-treffene i seg selv servert i størrelsesordener raskere, cache-miss kan også serveres raskere, siden jo flere cache-treff det er, jo færre samtidige diskforespørsler og jo lavere ventetid for de gjenværende missene som må serveres med disk.

Konklusjon

Etter å ha lært den grunnleggende semantikken til ZFS – hvordan kopiering-på-skriv fungerer, så vel som forholdet mellom lagringsbassenger, virtuelle enheter, blokker, sektorer og filer – er vi klare til å diskutere ytelse i den virkelige verden med reelle tall.

I neste del skal vi ta en titt på den faktiske ytelsen til bassenger med speilvendte vdevs og RAIDz, kontra hverandre, og også versus de tradisjonelle Linux-kjerne RAID-topologiene vi har utforsket. tidligere.

Først ønsket vi bare å dekke det grunnleggende - selve ZFS-topologiene - men etterpå en slik la oss gjøre oss klare til å snakke om mer avansert oppsett og tuning av ZFS, inkludert bruk av ekstra vdev-typer som L2ARC, SLOG og Special Allocation.

Kilde: www.habr.com

Legg til en kommentar