Dobrý deň.
Chcem sa podeliť so svojou praxou v budovaní systému ukladania dát pre KVM pomocou md RAID + LVM.
Program bude obsahovať:
- Zostavenie md RAID 1 z NVMe SSD.
- Zostavenie md RAID 6 zo SATA SSD a bežných diskov.
- Špecifiká fungovania TRIM/DISCARD na SSD RAID 1/6.
- Vytvorenie spustiteľného md RAID 1/6 poľa zo súhrnného súboru diskov.
- Inštalácia systému na NVMe RAID 1 pri absencii podpory NVMe v BIOS.
- Použitie LVM cache a LVM thin.
- Použitie snímok BTRFS a send/receive pre zálohovanie.
- Použitie LVM thin snímok a thin_delta pre zálohovanie v štýle BTRFS.
Ak máte záujem, pozývam vás pod kat.
Vyhlásenie
Autor nenesie žiadnu zodpovednosť za následky použitia alebo nepoužitia materiálov/príkladov/kódu/rád/údajov z tohto článku. Čítaním alebo akýmkoľvek spôsobom použitím tohto materiálu preberáte zodpovednosť za všetky následky týchto činov. Medzi možné následky patrí:
- Zhorené do chrumkava NVMe SSD.
- Úplne vyčerpaný počet zápisov a porucha SSD úložných zariadení.
- Úplná strata všetkých dát na všetkých úložných zariadeniach, vrátane záloh.
- Poruchový počítačový hardvér.
- Strávený čas, nervy a peniaze.
- Akékoľvek iné následky, ktoré nie sú uvedené vyššie.
Hardvér
Na sklade boli:
Základná doska zhruba z roku 2013 na čipsete Z87 spolu s Intel Core i7 / Haswell.
- Procesor s 4 jadrami a 8 vláknami
- 32 Gigabajtov operačnej pamäte DDR3
- 1 x 16 alebo 2 x 8 PCIe 3.0
- 1 x 4 + 1 x 1 PCIe 2.0
- 6 x 6 GBps SATA 3 konektorov
SAS adaptér LSI SAS9211-8I preflasovaný do režimu IT / HBA. Firmware s podporou RAID bol úmyselne nahradený firmwarem HBA, aby:
- Mohlo byť kedykoľvek vymenené toto rozhranie a nahradené akýmkoľvek iným prvým dostupným.
- TRIM/Discard fungoval normálne na diskoch, pretože v RAID firme tieto príkazy nie sú vôbec podporované, a HBA je vo všeobecnosti jedno, aké príkazy sa prenášajú po sbus.
Pevné disky, — 8 kusov HGST Travelstar 7K1000 s kapacitou 1 TB v formáte 2.5, ako pre notebooky. Tieto disky boli predtým v RAID 6 poli. V novom systéme si tiež nájdu uplatnenie. Na uchovávanie lokálnych záloh.
Pridali sa tiež:
6 kusov SATA SSD modelu Samsung 860 QVO 2TB. Od týchto SSD sa požaduje veľký objem, prítomnosť SLC cache, preferovaná spoľahlivosť a nízka cena. Povinná bola podpora discard/zero, ktorá sa overuje riadkom v dmesg:
kernel: ata1.00: Aktivácia discard_zeroes_data
2 kusy NVMe SSD modelu Samsung SSD 970 EVO 500GB.
Pre tieto SSD je dôležitá rýchlosť náhodného čítania/zápisu a schopnosť vyhovieť vašim potrebám. Chladič k nim. Nevyhnutne. Skutočne nevyhnutne. Inak ich môžete pripečiť do chrumkava pri prvej synchronizácii RAIDu.
Adaptér StarTech PEX8M2E2 pre 2 x NVMe SSD s inštaláciou do PCIe 3.0 8x slotu. Toto, opäť, je iba HBA, ale pre NVMe. Od lacnejších adaptérov sa líši absenciou požiadavky na podporu PCIe bifurkácie od základnej dosky vďaka zabudovanému PCIe prepínaču. Bude fungovať aj v najstaršom systéme, kde je PCIe, aj keď to bude x1 PCIe 1.0 slot. Samozrejme, s príslušnou rýchlosťou. Žiadne RAIDy tam nie sú. Zabudovaný BIOS na palube nie je. Takže, váš systém sa magicky nenaučí bootovať z NVMe a tým skôr robiť NVMe RAID vďaka tomuto zariadeniu.
Tento komponent bol podmienený výlučne prítomnosťou len jedného voľného 8x PCIe 3.0 v systéme, a pri prítomnosti 2 voľných slotov, sa ľahko nahrádza dvoma lacnými PEX4M2E1 alebo analógmi, ktoré sa dajú kúpiť kdekoľvek od 600 rubľov.
Odstránenie všetkých možných hardvérových alebo integrovaných v čipsete/BIOS RAIDov bolo urobené vedome, s cieľom mať možnosť plne nahradiť celý systém, okrem samotných SSD/HDD, pričom sú zachované všetky dáta. V ideálnom prípade, aby bolo možné zachovať aj nainštalovaný operačný systém pri prechode na úplne novú/odlišnú technológiu. Hlavné je, aby boli dostupné SATA a PCIe porty. Je to ako live CD alebo bootovacia USB kľúčenka, len veľmi rýchla a trochu rozmernejšia.
HumorNo, viete ako to chodí — niekedy je potrebné rýchlo vziať celý array so sebou. A dáta nechcete stratiť. Pre toto sú všetky spomínané nosiče pohodlne umiestnené na drážkach v štandardných 5.25 zásuvkách.
No, a samozrejme pre experimenty s rôznymi spôsobmi SSD cacheovania v Linuxe.
Hardvérové raidy, to je nuda. Zapneš. Buď to funguje, alebo nie. A s mdadm sú vždy možnosti.
Softvér
Predtým bola na hardvéri nainštalovaná Debian 8 Jessie, ktorá je blízka EOL. Bol zložený RAID 6 z vyššie spomenutých HDD v páre s LVM. Na ňom bežali virtuálne stroje v kvm/libvirt.
Keďže autor má vhodné skúsenosti s vytváraním prenosných zavádzacích SATA/NVMe flash diskov a aby sme príliš nenarušili zvyčajný apt-šablón, ako cieľový systém bola zvolená Ubuntu 18.04, ktorá sa už dosť stabilizovala, ale stále má tri roky podpory v perspektíve.
V spomínanom systéme sú prítomné všetky potrebné ovládače hardvéru priamo z krabice. Žiadny externý softvér a ovládače nám nebudú potrebné.
Príprava na inštaláciu
Na inštaláciu systému budeme potrebovať obraz Ubuntu Desktop. Serverová verzia má nejakú jadrovú inštalačku, ktorá prejavuje nadmernú neodstrániteľnú samostatnosť, a nevyhnutne vkladá UEFI systémový oddiel na jeden z diskov, čím pokazí celú krásu. Preto sa inštaluje iba v režime UEFI. Možnosti nenabízajú.
To nám nevyhovuje.
Prečo?Žiaľ, UEFI zavádzanie je veľmi zle kompatibilné so zavádzacím softvérovým RAIDom, pretože rezervovanie pre UEFI ESP oddiel nikto neponúka. V sieti sú recepty, ktoré navrhujú umiestniť ESP oddiel na flash disk v USB porte, ale to je bod zlyhania. Existujú recepty, ktoré používajú softvérový mdadm RAID 1 s metadátami verzie 0.9, ktoré nebránia UEFI BIOSu vidieť tento oddiel, ale to funguje do šťastného momentu, keď BIOS alebo iný OS na hardvéri zapíše niečo do ESP a zabudne synchronizovať s inými zrkadlami.
Okrem toho, zavádzanie UEFI závisí od NVRAM, ktorá sa spolu s diskami nepresunie na nový systém, pretože je súčasťou základnej dosky.
Takže, nebudeme vymýšľať nový bicykel. Už máme pripravený, rokmi overený dedovský bicykel, dnes nazývaný Legacy/BIOS boot, ktorý nesie hrdé meno CSM na UEFI-kompatibilných systémoch. Jednoducho ho vytiahneme z poličky, natrieme, dofúkame kolesá a vyčistíme vlhkou handričkou.
Verzia Desktop Ubuntu tiež nevie normálne nainštalovať s Legacy zavádzačom, ale tu, ako sa hovorí, aspoň existujú možnosti.
A tak, zbierame hardvér a zavádzame systém z bootovateľného flash disku Ubuntu Live. Budeme potrebovať sťahovať balíky, tak si nastavíme sieť, aká vám fungovala. Ak nefungovala, potrebné balíky môžeme do flash disku nahrať vopred.
Prihlásime sa do Desktop prostredia, spustíme emulátor terminálu a ideme na to:
#sudo bash
Ako…?Hornej strane textu je kanonický spúšťač hádok o sudo. S boS väčšími možnosťami prichádza aj väčšia zodpovednosť. Otázka je, či si ju dokážete prevziať. Mnohí považujú používanie sudo takýmto spôsobom za aspoň nebezpečné. Avšak:oPrečo nie ZFS…?

#apt-get install mdadm lvm2 thin-provisioning-tools btrfs-tools util-linux lsscsi nvme-cli mc
Keď inštalujeme softvér na náš počítač, v podstate požičiavame výkon nášho hardvéru vývojárom tohto softvéru.Keď dôverujeme tomuto softvéru pri ochrane našich dát, zaťažujeme sa úverom zodpovedajúcim hodnote obnovy týchto dát, ktorý raz budeme musieť splatiť.
Z tohto pohľadu je ZFS Ferrari, zatiaľ čo mdadm+lvm sa viac podobá bicyklu.
Subjektívne autor uprednostňuje požičiavať neznámym osobám ziskový bicykel pred Ferrarim. Cena nie je vysoká. Nie sú potrebné práva. Jednoduchšie dopravné predpisy. Parkovanie je bezplatné. Prechodnosť je lepšia. Na bicykel si vždy môžete pridať nohy a taktiež ho môžete opraviť vlastnými rukami.
Prečo teda BTRFS…?
Na naštartovanie operačného systému budeme potrebovať súborový systém podporovaný v Legacy/BIOS GRUB priamo z krabice, a pritom podporujúci snímky za behu. Použijeme ho pre /boot partíciu. Okrem toho autor preferuje používať tento FS pre / (koreň), pričom nezabúda poznamenať, že pre akýkoľvek iný softvér je možné vytvoriť samostatné partície na LVM a pripojiť ich do potrebných adresárov.Ani obrazy,
ani databázy nebudeme na tomto FS uchovávať. virtuálních strojůTento FS sa bude používať iba na vytváranie okamžitých snímok systému bez jeho vypnutia s následným prenášaním týchto snímok na záložný disk pomocou send/receive.
Okrem toho autor vo všeobecnosti preferuje mať minimum softvéru priamo na hardvéri a spúšťať celý ostatný softvér vo virtuálnych strojoch pomocou vecí ako prenášanie GPU a PCI-USB host kontrolérov do KVM cez IOMMU.
Na hardvéri ostáva len – uchovávanie dát, virtualizácia a zálohovanie.
Ak viac dôverujete ZFS, potom sú v podstate na uvedené použitie zamenniteľné.
Napriek tomu autor vedome ignoruje vstavané funkcie zrkadlenia/RAID a redundancie, ktoré sú k dispozícii v ZFS, BTRFS a LVM.
Napriek tomu autor vedome ignoruje vstavané funkcie zrkadlenia / RAID a redundancie, ktoré sú k dispozícii v ZFS, BTRFS a LVM.
Ako dodato argument, BTRFS má vlastnosť transformovať náhodný zápis na sekvenčný, čo mimoriadne pozitívne ovplyvňuje rýchlosť synchronizácie snímok / zálohovania na HDD.
Znovu preskenujeme všetky zariadenia:
#udevadm control --reload-rules && udevadm trigger
Pozrieme sa:
#lsscsi && nvme list
[0:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sda
[1:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdb
[2:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdc
[3:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdd
[4:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sde
[5:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdf
[6:0:0:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdg
[6:0:1:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdh
[6:0:2:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdi
[6:0:3:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdj
[6:0:4:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdk
[6:0:5:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdl
[6:0:6:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdm
[6:0:7:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdn
Node SN Model Namespace Usage Format FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1 S466NXXXXXXX15L Samsung SSD 970 EVO 500GB 1 0,00 GB / 500,11 GB 512 B + 0 B 2B2QEXE7
/dev/nvme1n1 S5H7NXXXXXXX48N Samsung SSD 970 EVO 500GB 1 0,00 GB / 500,11 GB 512 B + 0 B 2B2QEXE7
Rozdelenie „diskov“
NVMe SSD
No, nijako ich nebudeme rozdeľovať. Naše BIOS tieto úložiská aj tak nevidí. Takže pôjdu celkom do softvérového RAID. Rozdelenia tam ani nevytvoríme. Ak chceš striktne podľa „kanónu“ alebo „principiálne“ — vytvor jeden veľký oddiel, ako na HDD.
SATA HDD
Tu netreba vymýšľať nič špeciálne. Vytvoríme jeden oddiel na všetko. Oddiel vytvoríme preto, že tieto disky vidí BIOS a môže sa od nich pokúsiť bootovať. Neskôr nainštalujeme GRUB na tieto disky, aby sa systému to náhodou podarilo.
#cat >hdd.part << EOF
štítok: dos
štítok-id: 0x00000000
zariadenie: /dev/sdg
jednotka: sektory
/dev/sdg1 : start= 2048, size= 1953523120, type=fd, bootable
EOF
#sfdisk /dev/sdg < hdd.part
#sfdisk /dev/sdh < hdd.part
#sfdisk /dev/sdi < hdd.part
#sfdisk /dev/sdj < hdd.part
#sfdisk /dev/sdk < hdd.part
#sfdisk /dev/sdl < hdd.part
#sfdisk /dev/sdm < hdd.part
#sfdisk /dev/sdn < hdd.part
SATA SSD
Tu máme najzaujímavejšie možnosti.
Po prvé, naše úložiská majú veľkosť 2 TB. To je v rámci prípustného pre MBR, čo využijeme. V prípade potreby môžeme prejsť na GPT. GPT disky majú vrstvu kompatibility, ktorá umožňuje systémom kompatibilným s MBR vidieť prvé 4 oddiely, ak sú umiestnené v rámci prvých 2 terabajtov. Hlavné je, aby bootovací oddiel a oddiel bios_grub na týchto diskoch boli na začiatku. To umožňuje dokonca bootovanie z GPT diskov Legacy / BIOS.
Ale, to nie je náš prípad.
Tu budeme vytvárať dva oddiely. Prvý bude mať veľkosť 1 GB a bude použitý pre RAID 1 /boot.
Druhý bude použitý pre RAID 6 a zaberie všetok zvyšný voľný priestor, okrem malej nepartitionovanej oblasti na konci úložiska.
Čo je tá nepartitionovaná oblasť?Podľa zdrojov na internete majú naše SATA SSD na palube dynamicky rozširujúci SLC cache s veľkosťou od 6 do 78 gigabajtov. 6 gigabajtov dostaneme „zadarmo“ vďaka rozdielu medzi „gigabajtmi“ a „gigibajtami“ v technickom pase úložiska. Zvyšných 72 gigabajtov sa určuje z nevyužitého priestoru.
Tu treba poznamenať, že cache máme SLC, a miesto sa obsadzuje v režime 4 bit MLC. Čo pre nás efektívne znamená, že za každé 4 gigabajty voľného priestoru dostaneme len 1 gigabyte SLC cache.
Násobíme 72 gigabajty štyrmi a dostávame 288 gigabajtov. Toto je voľné miesto, ktoré nebudeme partitionovať, aby sme umožnili úložiskám plne využiť SLC cache.
Takto môžeme efektívne získať až 312 gigabajtov SLC cache celkovo zo šiestich úložných zariadení. Z týchto úložných zariadení budú 2 použité v RAID pre redundanciu.
Taký prísun cache nám umožní zriedkavo sa v praxi stretnúť so situáciou, keď zapisovanie neprebieha do cache. To veľmi dobre kompenzuje najväčší nedostatok QLC pamäte, – veľmi nízku rýchlosť zapisovania, keď sa dáta zapisujú mimo cache. Ak vaše záťaže tomuto nevyhovujú, odporúčam vám dôkladne uvažovať o tom, ako dlho vydržia vaše SSD pri takej záťaži zohľadňujúc TBW z technického preukazu.
#cat >ssd.part << EOF
štítok: dos
štítok-id: 0x00000000
zariadenie: \/dev\/sda
jednotka: sektory
/dev/sda1 : start= 2048, size= 2097152, type=fd, bootable
/dev/sda2 : start= 2099200, size= 3300950016, type=fd
EOF
#sfdisk /dev/sda < ssd.part
#sfdisk /dev/sdb < ssd.part
#sfdisk /dev/sdc < ssd.part
#sfdisk /dev/sdd < ssd.part
#sfdisk /dev/sde < ssd.part
#sfdisk /dev/sdf < ssd.part
Vytváranie polí
Na začiatok musíme premenovať stroj. Je to potrebné, pretože názov hostiteľa je súčasťou názvu poľa niekde vo vnútri mdadm a niekde to má vplyv. Samozrejme, polia môžeme neskôr premenovať, ale to sú zbytočné úkony.
#mcedit /etc/hostname
#mcedit /etc/hosts
#hostname
vdesk0
NVMe SSD
#mdadm --create --verbose --assume-clean /dev/md0 --level=1 --raid-devices=2 /dev/nvme[0-1]n1
Prečo —assume-clean…?Aby sme neinitializovali polia. Pre oba úrovne RAID 1 a 6 je to prijateľné. Všetko môže fungovať aj bez inicializácie, ak je to nové pole. Navyše, inicializácia poľa SSD pri vytvorení je zbytočné míňanie zdrojov TBW. Používame TRIM/DISCARD, kde je to možné, na zostavených poliach SSD, aby sme ich 'inicializovali'.
U polí SSD RAID 1 sa DISCARD podporuje priamo.
U polí SSD RAID 6 je potrebné zapnúť DISCARD v parametroch jadra.
Toto má zmysel robiť iba v prípade, ak všetky SSD používané v poliach úrovní 4/5/6 v tomto systéme majú funkčnú podporu discard_zeroes_data. Niekedy sa objavia zvláštne úložné zariadenia, ktoré oznámia jadru, že podporujú túto funkciu, ale v skutočnosti ju nemajú, alebo funkcia nefunguje vždy. V súčasnosti je podpora prakticky všade, avšak staršie úložné zariadenia a chybný firmware sa stále vyskytujú. Z tohto dôvodu je podpora DISCARD predvolene vypnutá pre RAID 6.
Pozor, nasledujúci príkaz zničí všetky dáta na NVMe úložných zariadeniach 'inicializovaním' poľa 'nulami'.
#blkdiscard /dev/md0
Ak sa niečo pokazilo, skúste určiť krok.
#blkdiscard --step 65536 /dev/md0
SATA SSD
#mdadm --create --verbose --assume-clean /dev/md1 --level=1 --raid-devices=6 /dev/sd[a-f]1
#blkdiscard /dev/md1
#mdadm --create --verbose --assume-clean /dev/md2 --chunk-size=512 --level=6 --raid-devices=6 /dev/sd[a-f]2
Prečo tak veľký…?Zvýšenie chunk-size pozitívne ovplyvňuje rýchlosť náhodného čítania blokmi až do chunk-size vrátane. K tomu dochádza, pretože jedna operácia zodpovedajúcej veľkosti alebo menšia môže byť úplne vykonaná na jednom zariadení. Preto sa IOPS zo všetkých zariadení sčíta. Podľa štatistík 99% IO nepresahuje 512K.
V RAID 6 sú IOPS na zápis vždy menšie alebo rovné IOPS jediného zariadenia. Na druhú stranu, pri náhodnom čítaní môže byť IOPS oveľa vyššie ako IOPS jedného zariadenia a tu má veľkosť bloku kľúčový význam.
Autor nevidí zmysel v pokusoch optimalizovať parameter, ktorý je v RAID 6 zle navrhnutý, a namiesto toho optimalizuje to, v čom sa RAID 6 ukazuje dobre.
Zlú náhodnú zapisovanie RAID 6 budeme kompenzovať vyrovnávacou pamäťou na NVMe a trikmi s thin-provisioning.
Zatiaľ sme nezapli DISCARD pre RAID 6. Takže „inicializovať“ tento array zatiaľ nebudeme. Urobíme to neskôr, — po nainštalovaní OS.
SATA HDD
#mdadm --create --verbose --assume-clean /dev/md3 --chunk-size=512 --level=6 --raid-devices=8 /dev/sd[g-n]1
LVM na NVMe RAID
Pre rýchlosť chceme umiestniť základný FS na NVMe RAID 1, ktorý je /dev/md0.
Napriek tomu, tento rýchly array budeme ešte potrebovať pre ďalšie potreby, ako swap, metadata a LVM-cache a metadata LVM-thin, preto na tomto array vytvoríme LVM VG.
#pvcreate /dev/md0
#vgcreate root /dev/md0
Vytvoríme oddiel pre základný FS.
#lvcreate -L 128G --name root root
Vytvoríme oddiel pre swap s veľkosťou operačnej pamäte.
#lvcreate -L 32G --name swap root
Inštalácia OS
Takže máme všetko potrebné na nainštalovanie systému.
Spúšťame inštalačný nástroj systému z prostredia Ubuntu Live. Bežná inštalácia. Iba na kroku výberu diskov na inštaláciu je potrebné uviesť nasledovné:
- /dev/md1, — точка монтирования /boot, ФС — BTRFS
- /dev/root/root (a.k.a /dev/mapper/root-root), — точка монтирования / (корень), ФС — BTRFS
- /dev/root/swap (a.k.a /dev/mapper/root-swap), — использовать как раздел подкачки
- Načítač nainštalujte na /dev/sda
Pri výbere BTRFS ako základného FS, — inštalátor automaticky vytvorí dva BTRFS objemy s názvami "@" pre / (koreň) a "@home" pre /home.
Zahajujeme inštaláciu...
Inštalácia sa ukončí modálnym oknom zobrazujúcim chybu inštalácie načítača. Bohužiaľ, nie je možné normálnym spôsobom opustiť toto dialogové okno a pokračovať v inštalácii. Odhlásime sa zo systému a znovu sa prihlásime, pričom sa dostaneme na čistú pracovnú plochu Ubuntu Live. Otvoríme terminál a znova:
#sudo bash
Vytvoríme chroot prostredie, aby sme mohli pokračovať v inštalácii:
#mkdir /mnt/chroot
#mount -o defaults,space_cache,noatime,nodiratime,discard,subvol=@ /dev/mapper/root-root /mnt/chroot
#mount -o defaults,space_cache,noatime,nodiratime,discard,subvol=@home /dev/mapper/root-root /mnt/chroot/home
#mount -o defaults,space_cache,noatime,nodiratime,discard /dev/md1 /mnt/chroot/boot
#mount --bind /proc /mnt/chroot/proc
#mount --bind /sys /mnt/chroot/sys
#mount --bind /dev /mnt/chroot/dev
Nastavíme sieť a hostname v chroot:
#cat /etc/hostname >/mnt/chroot/etc/hostname
#cat /etc/hosts >/mnt/chroot/etc/hosts
#cat /etc/resolv.conf >/mnt/chroot/etc/resolv.conf
Vstúpime do chroot prostredia:
#chroot /mnt/chroot
Na začiatku nainštalujeme balíky:
apt-get install --reinstall mdadm lvm2 thin-provisioning-tools btrfs-tools util-linux lsscsi nvme-cli mc debsums hdparm
Skontrolujeme a opravíme všetky balíky, ktoré sa neúspešne nainštalovali kvôli nedokončenej inštalácii systému:
#CORRUPTED_PACKAGES=$(debsums -s 2>&1 | awk '{print $6}' | uniq)
#apt-get install --reinstall $CORRUPTED_PACKAGES
Ak niečo nefunguje, možno budete musieť predtým upraviť /etc/apt/sources.list
Oprava parametrov pre modul RAID 6 na povolenie TRIM/DISCARD:
#cat >/etc/modprobe.d/raid456.conf << EOF
možnosti raid456 zariadenia_handle_discard_safely=1
EOF
Trochu prispôsobíme naše array:
#cat >/etc/udev/rules.d/60-md.rules << EOF
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/stripe_cache_size", ATTR{md/stripe_cache_size}="32768"
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/sync_speed_min", ATTR{md/sync_speed_min}="48000"
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/sync_speed_max", ATTR{md/sync_speed_max}="300000"
EOF
#cat >/etc/udev/rules.d/62-hdparm.rules << EOF
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", RUN+="/sbin/hdparm -B 254 /dev/%k"
EOF
#cat >/etc/udev/rules.d/63-blockdev.rules << EOF
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", RUN+="/sbin/blockdev --setra 1024 /dev/%k"
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="md*", RUN+="/sbin/blockdev --setra 0 /dev/%k"
EOF
Čo to bolo..?Vytvorili sme súbor pravidiel udev, ktoré budú robiť nasledovné:
- Stanovte adekvátnu veľkosť cache blokov pre RAID 6 na rok 2020. Predvolená hodnota sa zdá, že sa nezmenila od čias vzniku Linuxu a už dávno nie je adekvátna.
- Rezervujte minimálne IO počas kontrol/synchronizácií polí. To je potrebné, aby vaše polia nezostali v stave večnej synchronizácie pod záťažou.
- Obmedzte maximálne IO počas kontrol/synchronizácií polí. To je potrebné, aby synchronizácia/kontrola SSD RAID-ov nezahriala vaše disky do chrumkava. Osobitne aktuálne pre NVMe. (Pamätáte na chladič? Nemyslel som to ako žart.)
- Zakážte diskovým jednotkám prostredníctvom APM zastaviť rotáciu vretien (HDD) a nastavte časový limit pre spánok ovládačov diskov na 7 hodín. APM môžete úplne vypnúť, ak to vaše disky umožňujú (-B 255). Pri predvolenej hodnote sa disky zastavia po piatich sekundách. Potom bude OS chcieť zresetovať diskovú cache, disky sa opäť roztočia a všetko sa opakuje. Disky majú obmedzený maximálny počet otáčok vretien. Takýto jednoduchý cyklus podľa predvolených nastavení môže ľahko zabiť vaše disky za pár rokov. Týmto netrpia všetky disky, ale naše "notebookové" s príslušnými predvoľbami, ktoré z RAID-u robia krivé pokusy mini-MAID.
- Nastavte readahead na otáčajúcich sa diskoch na 1 megabajt — dva po sebe idúce bloky/chunky RAID 6
- Zakážte readahead na samotných poliach.
Upravíme /etc/fstab:
#cat >/etc/fstab << EOF
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
# file-system mount-point type options dump pass
/dev/mapper/root-root / btrfs defaults,space_cache,noatime,nodiratime,discard,subvol=@ 0 1
UUID=$(blkid -o value -s UUID /dev/md1) /boot btrfs defaults,space_cache,noatime,nodiratime,discard 0 2
/dev/mapper/root-root /home btrfs defaults,space_cache,noatime,nodiratime,discard,subvol=@home 0 2
/dev/mapper/root-swap none swap sw 0 0
EOF
Prečo tak..?Oddiel /boot budeme vyhľadávať podľa UUID, pretože názvy polí sa teoreticky môžu zmeniť.
Ostatné oddiely budeme vyhľadávať podľa LVM názvov v notácii /dev/mapper/vg-lv, pretože dostatočne unikátne identifikujú oddiely.
Nepoužívame UUID pre LVM, pretože UUID LVM objemov a ich snapshotov môže súhlasiť.Dvakrát pripojíme /dev/mapper/root-root..?Áno. Presne tak. Osobitosť BTRFS. Tento súborový systém možno namontovať viackrát s rôznymi subvol.
Vzhľadom na túto istú zvláštnosť odporúčam nikdy nevytvárať LVM snapshoty aktívnych BTRFS objemov. Môžete si pri reštarte vytvoriť prekvapenie.
Pre-generate the mdadm config:
#/usr/share/mdadm/mkconf | sed 's/#DEVICE/DEVICE/g' >/etc/mdadm/mdadm.conf
Upravíme nastavenia LVM:
#cat >>/etc/lvm/lvmlocal.conf << EOF
activation {
thin_pool_autoextend_threshold=90
thin_pool_autoextend_percent=5
}
allocation {
cache_pool_max_chunks=2097152
}
devices {
global_filter=["r|^/dev/.*_corig$|","r|^/dev/.*_cdata$|","r|^/dev/.*_cmeta$|","r|^/dev/.*gpv$|","r|^/dev/images/.*$|","r|^/dev/mapper/images.*$|","r|^/dev/backup/.*$|","r|^/dev/mapper/backup.*$|"]
issue_discards=1}
}
EOF
Čo to bolo..?Aktivovali sme automatické rozšírenie LVM thin pool pri dosiahnutí 90% zaplnenia o 5% z objemu.
Zvýšili sme maximálny počet cache blokov pre LVM cache.
Zakázali sme LVM vyhľadávať LVM objemy (PV) na:
- zariadeniach obsahujúcich LVM cache (cdata).
- zariadeniach, ktoré sú vyrovnané pomocou LVM cache obchádzajúc cache (_corig). Samotné cache zariadenie však bude stále skenované cez cache (len ).
- zariadeniach obsahujúcich metadata LVM cache (cmeta).
- na všetkých zariadeniach vo VG s názvom images. Tu budeme mať obrazy diskov virtuálnych strojov a nechceme, aby LVM na hostiteľovi aktivoval objemy patriace hosťujúcemu operačnému systému.
- na všetkých zariadeniach vo VG s názvom backup. Tu budeme mať zálohy obrazov virtuálnych strojov.
- na všetkých zariadeniach, ktorých názov končí na „gpv“ (guest physical volume).
Zaviedli sme podporu DISCARD pri uvoľňovaní voľného priestoru na LVM VG. Buďte opatrní. To spôsobí, že odstránenie LV na SSD môže byť dosť dlhé. Týka sa to najmä SSD RAID 6. Napriek tomu plánujeme použiť thin provisioning, takže nám to vôbec nebude prekážať.
Aktualizujeme obraz initramfs:
#update-initramfs -u -k all
Nainštalujeme a nakonfigurujeme grub:
#apt-get install grub-pc
#apt-get purge os-prober
#dpkg-reconfigure grub-pc
Aké disky vybrať?Všetky, ktoré sú sd*. Systém by sa mal byť schopný spustiť z akéhokoľvek fungujúceho SATA disku alebo SSD.
Prečo sme odpojení os-prober..?Za prílišnú samostatnosť a neposedné ruky.
Nepracuje správne, ak je jeden z RAID-ov v degradovanom stave. Snaží sa hľadať OS na oddieloch, ktoré sa používajú vo virtuálnych strojoch bežiacich na tomto hardvéri.
Ak ho potrebujete, môžete ho nechať, ale majte na pamäti všetky vyššie uvedené faktory. Odporúčam hľadať recepty na elimináciu neposedných rúk na internete.
Týmto sme ukončili počiatočnú inštaláciu. Prišiel čas reštartovať sa do novoinštalovaného OS. Nezabudnite odstrániť zavádzací Live CD/USB.
#exit
#reboot
Ako zavádzacie zariadenie vyberáme ktorýkoľvek zo SATA SSD.
LVM na SATA SSD.
Do tohto okamihu sme už spustili novú OS, nastavili sieť, apt, otvorili emulátor terminálu a spustili:
#sudo bash
Pokračujeme.
Inicializujeme pole zo SATA SSD:
#blkdiscard /dev/md2
Ak to nevyšlo, skúste:
#blkdiscard --step 65536 /dev/md2
Vytvárame LVM VG na SATA SSD:
#pvcreate /dev/md2
#vgcreate data /dev/md2
Prečo ešte jedna VG..?Naozaj, už máme VG s názvom root. Prečo nepridať všetko do jednej VG?
Ak je v VG niekoľko PV, všetky PV musia byť prítomné (online), aby sa VG správne aktivovalo. Výnimku tvoria LVM RAID, ktorý úmyselne nepoužívame.
Veľmi si prajeme, aby sa operačný systém pri zlyhaní (čítaj strate dát) na akomkoľvek z RAID 6 polí spustil normálne a dal nám možnosť problém vyriešiť.
Na prvom stupni abstrakcie izolujeme každý typ fyzického 'nositeľa' do samostatného VG.
Ak to poviem vedecky, rôzne RAID polia patria k rôznym 'domenám spoľahlivosti'. Nesmiete vytvárať pre ne ďalší spoločný bod zlyhania tým, že ich zmestíte do jednej VG.
Prítomnosť LVM na 'hardvéri' nám umožní rôzne rezať kusy rôznych RAID polí a rôzne ich kombinovať. Napríklad – spustiť súčasne bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, zložitú konfiguráciu ZFS s cache alebo akúkoľvek inú hybridnú zmes, aby sme to všetko mohli vyskúšať a porovnať.
Na 'hardvéri' nebudeme používať nič iné ako staré dobré 'tucet' LVM zväzkov. Možno výnimkou z tohto pravidla bude oddiel pre zálohovanie.
Myslím, že v tomto momente už mnohí čitatelia začali niečo podozrievať ohľadom matriošky.
LVM na SATA HDD
#pvcreate /dev/md3
#vgcreate backup /dev/md3
Opäť nová VG..?Veľmi si prajeme, aby sa náš operačný systém pri zlyhaní poľa diskov, ktoré budeme používať na zálohovanie dát, naďalej normálne spúšťal a súčasne zachoval prístup k nezálohovaným dátam. Preto, aby sme predišli problémom s aktiváciou VG, vytvárame samostatnú VG.
Nastavenie LVM cache
Vytvoríme LV na NVMe RAID 1, aby sme ho použili ako cache zariadenie.
#lvcreate -L 70871154688B --name cache root
Prečo tak málo…?Ide o to, že naše NVMe SSD majú tiež SLC cache. 4 gigabajty 'bezplatného' a 18 gigabajtov dynamického vďaka voľnému priestoru obsadenému v 3-bit MLC. Po vyčerpaní tejto cache sa NVMe SSD nebudú veľmi líšiť v rýchlosti od nášho SATA SSD s cache. Práve z tohto dôvodu nemá zmysel robiť LVM cache oddiel oveľa väčší než dvakrát objem SLC cache NVMe zariadenia. Pre používané NVMe zariadenia považuje autor za rozumné nastaviť cache na 32-64 gigabajtov.
Uvedená veľkosť oddielu je potrebná na usporiadanie 64 gigabajtov cache, umiestnenie metadát cache a zálohy metadát.
Navyše by som chcel poznamenať, že po nečistom vypnutí systému LVM označí celú vyrovnávaciu pamäť ako nečistú a bude ju znova synchronizovať. Navyše sa toto bude opakovať pri každom použití lvchange na tomto zariadení až do nového reštartu systému. Preto odporúčam okamžite prepracovať vyrovnávaciu pamäť pomocou zodpovedajúceho skriptu.
Vytvoríme LV na SATA RAID 6, aby sme ho mohli použiť ako vyrovnávaciu pamäť.
#lvcreate -L 3298543271936B --name cache data
Prečo len tri terabajty..?Aby bolo možné, ak je to potrebné, použiť SATA SSD RAID 6 na iné účely. Veľkosť vyrovnávacej pamäti je možné dynamicky zvýšiť za behu, bez zastavenia systému. Na to je potrebné dočasne zastaviť a znovu aktivovať vyrovnávaciu pamäť, ale rozdielnou výhodou LVM-cache v porovnaní napríklad s bcache je, že to je možné robiť za behu.
Vytvoríme novú VG pre vyrovnávaciu pamäť.
#pvcreate /dev/root/cache
#pvcreate /dev/data/cache
#vgcreate cache /dev/root/cache /dev/data/cache
Vytvoríme LV na vyrovnávacej pamäti.
#lvcreate -L 3298539077632B --name cachedata cache /dev/data/cache
Tu sme okamžite využili všetok voľný priestor na /dev/data/cache, aby sa všetky potrebné oddiely vytvorili priamo na /dev/root/cache. Ak sa niečo vytvorilo nesprávne, môžete to presunúť pomocou pvmove.
Vytvoríme a aktivujeme vyrovnávaciu pamäť:
#lvcreate -y -L 64G -n cache cache /dev/root/cache
#lvcreate -y -L 1G -n cachemeta cache /dev/root/cache
#lvconvert -y --type cache-pool --cachemode writeback --chunksize 64k --poolmetadata cache/cachemeta cache/cache
#lvconvert -y --type cache --cachepool cache/cache cache/cachedata
Prečo taký chunksize..?Metódou praktických experimentov autor zistil, že najlepší výsledok sa dosiahne, ak veľkosť bloku LVM cache zodpovedá veľkosti bloku LVM thin. Pri tom, čím menšia je veľkosť, tým lepšie sa konfigurácia osvedčuje pri náhodnom zápise.
64k je minimálna veľkosť bloku povolená pre LVM thin.
Buďte opatrní, writeback..!Áno. Tento typ vyrovnávacej pamäte odkladá synchronizáciu zápisu na vyrovnávaciu pamäťové zariadenie. To vedie k tomu, že v prípade straty vyrovnávacej pamäte môžu byť údaje na vyrovnávacej pamäti stratené. Neskôr autor řekne, aké opatrenia, okrem NVMe RAID 1, je možné prijať na kompenzáciu tohto rizika.
Tento typ vyrovnávacej pamäte bol zvolený zámerne na kompenzáciu nízkej výkonnosti RAID 6 pri náhodnom zápise.
Skontrolujme, čo sme získali:
#lvs -a -o lv_name,lv_size,devices --units B cache
LV LSize Zariadenia
[cache] 68719476736B cache_cdata(0)
[cache_cdata] 68719476736B /dev/root/cache(0)
[cache_cmeta] 1073741824B /dev/root/cache(16384)
cachedata 3298539077632B cachedata_corig(0)
[cachedata_corig] 3298539077632B /dev/data/cache(0)
[lvol0_pmspare] 1073741824B /dev/root/cache(16640)
Na /dev/data/cache by sa mala nachádzať len [cachedata_corig]. Ak niečo nie je v poriadku, použite pvmove.
Vyrovnávaciu pamäť môžete v prípade potreby vypnúť jedným príkazom:
#lvconvert -y --uncache cache/cachedata
Toto sa robí online. LVM iba synchronizuje vyrovnávaciu pamäť na disk, odstráni ju a premenováva cachedata_corig späť na cachedata.
Nastavenie LVM thin
Približne odhadneme, koľko miesta budeme potrebovať pre metadáta LVM thin:
#thin_metadata_size --block-size=64k --pool-size=6terabytes --max-thins=100000 -u bytes
thin_metadata_size - odhadovaná veľkosť oblasti metadat 3385794560 bajtov pre "--block-size=64kibibytes --pool-size=6terabytes --max-thins=100000"
Zaokrúhlime na 4 GB: 4294967296B
Vynásobíme dvoma a pridáme 4194304B pre metadáta LVM PV: 8594128896B
Vytvoríme samostatnú partíciu na NVMe RAID 1, aby sme na nej umiestnili metadáta LVM thin a ich zálohu:
#lvcreate -L 8594128896B --name images root
Prečo..?Môže vzniknúť otázka, prečo umiestniť metadáta LVM thin samostatne, keď budú aj tak vyrovnávané do NVMe a budú pracovať rýchlo.
Rýchlosť je dôležitá, ale nie je hlavným dôvodom. Ide o to, že cache je bod zlyhania. Môže sa mu niečo stať a ak budú metadáta LVM thin v cache, dôjde k úplnej strate všetkého. Bez celých metadát bude takmer nemožné obnoviť tenké zväzky.
Presunutím metadát na samostatný, necacheovaný, ale rýchly zväzok, zaručujeme ich bezpečnosť v prípade straty alebo poškodenia cache. V takom prípade budú všetky poškodenia spôsobené stratou cache lokalizované vo vnútri tenkých zväzkov, čo značne zjednoduší proces obnovy. S vysokou pravdepodobnosťou sa dajú tieto poškodenia obnoviť pomocou súborových systémových žurnálov.
Navyše, ak bol predtým vykonaný okamžitý snímok tenkého zväzku a po ňom bola cache aspoň raz úplne synchronizovaná, v dôsledku špecifík vnútorného zariadenia LVM thin bude zaručená integrita snímku v prípade straty cache.
Vytvoríme nový VG, ktorý sa bude zaoberať thin-provisioning:
#pvcreate /dev/root/images
#pvcreate /dev/cache/cachedata
#vgcreate images /dev/root/images /dev/cache/cachedata
Vytvoríme pool:
#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Prečo -Z yOkrem toho, na čo je tento režim určený — teda aby zabránil úniku dát z jednej virtuálnej mašiny do druhej pri prerozdeľovaní priestoru — sa zeroing dodatočne používa na zvýšenie rýchlosti náhodného zápisu blokmi menšími ako 64k. Akýkoľvek zápis menší ako 64k do predtým nealokovanej oblasti tenkého zväzku sa premení na 64K vyrovnané podľa hranice cache. To umožní vykonať operáciu úplne cez cache mimo cacheovaného zariadenia.
Presunieme LV na zodpovedajúce PV:
#pvmove -n images/thin-pool_tdata /dev/root/images /dev/cache/cachedata
#pvmove -n images/lvol0_pmspare /dev/cache/cachedata /dev/root/images
#pvmove -n images/thin-pool_tmeta /dev/cache/cachedata /dev/root/images
Skontrolujeme:
#lvs -a -o lv_name,lv_size,devices --units B images
LV LSize Zariadenia
[lvol0_pmspare] 4294967296B /dev/root/images(0)
tenký-pool 274877906944B tenký-pool_tdata(0)
[thin-pool_tdata] 274877906944B /dev/cache/cachedata(0)
[thin-pool_tmeta] 4294967296B /dev/root/images(1024)
Vytvoríme tenký zväzok pre testy:
#lvcreate -V 64G --thin-pool thin-pool --name test images
Nainštalujeme balíky na testovanie a sledovanie:
#apt-get install sysstat fio
Takto môžeme sledovať správanie našej skladovacej konfigurácie v reálnom čase:
#watch 'lvs --rows --reportformat basic --quiet -ocache_dirty_blocks,cache_settings cache/cachedata && (lvdisplay cache/cachedata | grep Cache) && (sar -p -d 2 1 | grep -E "sd|nvme|DEV|md1|md2|md3|md0" | grep -v Average | sort)'
Takto môžeme otestovať našu konfiguráciu:
#fio --loops=1 --size=64G --runtime=4 --filename=/dev/images/test --stonewall --ioengine=libaio --direct=1
--name=4kQD32read --bs=4k --iodepth=32 --rw=randread
--name=8kQD32read --bs=8k --iodepth=32 --rw=randread
--name=16kQD32read --bs=16k --iodepth=32 --rw=randread
--name=32KQD32read --bs=32k --iodepth=32 --rw=randread
--name=64KQD32read --bs=64k --iodepth=32 --rw=randread
--name=128KQD32read --bs=128k --iodepth=32 --rw=randread
--name=256KQD32read --bs=256k --iodepth=32 --rw=randread
--name=512KQD32read --bs=512k --iodepth=32 --rw=randread
--name=4Kread --bs=4k --rw=read
--name=8Kread --bs=8k --rw=read
--name=16Kread --bs=16k --rw=read
--name=32Kread --bs=32k --rw=read
--name=64Kread --bs=64k --rw=read
--name=128Kread --bs=128k --rw=read
--name=256Kread --bs=256k --rw=read
--name=512Kread --bs=512k --rw=read
--name=Seqread --bs=1m --rw=read
--name=Longread --bs=8m --rw=read
--name=Longwrite --bs=8m --rw=write
--name=Seqwrite --bs=1m --rw=write
--name=512Kwrite --bs=512k --rw=write
--name=256write --bs=256k --rw=write
--name=128write --bs=128k --rw=write
--name=64write --bs=64k --rw=write
--name=32write --bs=32k --rw=write
--name=16write --bs=16k --rw=write
--name=8write --bs=8k --rw=write
--name=4write --bs=4k --rw=write
--name=512KQD32write --bs=512k --iodepth=32 --rw=randwrite
--name=256KQD32write --bs=256k --iodepth=32 --rw=randwrite
--name=128KQD32write --bs=128k --iodepth=32 --rw=randwrite
--name=64KQD32write --bs=64k --iodepth=32 --rw=randwrite
--name=32KQD32write --bs=32k --iodepth=32 --rw=randwrite
--name=16KQD32write --bs=16k --iodepth=32 --rw=randwrite
--name=8KQD32write --bs=8k --iodepth=32 --rw=randwrite
--name=4kQD32write --bs=4k --iodepth=32 --rw=randwrite
| grep -E 'read|write|test' | grep -v ioengine
Pozor! Zdroje!Tento kód spustí 36 rôznych testov, z ktorých každé bude trvať 4 sekundy. Polovica testov je na zápis. Za 4 sekundy sa na NVMe dá zapísať veľmi veľa. Až 3 gigabajty za sekundu. Takže každý beh testov na zápis môže spotrebovať až 216 gigabajtov SSD zdrojov.
Čítanie a zápis naraz?Áno. Testy čítania a zápisu je rozumné spúšťať oddelene. Viac než to, je rozumné zabezpečiť, aby boli všetky cache synchronizované, aby predchádzajúci zápis nemal vplyv na čítanie.
Výsledky sa budú výrazne líšiť pri prvom spustení a následných, pričom sa berie do úvahy naplnenie cache a tenkého objemu, ako aj to, či sa systém podarilo synchronizovať cache, ktoré boli naplnené pri predchádzajúcom behu.
Okrem iného odporúčam zmerať rýchlosť na už naplnenom tenkom objeme, z ktorého bol pred chvíľou vyhotovený snapshot. Autor mal možnosť pozorovať, ako sa náhodný zápis náhle urýchľuje hneď po vytvorení prvého snapshotu, najmä keď cache ešte nie je úplne naplnéná. K tomu dochádza vďaka semantike copy-on-write zápisu, vyrovnávaniu blokov cache a tenkého objemu, a tomu, že náhodný zápis na RAID 6 sa mení na náhodné čítanie s RAID 6 s následným zápisom do cache. V našej konfigurácii je náhodné čítanie s RAID 6 až 6-krát (počet SATA SSD v poli) rýchlejšie ako zápis. Keďže bloky pre CoW sa prideľujú sekvenčne z tenkého poolu, väčšinou sa zápis zmení aj na sekvenčný.
Obe tieto vlastnosti je možné efektívne využiť.
Cache-„koherentné“ snapshoty
Aby sa znížilo riziko straty dát v prípade poškodenia/poklesu cache, autor navrhuje zaviesť prax rotácie snapshotov, ktorá zabezpečuje ich integritu v tomto prípade.
Po prvé, vzhľadom na to, že metadata tenkých objemov sú umiestnené na zariadení bez cache, metadata budú intact a možné straty budú izolované v rámci blokov dát.
Nasledujúci cyklus rotácie snapshotov zaručuje integritu dát v rámci snapshotov v prípade straty cache:
- Pre každý tenký objem s menom vytvoríme snapshot s menom .cached
- Nastavíme migration threshold na rozumnú vysokú hodnotu:
#lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata - V cykle kontrolujeme počet špinavých blokov v cache:
#lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}'kým nedostaneme nulu. Ak nulová hodnota chýba príliš dlho, môže sa dočasne vytvoriť prechodom cache do režimu writethrough. Avšak, zohľadňujúc rýchlostné charakteristiky našich polí SATA a NVMe SSD, ako aj ich životnosť TBW, buď budete schopní rýchlo zachytiť moment aj bez zmeny režimu cache, alebo vaše zariadenie úplne vyčerpá svoj zdroj za niekoľko dní. Vzhľadom na obmedzenia zdroja systém nie je schopný neustále fungovať pri 100% zaťažení zápisom. Naše NVMe SSD pri 100% zaťažení zápisom úplne vyčerpajú zdroj za 3-4 dni. SATA SSD prežijú iba dvakrát dlhšie. Preto budeme považovať, že väčšina zaťaženia ide na čítanie, a na zápis máme relatívne krátkodobé výbuchy extrémnej aktivity v kombinácii s nízkym zaťažením v priemere. - Akonáhle sme zachytili (alebo vytvorili) nulu — premenováme <meno>.cached na <meno>.committed. Starý <meno>.committed v tomto prípade odstránime.
- Voliteľne, ak je cache vyplnená na 100%, môže sa znova vytvoriť skriptom, čím sa vyčistí. S čiastočne prázdnou cache systém pracuje oveľa rýchlejšie na zápis.
- Nastavíme migračný prah na nulu:
#lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedataTo dočasne zakáže synchronizáciu cache na hlavné médium. - Čakáme, pokiaľ sa v cache nazbiera dostatok zmien
#lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}'alebo nastane časovač. - Opakujeme znova.
Načo zložitosti s migračným prahom…?Ide o to, že v reálnej praxi je „náhodný“ zápis v skutočnosti celkom predvídateľný. Ak zapíšeme niečo do sektora veľkosti 4 kilobajty, existuje veľká pravdepodobnosť, že v nasledujúcich pár minútach bude zapísaná informácia do tohto alebo jedného z susedných (+- 32K) sektorov.
Nastavením migračného prahu na nulu odkladáme synchronizáciu zápisu na SATA SSD a agregujeme niekoľko zmien jedného bloku 64K v cache. Takto výrazne šetríme zdroj SATA SSD.
A kde je kód..?Žiaľ, autor sa považuje za nedostatočne kompetentného v oblasti vývoja bash skriptov, pretože je stopercentný samouk a praktizuje „google“-driven development, preto považuje ten hrozný kód, ktorý vychádza z jeho rúk, za najlepšie nepoužívať nikomu inému.
Myslím, že profesionáli v tejto oblasti dokážu sami zrealizovať celú vyššie popísanú logiku, ak to bude potrebné, a možno to aj pekne zrealizovať ako systemd službu, ako sa o to pokúsil autor.
Jednoduchý systém rotácie snímok nám umožní nielen mať neustále jeden úplne synchronizovaný snímok na SATA SSD, ale aj pomocou utilitky thin_delta zistiť, ktoré bloky sa zmenili po jeho vytvorení, a tak lokalizovať poškodenia na základných zväzkoch a veľmi uľahčiť obnovu.
TRIM/DISCARD v libvirt/KVM
Keďže úložisko bude používané pre KVM riadené libvirtom, bolo by dobré naučiť naše VM nielen zaberanie voľného miesta, ale aj uvoľňovanie už nepotrebného.
To sa robí pomocou emulácie podpory TRIM/DISCARD na virtuálnych diskoch. Na to je potrebné zmeniť typ ovládača na virtio-scsi a upraviť xml.
#virsh edit vmname
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='writethrough' io='threads' discard='unmap'/>
<source dev='/dev/images/vmname'/>
<backingStore/>
<target dev='sda' bus='scsi'/>
<alias name='scsi0-0-0-0'/>
</disk>
<controller type='scsi' index='0' model='virtio-scsi'>
<alias name='scsi0'/>
</controller>
Takéto DISCARDy z hosťovských OS sú správne spracovávané LVMom, a bloky sú správne uvoľňované ako v cache, tak aj v tenkom puhle. V našom prípade sa to deje väčšinou oneskorene, pri odstraňovaní ďalšieho snímku.
Zálohovanie BTRFS
Použiť hotové skripty s veľkou opatrnosťou a na vlastné riziko. Autor písal tento kód sám a výhradne pre seba. Som si istý, že mnohí skúsení používatelia Linuxu majú podobné záplaty a kopírovať cudzí nebude potrebné.
Vytvoríme zväzok na záložnom zariadení:
#lvcreate -L 256G --name backup backup
Naformátujeme v BTRFS:
#mkfs.btrfs /dev/backup/backup
Vytvoríme montážne body a pripojíme root podadresáre FS:
#mkdir /backup
#mkdir /backup/btrfs
#mkdir /backup/btrfs/root
#mkdir /backup/btrfs/back
#ln -s /boot /backup/btrfs
# cat >>/etc/fstab << EOF
/dev/mapper/root-root /backup/btrfs/root btrfs defaults,space_cache,noatime,nodiratime 0 2
/dev/mapper/backup-backup /backup/btrfs/back btrfs defaults,space_cache,noatime,nodiratime 0 2
EOF
#mount -a
#update-initramfs -u
#update-grub
Vytvoríme adresáre pre zálohy:
#mkdir /backup/btrfs/back/remote
#mkdir /backup/btrfs/back/remote/root
#mkdir /backup/btrfs/back/remote/boot
Vytvoríme adresár pre zálohovacie skripty:
#mkdir /root/btrfs-backup
Skopírujeme skript:
Veľa zložitých bash kódov. Používajte na vlastné riziko. Autorovi neposielajte hnevné maily…#cat >/root/btrfs-backup/btrfs-backup.sh << EOF
#!/bin/bash
CESTA="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"
LOCK_FILE="/dev/shm/$SCRIPT_NAME.lock"
DATE_PREFIX='%Y-%m-%d'
DATE_FORMAT=$DATE_PREFIX'-%H-%M-%S'
DATE_REGEX='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
BASE_SUFFIX=".@base"
PEND_SUFFIX=".@pend"
SNAP_SUFFIX=".@snap"
MOUNTS="/backup/btrfs/"
BACKUPS="/backup/btrfs/back/remote/"
function terminate ()
{
echo "$1" >&2
exit 1
}
function wait_lock()
{
flock 98
}
function wait_lock_or_terminate()
{
echo "Čakám na zámok..."
wait_lock || terminate "Zlyhalo získanie zámku. Ukončujem..."
echo "Získal som zámok..."
}
function suffix()
{
FORMATTED_DATE=$(date +"$DATE_FORMAT")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}
function filter()
{
FORMATTED_DATE=$(date --date="$1" +"$DATE_PREFIX")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}
function backup()
{
SOURCE_PATH="$MOUNTS$1"
TARGET_PATH="$BACKUPS$1"
SOURCE_BASE_PATH="$MOUNTS$1$BASE_SUFFIX"
TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
TARGET_BASE_DIR="$(dirname $TARGET_BASE_PATH)"
SOURCE_PEND_PATH="$MOUNTS$1$PEND_SUFFIX"
TARGET_PEND_PATH="$BACKUPS$1$PEND_SUFFIX"
if [ -d "$SOURCE_BASE_PATH" ]
then
echo "$SOURCE_BASE_PATH nájdený"
else
echo "$SOURCE_BASE_PATH Súbor nenájdený, vytváram snapshot z $SOURCE_PATH do $SOURCE_BASE_PATH"
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_BASE_PATH
sync
if [ -d "$TARGET_BASE_PATH" ]
then
echo "$TARGET_BASE_PATH nájdený, nesprávne synchronizovaný so zdrojom... odstraňujem..."
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
fi
fi
if [ -d "$TARGET_BASE_PATH" ]
then
echo "$TARGET_BASE_PATH nájdený"
else
echo "$TARGET_BASE_PATH nenájdený. Synchronizujem do $TARGET_BASE_DIR"
btrfs send $SOURCE_BASE_PATH | btrfs receive $TARGET_BASE_DIR
sync
fi
if [ -d "$SOURCE_PEND_PATH" ]
then
echo "$SOURCE_PEND_PATH nájdený, odstraňujem..."
btrfs subvolume delete -c $SOURCE_PEND_PATH
sync
fi
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_PEND_PATH
sync
if [ -d "$TARGET_PEND_PATH" ]
then
echo "$TARGET_PEND_PATH nájdený, odstraňujem..."
btrfs subvolume delete -c $TARGET_PEND_PATH
sync
fi
echo "Posielam $SOURCE_PEND_PATH do $TARGET_PEND_PATH"
btrfs send -p $SOURCE_BASE_PATH $SOURCE_PEND_PATH | btrfs receive $TARGET_BASE_DIR
sync
TARGET_DATE_SUFFIX=$(suffix)
btrfs subvolume snapshot -r $TARGET_PEND_PATH "$TARGET_PATH$TARGET_DATE_SUFFIX"
sync
btrfs subvolume delete -c $SOURCE_BASE_PATH
sync
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
mv $SOURCE_PEND_PATH $SOURCE_BASE_PATH
mv $TARGET_PEND_PATH $TARGET_BASE_PATH
sync
}
function list()
{
LIST_TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
LIST_TARGET_BASE_DIR="$(dirname $LIST_TARGET_BASE_PATH)"
LIST_TARGET_BASE_NAME="$(basename -s .$BASE_SUFFIX $LIST_TARGET_BASE_PATH)"
find "$LIST_TARGET_BASE_DIR" -maxdepth 1 -mindepth 1 -type d -printf "%fn" | grep "${LIST_TARGET_BASE_NAME/$BASE_SUFFIX/$SNAP_SUFFIX}.$DATE_REGEX"
}
function remove()
{
REMOVE_TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
REMOVE_TARGET_BASE_DIR="$(dirname $REMOVE_TARGET_BASE_PATH)"
btrfs subvolume delete -c $REMOVE_TARGET_BASE_DIR/$2
sync
}
function removeall()
{
DATE_OFFSET="$2"
FILTER="$(filter "$DATE_OFFSET")"
while read -r SNAPSHOT ; do
remove "$1" "$SNAPSHOT"
done < <(list "$1" | grep "$FILTER")
}
(
COMMAND="$1"
shift
case "$COMMAND" in
"--help")
echo "Pomoc"
;;
"suffix")
suffix
;;
"filter")
filter "$1"
;;
"backup")
wait_lock_or_terminate
backup "$1"
;;
"list")
list "$1"
;;
"remove")
wait_lock_or_terminate
remove "$1" "$2"
;;
"removeall")
wait_lock_or_terminate
removeall "$1" "$2"
;;
*)
echo "Žiadne.."
;;
esac
) 98>$LOCK_FILE
EOF
Čo vlastne robí..?Obsahuje súbor základných príkazov na vytváranie snapshotov BTRFS a ich kopírovanie na iný FS prostredníctvom BTRFS send/receive.
Prvý spustenie môže byť relatívne dlhé, pretože na začiatku budú skopírované všetky dáta. Následné spustenia budú veľmi rýchle, pretože sa budú kopírovať len zmeny.
Ešte jeden skript, ktorý vložíme do cronu:
Ešte kúsok bash-kódu#cat >/root/btrfs-backup/cron-daily.sh << EOF
#!/bin/bash
CESTA="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"
BACKUP_SCRIPT="$SCRIPT_DIR/btrfs-backup.sh"
RETENTION="-60 dní"
$BACKUP_SCRIPT backup root/@
$BACKUP_SCRIPT removeall root/@ "$RETENTION"
$BACKUP_SCRIPT backup root/@home
$BACKUP_SCRIPT removeall root/@home "$RETENTION"
$BACKUP_SCRIPT backup boot/
$BACKUP_SCRIPT removeall boot/ "$RETENTION"
EOF
Čo robí..?Vytvára a synchronizuje na backup FS inkrementálne snímky uvedených BTRFS-objemov. Po tom odstraňuje všetky snímky vytvorené pred 60 dňami. Po spustení v podpriečinkoch /backup/btrfs/back/remote/ sa objavia datované snímky uvedených objemov.
Dáme kódu práva na vykonávanie:
#chmod +x /root/btrfs-backup/cron-daily.sh
#chmod +x /root/btrfs-backup/btrfs-backup.sh
Skontrolujeme a vložíme do cronu:
#/usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/btrfs-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t btrfs-backup
#cat /var/log/syslog | grep btrfs-backup
#crontab -e
0 2 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/btrfs-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t btrfs-backup
Zálohovanie LVM thin
Vytvoríme tenký pool na záložnom zariadení:
#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T backup/thin-pool
Nainštalujeme ddrescue, pretože skripty budú tento nástroj používať:
#apt-get install gddrescue
Vytvoríme adresár pre skripty:
#mkdir /root/lvm-thin-backup
Skopírujeme skripty:
Veľmi veľa bashu vo vnútri...#cat >/root/lvm-thin-backup/lvm-thin-backup.sh << EOF
#!/bin/bash
CESTA="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"
LOCK_FILE="/dev/shm/$SCRIPT_NAME.lock"
DATE_PREFIX='%Y-%m-%d'
DATE_FORMAT=$DATE_PREFIX'-%H-%M-%S'
DATE_REGEX='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
BASE_SUFFIX=".base"
PEND_SUFFIX=".pend"
SNAP_SUFFIX=".snap"
BACKUPS="backup"
BACKUPS_POOL="thin-pool"
export LVM_SUPPRESS_FD_WARNINGS=1
function terminate ()
{
echo "$1" >&2
exit 1
}
function wait_lock()
{
flock 98
}
function wait_lock_or_terminate()
{
echo "Čakám na zámok..."
wait_lock || terminate "Zlyhalo získanie zámku. Ukončujem..."
echo "Získal som zámok..."
}
function suffix()
{
FORMATTED_DATE=$(date +"$DATE_FORMAT")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}
function filter()
{
FORMATTED_DATE=$(date --date="$1" +"$DATE_PREFIX")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}
function read_thin_id {
lvs --rows --reportformat basic --quiet -othin_id "$1/$2" | awk '{print $2}'
}
function read_pool_lv {
lvs --rows --reportformat basic --quiet -opool_lv "$1/$2" | awk '{print $2}'
}
function read_lv_dm_path {
lvs --rows --reportformat basic --quiet -olv_dm_path "$1/$2" | awk '{print $2}'
}
function read_lv_active {
lvs --rows --reportformat basic --quiet -olv_active "$1/$2" | awk '{print $2}'
}
function read_lv_chunk_size {
lvs --rows --reportformat basic --quiet --units b --nosuffix -ochunk_size "$1/$2" | awk '{print $2}'
}
function read_lv_size {
lvs --rows --reportformat basic --quiet --units b --nosuffix -olv_size "$1/$2" | awk '{print $2}'
}
function activate_volume {
lvchange -ay -Ky "$1/$2"
}
function deactivate_volume {
lvchange -an "$1/$2"
}
function read_thin_metadata_snap {
dmsetup status "$1" | awk '{print $7}'
}
function thindiff()
{
DIFF_VG="$1"
DIFF_SOURCE="$2"
DIFF_TARGET="$3"
DIFF_SOURCE_POOL=$(read_pool_lv $DIFF_VG $DIFF_SOURCE)
DIFF_TARGET_POOL=$(read_pool_lv $DIFF_VG $DIFF_TARGET)
if [ "$DIFF_SOURCE_POOL" == "" ]
then
(>&2 echo "Zdroj LV nie je tenký.")
exit 1
fi
if [ "$DIFF_TARGET_POOL" == "" ]
then
(>&2 echo "Cieľový LV nie je tenký.")
exit 1
fi
if [ "$DIFF_SOURCE_POOL" != "$DIFF_TARGET_POOL" ]
then
(>&2 echo "Zdrojové a cieľové LV patrí k rôznym tenkým poolom.")
exit 1
fi
DIFF_POOL_PATH=$(read_lv_dm_path $DIFF_VG $DIFF_SOURCE_POOL)
DIFF_SOURCE_ID=$(read_thin_id $DIFF_VG $DIFF_SOURCE)
DIFF_TARGET_ID=$(read_thin_id $DIFF_VG $DIFF_TARGET)
DIFF_POOL_PATH_TPOOL="$DIFF_POOL_PATH-tpool"
DIFF_POOL_PATH_TMETA="$DIFF_POOL_PATH"_tmeta
DIFF_POOL_METADATA_SNAP=$(read_thin_metadata_snap $DIFF_POOL_PATH_TPOOL)
if [ "$DIFF_POOL_METADATA_SNAP" != "-" ]
then
(>&2 echo "Snapshots metadát tenkého poolu už existujú. Predpokladá sa zastaraný. Uvoľníme snapshot metadát o 5 sekúnd.")
sleep 5
dmsetup message $DIFF_POOL_PATH_TPOOL 0 release_metadata_snap
fi
dmsetup message $DIFF_POOL_PATH_TPOOL 0 reserve_metadata_snap
DIFF_POOL_METADATA_SNAP=$(read_thin_metadata_snap $DIFF_POOL_PATH_TPOOL)
if [ "$DIFF_POOL_METADATA_SNAP" == "-" ]
then
(>&2 echo "Zlyhalo vytvorenie snapshotu metadát tenkého poolu.")
exit 1
fi
#We keep output in variable because metadata snapshot need to be released early.
DIFF_DATA=$(thin_delta -m$DIFF_POOL_METADATA_SNAP --snap1 $DIFF_SOURCE_ID --snap2 $DIFF_TARGET_ID $DIFF_POOL_PATH_TMETA)
dmsetup message $DIFF_POOL_PATH_TPOOL 0 release_metadata_snap
echo $"$DIFF_DATA" | grep -E 'different|left_only|right_only' | sed 's\/<\/"/g' | sed 's\/ "/"/g' | awk -F'"' '{print $6 "t" $8 "t" $11}' | sed 's\/different\/copy\/g' | sed 's\/left_only\/copy\/g' | sed 's\/right_only\/discard\/g'
}
function thinsync()
{
SYNC_VG="$1"
SYNC_PEND="$2"
SYNC_BASE="$3"
SYNC_TARGET="$4"
SYNC_PEND_POOL=$(read_pool_lv $SYNC_VG $SYNC_PEND)
SYNC_BLOCK_SIZE=$(read_lv_chunk_size $SYNC_VG $SYNC_PEND_POOL)
SYNC_PEND_PATH=$(read_lv_dm_path $SYNC_VG $SYNC_PEND)
activate_volume $SYNC_VG $SYNC_PEND
while read -r SYNC_ACTION SYNC_OFFSET SYNC_LENGTH ; do
SYNC_OFFSET_BYTES=$((SYNC_OFFSET * SYNC_BLOCK_SIZE))
SYNC_LENGTH_BYTES=$((SYNC_LENGTH * SYNC_BLOCK_SIZE))
if [ "$SYNC_ACTION" == "copy" ]
then
ddrescue --quiet --force --input-position=$SYNC_OFFSET_BYTES --output-position=$SYNC_OFFSET_BYTES --size=$SYNC_LENGTH_BYTES "$SYNC_PEND_PATH" "$SYNC_TARGET"
fi
if [ "$SYNC_ACTION" == "discard" ]
then
blkdiscard -o $SYNC_OFFSET_BYTES -l $SYNC_LENGTH_BYTES "$SYNC_TARGET"
fi
done < <(thindiff "$SYNC_VG" "$SYNC_PEND" "$SYNC_BASE")
}
function discard_volume()
{
DISCARD_VG="$1"
DISCARD_LV="$2"
DISCARD_LV_PATH=$(read_lv_dm_path "$DISCARD_VG" "$DISCARD_LV")
if [ "$DISCARD_LV_PATH" != "" ]
then
echo "$DISCARD_LV_PATH nájdené"
else
echo "$DISCARD_LV nenájdené v $DISCARD_VG"
exit 1
fi
DISCARD_LV_POOL=$(read_pool_lv $DISCARD_VG $DISCARD_LV)
DISCARD_LV_SIZE=$(read_lv_size "$DISCARD_VG" "$DISCARD_LV")
lvremove -y --quiet "$DISCARD_LV_PATH" || exit 1
lvcreate --thin-pool "$DISCARD_LV_POOL" -V "$DISCARD_LV_SIZE"B --name "$DISCARD_LV" "$DISCARD_VG" || exit 1
}
function backup()
{
SOURCE_VG="$1"
SOURCE_LV="$2"
TARGET_VG="$BACKUPS"
TARGET_LV="$SOURCE_VG-$SOURCE_LV"
SOURCE_BASE_LV="$SOURCE_LV$BASE_SUFFIX"
TARGET_BASE_LV="$TARGET_LV$BASE_SUFFIX"
SOURCE_PEND_LV="$SOURCE_LV$PEND_SUFFIX"
TARGET_PEND_LV="$TARGET_LV$PEND_SUFFIX"
SOURCE_BASE_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_BASE_LV")
SOURCE_PEND_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_PEND_LV")
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
TARGET_PEND_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_PEND_LV")
if [ "$SOURCE_BASE_LV_PATH" != "" ]
then
echo "$SOURCE_BASE_LV_PATH found"
else
echo "Base zdroj nebol nájdený, vytváram snímku $SOURCE_VG/$SOURCE_LV do $SOURCE_VG/$SOURCE_BASE_LV"
lvcreate --quiet --snapshot --name "$SOURCE_BASE_LV" "$SOURCE_VG/$SOURCE_LV" || exit 1
SOURCE_BASE_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_BASE_LV")
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
echo "Zahadzujem $SOURCE_BASE_LV_PATH, pretože musíme bootstrapiť."
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SOURCE_BASE_CHUNK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)
discard_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
sync
if [ "$TARGET_BASE_LV_PATH" != "" ]
then
echo "$TARGET_BASE_LV_PATH nájdený, nie je v súlade so zdrojom… odstraňujem…"
lvremove -y --quiet $TARGET_BASE_LV_PATH || exit 1
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
sync
fi
fi
SOURCE_BASE_SIZE=$(read_lv_size "$SOURCE_VG" "$SOURCE_BASE_LV")
if [ "$TARGET_BASE_LV_PATH" != "" ]
then
echo "$TARGET_BASE_LV_PATH found"
else
echo "$TARGET_VG/$TARGET_LV nebol nájdený. Vytváram prázdny objem."
lvcreate --thin-pool "$BACKUPS_POOL" -V "$SOURCE_BASE_SIZE"B --name "$TARGET_BASE_LV" "$TARGET_VG" || exit 1
echo "Musím znovu bootstrapiť. Zahadzujem zdroj na $SOURCE_BASE_LV_PATH"
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SOURCE_BASE_CHUNK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)
discard_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
TARGET_BASE_POOL=$(read_pool_lv $TARGET_VG $TARGET_BASE_LV)
TARGET_BASE_CHUNK_SIZE=$(read_lv_chunk_size $TARGET_VG $TARGET_BASE_POOL)
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
echo "Zahadzujem cieľ na $TARGET_BASE_LV_PATH"
discard_volume "$TARGET_VG" "$TARGET_BASE_LV"
sync
fi
if [ "$SOURCE_PEND_LV_PATH" != "" ]
then
echo "$SOURCE_PEND_LV_PATH found removing..."
lvremove -y --quiet "$SOURCE_PEND_LV_PATH" || exit 1
sync
fi
lvcreate --quiet --snapshot --name "$SOURCE_PEND_LV" "$SOURCE_VG/$SOURCE_LV" || exit 1
SOURCE_PEND_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_PEND_LV")
sync
if [ "$TARGET_PEND_LV_PATH" != "" ]
then
echo "$TARGET_PEND_LV_PATH found removing..."
lvremove -y --quiet $TARGET_PEND_LV_PATH
sync
fi
lvcreate --quiet --snapshot --name "$TARGET_PEND_LV" "$TARGET_VG/$TARGET_BASE_LV" || exit 1
TARGET_PEND_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_PEND_LV")
SOURCE_PEND_LV_SIZE=$(read_lv_size "$SOURCE_VG" "$SOURCE_PEND_LV")
lvresize -L "$SOURCE_PEND_LV_SIZE"B "$TARGET_PEND_LV_PATH"
activate_volume "$TARGET_VG" "$TARGET_PEND_LV"
echo "Synchronizujem $SOURCE_PEND_LV_PATH na $TARGET_PEND_LV_PATH"
thinsync "$SOURCE_VG" "$SOURCE_PEND_LV" "$SOURCE_BASE_LV" "$TARGET_PEND_LV_PATH" || exit 1
sync
TARGET_DATE_SUFFIX=$(suffix)
lvcreate --quiet --snapshot --name "$TARGET_LV$TARGET_DATE_SUFFIX" "$TARGET_VG/$TARGET_PEND_LV" || exit 1
sync
lvremove --quiet -y "$SOURCE_BASE_LV_PATH" || exit 1
sync
lvremove --quiet -y "$TARGET_BASE_LV_PATH" || exit 1
sync
lvrename -y "$SOURCE_VG/$SOURCE_PEND_LV" "$SOURCE_BASE_LV" || exit 1
lvrename -y "$TARGET_VG/$TARGET_PEND_LV" "$TARGET_BASE_LV" || exit 1
sync
deactivate_volume "$TARGET_VG" "$TARGET_BASE_LV"
deactivate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
}
function verify()
{
SOURCE_VG="$1"
SOURCE_LV="$2"
TARGET_VG="$BACKUPS"
TARGET_LV="$SOURCE_VG-$SOURCE_LV"
SOURCE_BASE_LV="$SOURCE_LV$BASE_SUFFIX"
TARGET_BASE_LV="$TARGET_LV$BASE_SUFFIX"
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
SOURCE_BASE_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_BASE_LV")
if [ "$SOURCE_BASE_LV_PATH" != "" ]
then
echo "$SOURCE_BASE_LV_PATH found"
else
echo "$SOURCE_BASE_LV_PATH not found"
exit 1
fi
if [ "$TARGET_BASE_LV_PATH" != "" ]
then
echo "$TARGET_BASE_LV_PATH found"
else
echo "$TARGET_BASE_LV_PATH not found"
exit 1
fi
activate_volume "$TARGET_VG" "$TARGET_BASE_LV"
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
echo Porovnávam "$SOURCE_BASE_LV_PATH" s "$TARGET_BASE_LV_PATH"
cmp "$SOURCE_BASE_LV_PATH" "$TARGET_BASE_LV_PATH"
echo Hotovo...
deactivate_volume "$TARGET_VG" "$TARGET_BASE_LV"
deactivate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
}
function resync()
{
SOURCE_VG="$1"
SOURCE_LV="$2"
TARGET_VG="$BACKUPS"
TARGET_LV="$SOURCE_VG-$SOURCE_LV"
SOURCE_BASE_LV="$SOURCE_LV$BASE_SUFFIX"
TARGET_BASE_LV="$TARGET_LV$BASE_SUFFIX"
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
SOURCE_BASE_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_BASE_LV")
if [ "$SOURCE_BASE_LV_PATH" != "" ]
then
echo "$SOURCE_BASE_LV_PATH found"
else
echo "$SOURCE_BASE_LV_PATH not found"
exit 1
fi
if [ "$TARGET_BASE_LV_PATH" != "" ]
then
echo "$TARGET_BASE_LV_PATH found"
else
echo "$TARGET_BASE_LV_PATH not found"
exit 1
fi
activate_volume "$TARGET_VG" "$TARGET_BASE_LV"
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SYNC_BLOCK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)
echo Synchronizujem "$SOURCE_BASE_LV_PATH" na "$TARGET_BASE_LV_PATH"
CMP_OFFSET=0
while [[ "$CMP_OFFSET" != "" ]] ; do
CMP_MISMATCH=$(cmp -i "$CMP_OFFSET" "$SOURCE_BASE_LV_PATH" "$TARGET_BASE_LV_PATH" | grep differ | awk '{print $5}' | sed 's\/,//g')
if [[ "$CMP_MISMATCH" != "" ]] ; then
CMP_OFFSET=$(( CMP_MISMATCH + CMP_OFFSET ))
SYNC_OFFSET_BYTES=$(( ( CMP_OFFSET / SYNC_BLOCK_SIZE ) * SYNC_BLOCK_SIZE ))
SYNC_LENGTH_BYTES=$(( SYNC_BLOCK_SIZE ))
echo "Synchronizujem $SYNC_LENGTH_BYTES bajtov na $SYNC_OFFSET_BYTES z $SOURCE_BASE_LV_PATH do $TARGET_BASE_LV_PATH"
ddrescue --quiet --force --input-position=$SYNC_OFFSET_BYTES --output-position=$SYNC_OFFSET_BYTES --size=$SYNC_LENGTH_BYTES "$SOURCE_BASE_LV_PATH" "$TARGET_BASE_LV_PATH"
else
CMP_OFFSET=""
fi
done
echo Hotovo...
deactivate_volume "$TARGET_VG" "$TARGET_BASE_LV"
deactivate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
}
function list()
{
LIST_SOURCE_VG="$1"
LIST_SOURCE_LV="$2"
LIST_TARGET_VG="$BACKUPS"
LIST_TARGET_LV="$LIST_SOURCE_VG-$LIST_SOURCE_LV"
LIST_TARGET_BASE_LV="$LIST_TARGET_LV$SNAP_SUFFIX"
lvs -olv_name | grep "$LIST_TARGET_BASE_LV.$DATE_REGEX"
}
function remove()
{
REMOVE_TARGET_VG="$BACKUPS"
REMOVE_TARGET_LV="$1"
lvremove -y "$REMOVE_TARGET_VG/$REMOVE_TARGET_LV"
sync
}
function removeall()
{
DATE_OFFSET="$3"
FILTER="$(filter "$DATE_OFFSET")"
while read -r SNAPSHOT ; do
remove "$SNAPSHOT"
done < <(list "$1" "$2" | grep "$FILTER")
}
(
COMMAND="$1"
shift
case "$COMMAND" in
"--help")
echo "Pomoc"
;;
"suffix")
suffix
;;
"filter")
filter "$1"
;;
"backup")
wait_lock_or_terminate
backup "$1" "$2"
;;
"list")
list "$1" "$2"
;;
"thindiff")
thindiff "$1" "$2" "$3"
;;
"thinsync")
thinsync "$1" "$2" "$3" "$4"
;;
"verify")
wait_lock_or_terminate
verify "$1" "$2"
;;
"resync")
wait_lock_or_terminate
resync "$1" "$2"
;;
"remove")
wait_lock_or_terminate
remove "$1"
;;
"removeall")
wait_lock_or_terminate
removeall "$1" "$2" "$3"
;;
*)
echo "Žiadne.."
;;
esac
) 98>$LOCK_FILE
EOF
Čo to robí…?Obsahuje súbor príkazov na manipuláciu s tenkými snímkami a synchronizáciu rozdielov medzi dvoma tenkými snímkami, získanými pomocou thin_delta, na iné blokové zariadenie s použitím ddrescue a blkdiscard.
Ďalší skript, ktorý pridáme do crontabu:
Ešte trochu bash#cat >/root/lvm-thin-backup/cron-daily.sh << EOF
#!/bin/bash
CESTA="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"
BACKUP_SCRIPT="$SCRIPT_DIR/lvm-thin-backup.sh"
RETENTION="-60 days"
$BACKUP_SCRIPT backup images linux-dev
$BACKUP_SCRIPT backup images win8
$BACKUP_SCRIPT backup images win8-data
#etc
$BACKUP_SCRIPT removeall images linux-dev "$RETENTION"
$BACKUP_SCRIPT removeall images win8 "$RETENTION"
$BACKUP_SCRIPT removeall images win8-data "$RETENTION"
#etc
EOF
Čo to robí…?Používa predchádzajúci skript na vytváranie a synchronizáciu záloh uvedených tenkých objemov. Skript nechá neaktívne snímky uvedených objemov, ktoré sú potrebné na sledovanie zmien od poslednej synchronizácie.
Tento skript je potrebné upraviť, aby sa uviedol zoznam tenkých objemov, pre ktoré je potrebné vytvoriť zálohy. Uvedené názvy sú uvedené iba ako príklad. Ak chcete, môžete napísať skript, ktorý synchronizuje všetky objemy.
Povieme práva:
#chmod +x /root/lvm-thin-backup/cron-daily.sh
#chmod +x /root/lvm-thin-backup/lvm-thin-backup.sh
Skontrolujeme a vložíme do cronu:
#/usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/lvm-thin-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t lvm-thin-backup
#cat /var/log/syslog | grep lvm-thin-backup
#crontab -e
0 3 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/lvm-thin-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t lvm-thin-backup
Prvý spustenie bude dlhé, pretože tenké objemy budú úplne synchronizované kopírovaním celého používaného priestoru. Vďaka metadátam LVM thin vieme, ktoré bloky sú skutočne používané, takže sa budú kopírovať iba skutočne používané bloky tenkých objemov.
Nasledujúce spustenia budú kopírovať dáta inkrementálne vďaka sledovaniu zmien prostredníctvom metadát LVM thin.
Pozrieme sa, čo sa podarilo:
#time /root/btrfs-backup/cron-daily.sh
reálny 0m2,967s
užívateľ 0m0,225s
systém 0m0,353s
#time /root/lvm-thin-backup/cron-daily.sh
real 1m2,710s
user 0m12,721s
sys 0m6,671s
#ls -al /backup/btrfs/back/remote/*
/backup/btrfs/back/remote/boot:
total 0
drwxr-xr-x 1 root root 1260 mar 26 09:11 .
drwxr-xr-x 1 root root 16 mar 6 09:30 ..
drwxr-xr-x 1 root root 322 mar 26 02:00 .@base
drwxr-xr-x 1 root root 516 mar 6 09:39 .@snap.2020-03-06-09-39-37
drwxr-xr-x 1 root root 516 mar 6 09:39 .@snap.2020-03-06-09-39-57
...
/backup/btrfs/back/remote/root:
total 0
drwxr-xr-x 1 root root 2820 mar 26 09:11 .
drwxr-xr-x 1 root root 16 mar 6 09:30 ..
drwxr-xr-x 1 root root 240 mar 26 09:11 @.@base
drwxr-xr-x 1 root root 22 mar 26 09:11 @home.@base
drwxr-xr-x 1 root root 22 mar 6 09:39 @home.@snap.2020-03-06-09-39-35
drwxr-xr-x 1 root root 22 mar 6 09:39 @home.@snap.2020-03-06-09-39-57
...
drwxr-xr-x 1 root root 240 mar 6 09:39 @.@snap.2020-03-06-09-39-26
drwxr-xr-x 1 root root 240 mar 6 09:39 @.@snap.2020-03-06-09-39-56
...
#lvs -olv_name,lv_size images && lvs -olv_name,lv_size backup
LV LSize
linux-dev 128,00g
linux-dev.base 128,00g
thin-pool 1,38t
win8 128,00g
win8-data 2,00t
win8-data.base 2,00t
win8.base 128,00g
LV LSize
backup 256,00g
images-linux-dev.base 128,00g
images-linux-dev.snap.2020-03-08-10-09-11 128,00g
images-linux-dev.snap.2020-03-08-10-09-25 128,00g
...
images-win8-data.base 2,00t
images-win8-data.snap.2020-03-16-14-11-55 2,00t
images-win8-data.snap.2020-03-16-14-19-50 2,00t
...
images-win8.base 128,00g
images-win8.snap.2020-03-17-04-51-46 128,00g
images-win8.snap.2020-03-18-03-02-49 128,00g
...
thin-pool <2,09t
O čo tu ide s matrioškami?
Pravdepodobne je to preto, že logické zväzky LVM LV môžu byť fyzickými zväzkami LVM PV pre iné VG. LVM môže byť rekurzívny, ako matriošky. To dáva LVM mimoriadnu flexibilitu.
P.S.
V nasledujúcom článku sa pokúsime využiť niekoľko podobných mobilných úložísk/KVM ako základ na vytvorenie geo-distribuovaného storage/vm-klastra s replikáciou na viacerých kontinentoch prostredníctvom domácich desktopov, domácich internetov a P2P sietí.
Zdroj: habr.com
