Nagyítás / Nem, valójában nem lehet OpenZFS logóval ellátott Ironwolf lemezeket vásárolni, de mivel garantáltan SMR-mentesek, jó választásnak számítanak.
Jim Salter

Amint mindannyian belépünk a COVID-19 járvány harmadik hónapjába, és új projekteket keresünk, amelyekkel leköthetjük magunkat (értsd: épelméjűek), érdekelne, hogy megtanuljuk a számítógépes tárolás alapjait? Idén tavasszal csendben már átvettünk néhány szükséges alapismeretet, például azt, hogyan teszteljük a lemezek sebességét, és mi a fene az a RAID. A második ilyen történetben még egy folytatást is ígértünk, amelyben a különböző többlemezes topológiák teljesítményét vizsgáljuk a ZFS-ben, a következő generációs fájlrendszerben, amelyről már hallottatok, mivel az Apple-től az Ubuntu-ig mindenhol megjelenik.

Nos, ma eljött a nap, hogy felfedezzétek, ZFS-kíváncsi olvasók. Csak tudjátok előre, hogy az OpenZFS fejlesztőjének, Matt Ahrensnek a visszafogott szavaival élve: “ez nagyon bonyolult.”

Még többet

De mielőtt rátérnénk a számokra – és jönnek, ígérem!-a nyolc lemeznyi ZFS alakításának minden módjáról, beszélnünk kell arról, hogy a ZFS egyáltalán hogyan tárolja az adatokat a lemezen.

Zpoolok, vdev-k és eszközök

Hogy igazán megértsük a ZFS-t, valódi figyelmet kell fordítanunk a tényleges felépítésére. A ZFS egyesíti a hagyományos kötetkezelő és fájlrendszer rétegeket, és copy-on-write tranzakciós mechanizmust használ – mindkettő azt jelenti, hogy a rendszer szerkezetileg nagyon különbözik a hagyományos fájlrendszerektől és RAID tömböktől. Az első főbb építőelemek, amelyeket meg kell értenünk, a zpools, vdevs és devices.

zpool

A zpool a legfelső ZFS-struktúra. A zpool egy vagy több vdevs-t tartalmaz, amelyek mindegyike viszont egy vagy több devices-t tartalmaz. A zpoolok önálló egységek – egy fizikai számítógépen két vagy több különálló zpool is lehet, de mindegyik teljesen független a többitől. A zpoolok nem oszthatnak meg egymással vdevs-at.

A ZFS redundancia a vdev szinten van, nem a zpool szinten. A zpool szintjén egyáltalán nincs redundancia – ha bármelyik tároló vdev vagy SPECIAL vdev elveszik, az egész zpool elveszik vele együtt.

Hirdetés

A modern zpoolok túlélik egy CACHE vagy LOG vdev elvesztését – bár egy kis mennyiségű piszkos adatot elveszíthetnek, ha egy LOG vdev áramkimaradás vagy rendszerösszeomlás során elveszik.

Egy gyakori tévhit, hogy a ZFS “csíkozza” az írásokat a poolon keresztül – de ez pontatlan. A zpool nem egy viccesen kinéző RAID0 – hanem egy viccesen kinéző JBOD, egy összetett elosztási mechanizmussal, amely változhat.

A legtöbb esetben az írások a rendelkezésre álló vdev-k között a rendelkezésre álló szabad helyüknek megfelelően kerülnek elosztásra, így elméletileg minden vdev egyszerre fog megtelni. A ZFS újabb verzióiban a vdev-kihasználtságot is figyelembe lehet venni – ha az egyik vdev jelentősen elfoglaltabb, mint a másik (pl.: olvasási terhelés miatt), akkor átmenetileg kihagyható az íráshoz, annak ellenére, hogy a legnagyobb arányban áll rendelkezésre szabad hely.

Hirdetés

A modern ZFS írási elosztási módszerekbe épített kihasználtsági tudatossági mechanizmus csökkentheti a késleltetést és növelheti az átviteli sebességet a szokatlanul nagy terhelés időszakaiban – de nem szabad összekeverni azzal a szabadkártyával, hogy a lassú rozsdás lemezeket és a gyors SSD-ket akarva-akaratlanul keverjük ugyanabban a poolban. Egy ilyen össze nem illő pool általában még mindig úgy fog teljesíteni, mintha teljes egészében a jelenlévő leglassabb eszközből állna.

vdev

Minden zpool egy vagy több vdevs(a virtuális eszköz rövidítése) eszközből áll. Minden vdev viszont egy vagy több valós devices-ből áll. A legtöbb vdev egyszerű tárolásra szolgál, de számos speciális támogatási osztálya is létezik a vdev-nek – köztük a CACHE, LOG és SPECIAL. Mindegyik vdev-típus öt topológia egyikét kínálhatja – egy eszköz, RAIDz1, RAIDz2, RAIDz3 vagy tükör.

A RAIDz1, RAIDz2 és RAIDz3 a tárolási szürkeállományok által “diagonális paritású RAID”-nek nevezett speciális változatai. Az 1, 2 és 3 arra utal, hogy az egyes adatcsíkokhoz hány paritásblokk van hozzárendelve. Ahelyett, hogy teljes lemezeket dedikálnának a paritásnak, a RAIDz vdev-k a paritást félig egyenletesen osztják el a lemezek között. Egy RAIDz tömb annyi lemezt veszíthet el, ahány paritásblokkja van; ha még egyet elveszít, akkor meghibásodik, és magával viszi a zpool-t is.

Hirdetés

A tükör vdev-k pontosan azok, aminek hangzanak – egy tükör vdev-ben minden blokk a vdev minden eszközén tárolódik. Bár a kétoldali tükrök a legelterjedtebbek, egy mirror vdev tetszőleges számú eszközt tartalmazhat – a nagyobb összeállításokban a nagyobb olvasási teljesítmény és a hibaállóság miatt gyakoriak a háromoldaliak. Egy tükrözött vdev bármilyen hibát túlélhet, amíg legalább egy eszköz a vdev-ben egészséges marad.

Az egyeszközös vdev-k is pontosan azok, aminek hangzanak – és eredendően veszélyesek. Az egyeszközös vdev nem képes túlélni semmilyen hibát – és ha tárolóként vagy SPECIAL vdev-ként használják, a hiba magával rántja az egész zpool vdev-et. Legyünk itt nagyon-nagyon óvatosak.

CACHE, LOG és SPECIAL vdev-ket a fenti topológiák bármelyikével létrehozhatunk – de ne feledjük, egy SPECIAL vdev elvesztése a pool elvesztését jelenti, ezért a redundáns topológia erősen ajánlott.

device

Ez talán a legkönnyebben érthető ZFS-hez kapcsolódó kifejezés – szó szerint csak egy véletlen hozzáférésű blokkeszköz. Ne feledjük, a vdevs egyedi eszközökből áll, a zpool pedig vdevs-ból.

A lemezek – akár rozsdásak, akár szilárdtestek – a leggyakrabban vdev építőelemként használt blokkeszközök. Bármi, aminek a /dev leírója lehetővé teszi a véletlenszerű hozzáférést, működni fog – így egész hardveres RAID tömbök használhatók (és néha használják is) egyedi eszközként.

Hirdetés

Az egyszerű nyers fájl az egyik legfontosabb alternatív blokkeszköz, amiből egy vdev felépíthető. A sparse fájlokból készített tesztpoolok hihetetlenül kényelmes módja annak, hogy gyakoroljuk a zpool parancsokat, és megnézzük, mennyi hely áll rendelkezésre egy adott topológiájú poolon vagy vdev-n.

Nagyítás / A sparse fájlokból néhány másodperc alatt létrehozhatunk egy tesztpoolt – de ne felejtsük el megsemmisíteni a tesztpoolt és az azt alkotó sparse fájlokat, amikor végeztünk.
Jim Salter

Tegyük fel, hogy egy nyolc rekeszes szerver építésén gondolkodik, és eléggé biztos benne, hogy 10 TB-os (~9300 GiB) lemezeket szeretne használni – de nem biztos benne, hogy milyen topológia felel meg leginkább az igényeinek. A fenti példában pillanatok alatt létrehozunk egy tesztpoolt ritka állományokból – és most már tudjuk, hogy egy nyolc 10 TB-os lemezből álló RAIDz2 vdev 50 TB hasznos kapacitást kínál.

A device-nek van egy speciális osztálya – az SPARE. A Hotspare eszközök a normál eszközökkel ellentétben a teljes poolhoz tartoznak, nem pedig egyetlen vdev-hoz. Ha a pool bármelyik vdev eszköze meghibásodik, és egy SPARE csatlakozik a poolhoz és elérhető, a SPARE automatikusan csatlakozik a meghibásodott vdev-hoz.

Hirdetés

Amint csatlakozik a meghibásodott vdev-hoz, a SPARE elkezdi fogadni a hiányzó eszközön lévő adatok másolatait vagy rekonstrukcióit. A hagyományos RAID-ben ezt “újjáépítésnek” neveznénk – a ZFS-ben ezt “újraszerkesztésnek” hívják.”

Fontos megjegyezni, hogy az SPARE eszközök nem helyettesítik véglegesen a meghibásodott eszközöket. Ezek csak helytartók, amelyek célja, hogy minimalizálják azt az ablakot, amely alatt egy vdev degradáltan fut. Amint az admin lecserélte a vdev meghibásodott eszközét, és az új, állandó helyettesítő eszköz újraindul, az SPARE leválik a vdev-ről, és visszatér az egész poolra kiterjedő szolgálatba.

Adatkészletek, blokkok és szektorok

A következő építőelemek, amelyeket meg kell értenie a ZFS útja során, nem annyira a hardverhez, hanem magának az adatnak a szervezéséhez és tárolásához kapcsolódnak. Itt kihagyunk néhány szintet – például a metaszintet – annak érdekében, hogy a dolgok a lehető legegyszerűbbek legyenek, ugyanakkor az általános szerkezetet is megértsük.

Adatkészletek

A ZFS dataset nagyjából analóg egy szabványos, felcsatolt fájlrendszerrel – mint egy hagyományos fájlrendszer, a felületes szemlélődés számára úgy tűnik, mintha “csak egy újabb mappa” lenne. De a hagyományos csatolt fájlrendszerekhez hasonlóan minden egyes ZFS dataset-nak saját mögöttes tulajdonságai vannak.

Először is, egy dataset-hoz hozzárendelhető kvóta. Ha zfs set quota=100G poolname/datasetname, akkor a rendszerbe szerelt /poolname/datasetname mappába

Hirdetés

Észrevettük a fenti példában a vezető kötőjelek jelenlétét – és hiányát? Minden adatkészletnek megvan a helye mind a ZFS-hierarchiában, mind a rendszercsatlakoztatási hierarchiában. A ZFS-hierarchiában nincsenek vezető kötőjelek – a pool nevével kezdjük, majd az egyik adatkészlettől a másikig vezető útvonallal – pl. pool/parent/child egy child nevű adatkészlethez a parent szülő adatkészlet alatt, egy kreatívan pool nevű poolban.

Alapértelmezés szerint a dataset csatlakoztatási pontja megegyezik a ZFS hierarchikus nevével, egy vezető kötőjellel – a pool nevű pool a /pool, a parent adatkészlet a /pool/parent, a child gyermek adatkészlet pedig a /pool/parent/child címre van csatlakoztatva. Az adatkészlet rendszermountpontját azonban megváltoztathatjuk.

Ha zfs set mountpoint=/lol pool/parent/child lenne, akkor a pool/parent/child adatkészlet valójában /lol-ként lenne mountolva a rendszerbe.

Hirdetés

Az adatkészleteken kívül meg kell említenünk a zvols-et is. A zvol nagyjából analóg a dataset-hoz, kivéve, hogy valójában nincs benne fájlrendszer – ez csak egy blokkeszköz. Létrehozhat például egy zvol-t mypool/myzvol néven, majd formázhatja az ext4 fájlrendszerrel, majd csatlakoztathatja ezt a fájlrendszert – most már van egy ext4 fájlrendszere, de a ZFS összes biztonsági funkciójával támogatva! Ez butaságnak tűnhet egy számítógépen – de sokkal több értelme van egy iSCSI-export háttértáraként.

Blocks

Egy ZFS-poolban minden adat – beleértve a metaadatokat is – a blocks-ben tárolódik. A block maximális mérete minden dataset esetében a recordsize tulajdonságban van meghatározva. A rekordméret változtatható, de a recordsize megváltoztatása nem változtatja meg az adatállományba már beírt blocks méretét vagy elrendezését – csak az új blokkok esetében, amikor azok beírásra kerülnek.

Ha nincs másként definiálva, a jelenlegi alapértelmezett recordsize 128KiB. Ez egyfajta kényelmetlen kompromisszumot jelent, amelyben a teljesítmény nem lesz ideális sok mindenhez, de nem is lesz szörnyű sok mindenhez. A Recordsize a 4K és 1M közötti bármely értékre beállítható. (A Recordsize további hangolással és kellő határozottsággal még nagyobbra is beállítható, de ez ritkán jó ötlet.)

Hirdetés

Minden adott block csak egy fájl adataira hivatkozik – két különálló fájlt nem lehet egy block-be zsúfolni. Minden fájl egy vagy több blocks-ből áll, a mérettől függően. Ha egy fájl kisebb, mint recordsize, akkor egy alulméretezett blokkban lesz tárolva – például egy 2KiB-os fájlt tartalmazó block csak egyetlen 4KiB-os sector blokkot foglal el a lemezen.

Ha egy fájl elég nagy ahhoz, hogy több blocks-et igényeljen, akkor az azt tartalmazó összes rekord recordsize hosszúságú lesz – beleértve az utolsó rekordot is, amely többnyire üres hely lehet.

Zvols nem rendelkezik a recordsize tulajdonsággal – helyette volblocksize, ami nagyjából egyenértékű.

Sectors

Az utolsó tárgyalandó építőelem a szerény sector. A sector a legkisebb fizikai egység, amely a mögötte lévő device-be írható vagy onnan olvasható. Több évtizeden keresztül a legtöbb lemez 512 bájtos sectors-öt használt. Újabban a legtöbb lemez 4KiB sectors-t használ, és néhány – különösen az SSD-k – 8KiB sectors-t, vagy még nagyobbat.

A ZFS rendelkezik egy olyan tulajdonsággal, amely lehetővé teszi a sector méretének kézi beállítását, az úgynevezett ashift. Kissé zavaró módon a ashift valójában a bináris exponens, amely a szektor méretét jelöli – például a ashift=9 beállítása azt jelenti, hogy a sector mérete 2^9, azaz 512 bájt lesz.

Hirdetés

A ZFS lekérdezi az operációs rendszert minden egyes device blokkról, amikor az egy új vdev-ba kerül, és elméletileg automatikusan megfelelően beállítja a ashift-t ezen információk alapján. Sajnos sok olyan lemez van, amelyik hazudik arról, hogy mekkora a sector mérete, hogy kompatibilis maradjon a Windows XP-vel (amely képtelen volt megérteni a más sector méretű lemezeket).

Ez azt jelenti, hogy a ZFS adminisztrátornak erősen ajánlott tisztában lennie a devices tényleges sector méretével, és manuálisan beállítani a ashift-t ennek megfelelően. Ha a ashift túl alacsonyan van beállítva, csillagászati olvasási/írási erősítési büntetés keletkezik – egy 512 bájtos “szektor” írása egy 4KiB valós sector-be azt jelenti, hogy ki kell írni az első “szektort”, majd ki kell olvasni a 4KiB sector-t, módosítani a második 512 bájtos “szektorral”, vissza kell írni egy *új* 4KiB sector-be, és így tovább, minden egyes írásnál.

A való világban ez az erősítési büntetés elég keményen sújt egy Samsung EVO SSD-t – amelynek ashift=13-nak kellene lennie, de hazudik a szektorméretéről, és ezért alapértelmezés szerint ashift=9, ha egy okos admin nem írja felül – ahhoz, hogy lassabbnak tűnjön, mint egy hagyományos rozsdás lemez.

Hirdetés

Ezzel szemben a ashift túl magas beállítása gyakorlatilag nem jár büntetéssel. Nincs valódi teljesítménybüntetés, és a slack space növekedése végtelenül kicsi (vagy nulla, ha a tömörítés be van kapcsolva). Erősen javasoljuk, hogy még az 512 bájtos szektorokat valóban használó lemezeknél is ashift=12 vagy akár ashift=13 legyen beállítva a jövőbiztosítás érdekében.

A ashift tulajdonság per-vdev – nem pedig pool-onként, ahogy azt általában és tévesen gondolják – és megváltoztathatatlan, ha egyszer be van állítva. Ha véletlenül elrontod a ashift-t, amikor egy új vdev-t adsz hozzá egy poolhoz, akkor visszavonhatatlanul megfertőzted a poolt egy drasztikusan alulteljesítő vdev-val, és általában nincs más lehetőséged, mint megsemmisíteni a poolt és újrakezdeni. Még a vdev eltávolítása sem menthet meg egy elrontott ashift-beállítástól!

Copy-on-Write szemantika

CoW-Copy on Write – a ZFS nagy részének alapvető alapja. Az alapkoncepció egyszerű – ha egy hagyományos fájlrendszert arra kérsz, hogy helyben módosítson egy fájlt, az pontosan azt teszi, amit kértél tőle. Ha megkérsz egy copy-on-write fájlrendszert, hogy ugyanezt tegye meg, azt mondja, hogy “oké” – de hazudik neked.

Ehelyett a copy-on-write fájlrendszer kiírja az általad módosított block új verzióját, majd frissíti a fájl metaadatait, hogy megszüntesse a régi block linkjét, és összekapcsolja az új block-t, amit most írtál.

Hirdetés

A régi block összekapcsolása és az új összekapcsolása egyetlen műveletben történik, így nem lehet megszakítani – ha a művelet után lemerül a táp, akkor a fájl új verziója van meg, ha pedig előtte, akkor a régi verzió. Mindig fájlrendszer-konzisztens vagy, mindkét esetben.

A ZFS-ben a copy-on-write nem csak a fájlrendszer szintjén van, hanem a lemezkezelés szintjén is. Ez azt jelenti, hogy a RAID-lyuk – egy olyan állapot, amikor egy csíkot csak részben írnak ki, mielőtt a rendszer összeomlik, ami a tömböt inkonzisztenssé és az újraindítás után sérültté teszi – nem érinti a ZFS-t. A csíkok írása atomikus, a vdev mindig konzisztens, és Bob a nagybácsi.

ZIL – a ZFS Intent Log

Az írási műveleteknek két fő kategóriája van – szinkron (sync) és aszinkron (async). A legtöbb munkaterhelés esetében az írási műveletek túlnyomó többsége aszinkron – a fájlrendszer összesítheti és kötegekben rögzítheti őket, csökkentve ezzel a töredezettséget és óriási mértékben növelve az átviteli sebességet.

A szinkronizált írások egy teljesen más állat – amikor egy alkalmazás szinkronizált írást kér, azt mondja a fájlrendszernek, hogy “ezt most kell rögzítened a nem illékony tárolóra, és amíg ezt nem teszed meg, addig nem tudok mást tenni”. A szinkronírásokat ezért azonnal le kell kötni a lemezre – és ha ez növeli a töredezettséget vagy csökkenti az átviteli sebességet, hát legyen.

Hirdetés

A ZFS a szinkronírásokat a normál fájlrendszerektől eltérően kezeli – ahelyett, hogy a szinkronírásokat azonnal kiürítené a normál tárolóba, a ZFS a ZFS Intent Log vagy ZIL nevű speciális tárolási területre köti őket. A trükk itt az, hogy ezek az írások is a memóriában maradnak, a normál aszinkron írási kérésekkel együtt aggregálva, hogy később teljesen normális TXG-ként (Transaction Groups, tranzakciós csoportok) kiürüljenek a tárolóba.

A normál működés során a ZIL-be írnak, és soha többé nem olvasnak belőle. Amikor a ZIL-be mentett írásokat néhány pillanattal később normál TXG-kben a RAM-ból a főtárolóba commitolják, a ZIL-ről leválasztják őket. A ZIL-ből csak a pool importálásakor történik olvasás.

Ha a ZFS összeomlik – vagy az operációs rendszer összeomlik, vagy egy kezeletlen áramkimaradás történik -, miközben a ZIL-ben adatok vannak, akkor a következő pool importáláskor (pl. a lezuhant rendszer újraindításakor) az adatok kiolvasásra kerülnek. Ami a ZIL-ben van, az beolvasásra kerül, TXG-kbe aggregálódik, a főtárolóba kerül, majd az importálás során a ZIL-ből leválasztásra kerül.

Hirdetés

A rendelkezésre álló vdev támogatási osztályok egyike a LOG– más néven SLOG vagy Secondary LOG eszköz. Az SLOG mindössze annyit tesz, hogy a pool számára egy külön – és remélhetőleg sokkal gyorsabb, nagyon nagy írási állóképességű – vdev-t biztosít a ZIL tárolására, ahelyett, hogy a ZIL-t a főtárolón tartaná vdevs. Minden tekintetben a ZIL ugyanúgy viselkedik, akár a főtárolón, akár egy LOG vdev-n van – de ha a LOG vdev nagyon nagy írási teljesítményű, akkor a szinkronizált írási visszatérések nagyon gyorsan megtörténnek.

Egy LOG vdev hozzáadása egy poolhoz egyáltalán nem tud és nem is fog közvetlenül javítani az aszinkron írási teljesítményen – még akkor sem, ha minden írást a ZIL-be kényszerítesz a zfs set sync=always használatával, akkor is ugyanúgy és ugyanolyan ütemben kerülnek a TXG-kben a főtárolóra, mint ahogyan a LOG nélkül is történne. Az egyetlen közvetlen teljesítményjavulás a szinkron írási késleltetésre vonatkozik (mivel a LOG nagyobb sebessége lehetővé teszi, hogy a sync hívás gyorsabban térjen vissza).

Egy olyan környezetben azonban, amely már sok szinkron írást igényel, a LOG vdev közvetve gyorsíthatja az aszinkron írásokat és a nem gyorsított olvasásokat is. A ZIL-írások külön LOG vdev-re való áthelyezése kevesebb versenyt jelent az IOPS-ért az elsődleges tárolón, ezáltal bizonyos mértékig növeli az összes olvasás és írás teljesítményét.

Snapshotok

A copy-on-write szemantika a ZFS atomi pillanatfelvételek és az inkrementális aszinkron replikáció szükséges alapját is képezi. Az élő fájlrendszer rendelkezik egy mutatófával, amely az összes records aktuális adatot tartalmazó records-t jelöli – amikor pillanatfelvételt készítünk, egyszerűen másolatot készítünk erről a mutatófáról.

Amikor egy rekordot felülírunk az élő fájlrendszerben, a ZFS először a block új verzióját írja a kihasználatlan helyre. Ezután eltávolítja a block régi verzióját az aktuális fájlrendszerből. De ha bármelyik snapshot hivatkozik a régi block-re, az továbbra is megváltoztathatatlan marad. A régi block valójában nem lesz visszavéve szabad helyként, amíg az összes snapshots, amely erre a block-re hivatkozik, meg nem semmisül!

Replikáció

Ha megértetted, hogyan működnek a pillanatfelvételek, akkor a replikáció megértéséhez is jó helyen vagy. Mivel egy pillanatkép egyszerűen egy records mutatókból álló fa, ebből következik, hogy ha zfs send egy pillanatképet készítünk, akkor elküldjük ezt a fát és a hozzá tartozó összes rekordot is. Amikor ezt a zfs send-t a célon lévő zfs receive-be csövezzük, az mind a tényleges block tartalmát, mind a blocks-re utaló mutatók fáját a céladatkészletbe írja.

A második zfs send-nél már érdekesebbé válnak a dolgok. Most, hogy már két rendszered van, amelyek mindegyike tartalmazza a poolname/datasetname@1 pillanatfelvételt, készíthetsz egy új, poolname/datasetname@2 pillanatfelvételt. Tehát a forráspoolon van datasetname@1 és datasetname@2, a célpoolon pedig eddig csak az első pillanatkép – datasetname@1.

Mivel van egy közös pillanatképünk a forrás és a cél között – datasetname@1 -, építhetünk rá egy inkrementális zfs send-et. Amikor megkérjük a rendszert, hogy zfs send -i poolname/datasetname@1 poolname/datasetname@2, összehasonlítja a két mutatófát. Minden olyan mutató, amely csak a @2-ben létezik, nyilvánvalóan az új blocks-re hivatkozik – így szükségünk lesz ezeknek a blocks-eknek a tartalmára is.

Hirdetés

A távoli rendszeren az így kapott inkrementális send bepipálása hasonlóan egyszerű. Először kiírjuk az összes új records-t, amely a send folyamban szerepel, majd beillesztjük az ezekre a blocks-re mutató mutatókat. Presto, megvan a @2 az új rendszeren!

A ZFS aszinkron inkrementális replikáció óriási előrelépés a korábbi, nem pillanatfelvétel-alapú technikákhoz képest, mint például a rsync. Mindkét esetben csak a megváltozott adatokat kell átküldeni a vezetéken – de a rsync-nek először mindkét oldalon be kell olvasnia az összes adatot a lemezről az ellenőrző összegzéshez és az összehasonlításhoz. Ezzel szemben a ZFS replikációnak nem kell mást beolvasnia, csak a mutatófákat – és minden blocks, amit ez a mutatófa tartalmaz, és ami még nem volt jelen a közös pillanatfelvételben.

Inline tömörítés

A copy-on-write szemantika megkönnyíti az inline tömörítést is. Egy hagyományos fájlrendszerrel, amely helyben történő módosítást kínál, a tömörítés problematikus – a módosított adatok régi és új verziójának is pontosan ugyanarra a helyre kell beférnie.

Ha egy fájl közepén lévő adatdarabot tekintünk, amely 1MiB nullával kezdi életét –0x00000000 ad nauseam -, nagyon könnyen egyetlen lemezszektorba tömörülne. De mi történik, ha ezt az 1MiB nullát 1MiB tömöríthetetlen adatra cseréljük, például JPEG vagy pszeudo-véletlenszerű zajra? Hirtelen ennek az 1MiB adatnak 256 4KiB-os szektorra van szüksége, nem csak egyre – és a fájl közepén lévő lyuk csak egy szektor széles.

Hirdetés

A ZFS-nek nincs ilyen problémája, mivel a módosított rekordok mindig a kihasználatlan helyre íródnak – az eredeti block csak egyetlen 4KiB sector-ot foglal el, az új rekord pedig 256-ot, de ez nem probléma – az újonnan módosított darabka a fájl “közepéről” a kihasználatlan helyre íródott volna, akár változott a mérete, akár nem, így a ZFS számára ez a “probléma” csak egy újabb nap az irodában.

A ZFS inline tömörítése alapértelmezés szerint ki van kapcsolva, és csatlakoztatható algoritmusokat kínál – jelenleg az LZ4, a gzip (1-9), az LZJB és a ZLE is.

  • Az LZ4 egy stream algoritmus, amely rendkívül gyors tömörítést és kicsomagolást kínál, és a legtöbb felhasználási esetben – még nagyon vérszegény CPU-k esetén is – teljesítménygyőzelmet jelent.
  • A GZIP a tiszteletre méltó algoritmus, amelyet minden Unix-szerű felhasználó ismer és szeret. Az 1-9. tömörítési szintekkel valósítható meg, a tömörítési arány és a CPU-használat a 9. szinthez közeledve növekszik. A Gzip előnyös lehet minden szöveges (vagy egyébként rendkívül tömöríthető) felhasználási esetben, de egyébként gyakran CPU-szűk keresztmetszetet eredményez – különösen a magasabb szinteken óvatosan használjuk.
  • Az LZJB a ZFS által használt eredeti algoritmus. Elavult, és a továbbiakban nem szabad használni – a LZ4 minden szempontból jobb.
  • A ZLE a Zero Level Encoding – a normál adatokat teljesen békén hagyja, de a nagy nullasorozatokat tömöríti. Hasznos a teljesen tömöríthetetlen adathalmazoknál (pl. JPEG, MP4 vagy más, már tömörített formátumok), mivel figyelmen kívül hagyja a tömöríthetetlen adatokat, de tömöríti a végső rekordok üres helyét.

Az LZ4 tömörítést szinte minden elképzelhető felhasználási esetre ajánljuk; a tömöríthetetlen adatokkal való találkozáskor a teljesítményveszteség nagyon kicsi, és a tipikus adatoknál a teljesítménynövekedés jelentős. Egy VM-kép másolása egy új Windows operációs rendszer telepítéséhez (csak a telepített Windows operációs rendszer, még nem voltak rajta adatok) 27%-kal gyorsabban ment a compression=lz4-vel, mint a compression=none-vel ebben a 2015-ös tesztben.

ARC-the Adaptive Replacement Cache

A ZFS az egyetlen általunk ismert modern fájlrendszer, amely saját olvasási gyorsítótár-mechanizmust használ, és nem az operációs rendszer lapozó gyorsítótárára támaszkodik, hogy a nemrég olvasott blokkok másolatait a RAM-ban tartsa számára.

Bár a külön cache-mechanizmusnak megvannak a maga problémái – a ZFS nem tud olyan azonnal reagálni az új memóriafoglalási kérésekre, mint a kernel, és ezért egy új mallocate()hívás sikertelen lehet, ha az ARC által éppen elfoglalt RAM-ra lenne szüksége -, jó okunk van, legalábbis egyelőre, hogy elviseljük.

Hirdetés

Minden ismert modern operációs rendszer – beleértve a MacOS-t, a Windows-t, a Linuxot és a BSD-t – az LRU (Least Recently Used) algoritmust használja a lap gyorsítótár megvalósításához. Az LRU egy naiv algoritmus, amely a gyorsítótárban tárolt blokkot minden egyes olvasáskor a várólista “tetejére” emeli, és szükség szerint kiüríti a várólista “aljáról” a blokkokat, hogy a “tetejére” új gyorsítótár-kihagyások (olyan blokkok, amelyeket nem a gyorsítótárból, hanem a lemezről kellett olvasni) kerüljenek.”

Ez eddig rendben van, de a nagy munkaadat-halmazokkal rendelkező rendszerekben az LRU könnyen a “thrashing” végére juthat – a nagyon gyakran szükséges blokkok kiiktatása, hogy helyet csináljon olyan blokkoknak, amelyeket soha többé nem olvasnak a gyorsítótárból.

Az ARC egy sokkal kevésbé naiv algoritmus, amelyet “súlyozott” gyorsítótárként lehet elképzelni. Minden egyes alkalommal, amikor egy cache-blokkot olvasnak, az egy kicsit “nehezebbé” és nehezebben kilakoltathatóvá válik – és még a kilakoltatás után is egy ideig nyomon követhető a kilakoltatott blokk. Egy kilakoltatott blokk, amelyet aztán vissza kell olvasni a gyorsítótárba, szintén “nehezebbé” és nehezebben kilakoltathatóvá válik.

Hirdetés

Mindennek a végeredménye egy olyan gyorsítótár, amelynek jellemzően sokkal nagyobb a találati aránya – a gyorsítótár találatai (a gyorsítótárból kiszolgált olvasások) és a gyorsítótár kihagyásai (a lemezről kiszolgált olvasások) közötti arány. Ez egy rendkívül fontos statisztika – nem csak maguk a cache-találatok kiszolgálása történik nagyságrendekkel gyorsabban, hanem a cache-kihagyások is gyorsabban kiszolgálhatók, mivel több cache-találat==kevesebb egyidejű kérés a lemezhez==kisebb késleltetés a lemezről kiszolgálandó hiányzásoknál.

Végkövetkeztetés

Most, hogy lefedtük a ZFS alapvető szemantikáját – hogyan működik az írás utáni másolás, valamint a poolok, vdev-k, blokkok, szektorok és fájlok közötti kapcsolatok – készen állunk arra, hogy a tényleges teljesítményről beszéljünk, valós számokkal.

Maradjanak velünk a tárolás alapjai sorozatunk következő részében, hogy megnézzük a tükrözött és RAIDz vdev-ket használó poolok tényleges teljesítményét, összehasonlítva mind egymással, mind a korábban vizsgált hagyományos Linux kernel RAID topológiákkal.

Hirdetés

Először csak az alapokkal foglalkozunk – magukkal a ZFS topológiákkal -, de utána készen állunk arra, hogy beszéljünk a fejlettebb ZFS beállításról és hangolásról, beleértve az olyan támogató vdev típusok használatát, mint az L2ARC, SLOG és Special Allocation.

admin

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.

lg