Kaj imata skupnega LVM in Matryoshka?

Dober dan.
S skupnostjo bi rad delil svojo praktično izkušnjo gradnje sistema za shranjevanje podatkov za KVM z uporabo md RAID + LVM.

Program bo vključeval:

  • Gradnja md RAID 1 iz NVMe SSD.
  • Sestavljanje md RAID 6 iz SATA SSD in običajnih diskov.
  • Značilnosti delovanja TRIM/DISCARD na SSD RAID 1/6.
  • Ustvarjanje zagonskega polja md RAID 1/6 na skupnem nizu diskov.
  • Namestitev sistema na NVMe RAID 1, ko v BIOS-u ni podpore za NVMe.
  • Uporaba LVM cache in LVM thin.
  • Uporaba posnetkov BTRFS in pošiljanje/prejemanje za varnostno kopiranje.
  • Uporaba tankih posnetkov LVM in thin_delta za varnostne kopije v slogu BTRFS.

Če vas zanima, si oglejte kat.

Заявление

Avtor ne prevzema nobene odgovornosti za posledice uporabe ali neuporabe materialov/primerov/kode/nasvetov/podatkov iz tega članka. Z branjem ali kakršno koli uporabo tega gradiva prevzemate odgovornost za vse posledice teh dejanj. Možne posledice vključujejo:

  • Hrustljavo ocvrti NVMe SSD.
  • Popolnoma izrabljen zapisni vir in okvara SSD diskov.
  • Popolna izguba vseh podatkov na vseh diskih, vključno z varnostnimi kopijami.
  • Pokvarjena strojna oprema računalnika.
  • Zapravljen čas, živci in denar.
  • Vse druge posledice, ki niso navedene zgoraj.

Železo

Na voljo so bili:

Matična plošča iz približno leta 2013 z naborom čipov Z87, skupaj z Intel Core i7 / Haswell.

  • Procesor 4 jedra, 8 niti
  • 32 GB DDR3 RAM
  • 1 x 16 ali 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 priključki

Adapter SAS LSI SAS9211-8I je prešel v način IT / HBA. Vdelana programska oprema, ki podpira RAID, je bila namerno nadomeščena z vdelano programsko opremo HBA za:

  1. Ta adapter lahko kadar koli vržete ven in ga zamenjate s katerim koli drugim.
  2. TRIM/Discard je na diskih deloval normalno, ker... v vdelani programski opremi RAID ti ukazi sploh niso podprti in HBA na splošno ne skrbi, kateri ukazi se prenašajo po vodilu.

Trdi diski - 8 kosov HGST Travelstar 7K1000 s kapaciteto 1 TB v faktorju oblike 2.5, kot za prenosnike. Ti pogoni so bili prej v polju RAID 6. Uporabni bodo tudi v novem sistemu. Za shranjevanje lokalnih varnostnih kopij.

Dodatno dodano:

6 kosov SATA SSD model Samsung 860 QVO 2TB. Ti SSD diski so zahtevali veliko prostornino, želena je bila prisotnost predpomnilnika SLC, zanesljivost in nizka cena. Zahtevana je bila podpora za zavrženje/ničlo, kar je preverjeno z vrstico v dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 kosa NVMe SSD model Samsung SSD 970 EVO 500GB.

Za te SSD-je sta pomembni naključna hitrost branja/pisanja in zmogljivost virov za vaše potrebe. Radiator za njih. Nujno. Vsekakor. Sicer jih ob prvi sinhronizaciji RAID hrustljavo ocvremo.

StarTech PEX8M2E2 adapter za 2 x NVMe SSD, nameščen v režo PCIe 3.0 8x. To je spet samo HBA, vendar za NVMe. Od poceni adapterjev se razlikuje po tem, da ne potrebuje podpore za bifurkacijo PCIe na matični plošči zaradi prisotnosti vgrajenega stikala PCIe. Deloval bo tudi v najstarejšem sistemu s PCIe, tudi če je x1 reža PCIe 1.0. Seveda s primerno hitrostjo. Tam ni RAID-ov. Na plošči ni vgrajenega BIOS-a. Torej se vaš sistem zaradi te naprave ne bo čudežno naučil zagnati z NVMe, še manj pa z NVMe RAID.

Ta komponenta je nastala izključno zaradi prisotnosti samo enega brezplačnega 8x PCIe 3.0 v sistemu, in če sta 2 prosti reži, jo je mogoče enostavno zamenjati z dvema penijema PEX4M2E1 ali analogi, ki jih je mogoče kupiti kjer koli po ceni 600 rubljev.

Zavrnitev vseh vrst strojne opreme ali vgrajenih chipset/BIOS RAID-ov je bila narejena namerno, da bi lahko v celoti nadomestili celoten sistem, z izjemo samega SSD/HDD, pri tem pa ohranili vse podatke. Idealno, da lahko ob prehodu na popolnoma novo/drugačno strojno opremo shranite celo nameščen operacijski sistem. Glavna stvar je, da obstajajo vrata SATA in PCIe. Je kot živi CD ali zagonski bliskovni pogon, le da je zelo hiter in malo zajeten.

HumorV nasprotnem primeru veste, kaj se zgodi - včasih morate nujno vzeti celotno paleto s seboj. Vendar ne želim izgubiti podatkov. Za to so vsi omenjeni mediji priročno nameščeni na diapozitivih v 5.25 ležiščih standardnega ohišja.

No, in seveda za eksperimentiranje z različnimi metodami predpomnjenja SSD v Linuxu.

Racije strojne opreme so dolgočasne. Ga vklopite. Ali deluje ali pa ne. In pri mdadm vedno obstajajo možnosti.

Programska oprema

Prej je bil na strojni opremi nameščen Debian 8 Jessie, ki je blizu EOL. RAID 6 je bil sestavljen iz zgoraj omenjenih trdih diskov v paru z LVM. Poganjal je virtualne stroje v kvm/libvirt.

Ker Avtor ima primerne izkušnje pri ustvarjanju prenosnih zagonskih bliskovnih pogonov SATA/NVMe, poleg tega pa je bil kot ciljni sistem izbran Ubuntu 18.04, da ne bi pokvaril običajne predloge apt, ki je že dovolj stabiliziran, vendar ima še 3 leta podporo v prihodnosti.

Omenjeni sistem vsebuje vse gonilnike strojne opreme, ki jih potrebujemo takoj po izdelavi. Ne potrebujemo programske opreme ali gonilnikov tretjih oseb.

Priprave na namestitev

Za namestitev sistema potrebujemo Ubuntu Desktop Image. Strežniški sistem ima nekakšen živahen inštalater, ki kaže pretirano samostojnost, ki je ni mogoče onemogočiti tako, da sistemsko particijo UEFI potisnete na enega od diskov in pokvari vso lepoto. V skladu s tem je nameščen samo v načinu UEFI. Ne ponuja nobenih možnosti.

S tem nismo zadovoljni.

Zakaj?Na žalost je zagon UEFI izjemno slabo združljiv z RAID zagonske programske opreme, ker... Nihče nam ne ponuja rezervacij za particijo UEFI ESP. Na spletu obstajajo recepti, ki predlagajo namestitev particije ESP na bliskovni pogon v vrata USB, vendar je to točka napake. Obstajajo recepti, ki uporabljajo programsko opremo mdadm RAID 1 z metapodatki različice 0.9, ki UEFI BIOS-u ne preprečijo, da bi videl to particijo, vendar to živi do srečnega trenutka, ko BIOS ali drug OS strojne opreme zapiše nekaj v ESP in pozabi to sinhronizirati z drugimi ogledala.

Poleg tega je zagon UEFI odvisen od NVRAM-a, ki se ne bo premaknil skupaj z diski v nov sistem, ker je del matične plošče.

Torej, ne bomo izumljali novega kolesa. Imamo že pripravljeno, časovno preizkušeno dedkovo kolo, zdaj imenovano Legacy/BIOS boot, ki nosi ponosno ime CSM na sistemih, združljivih z UEFI. Samo vzeli ga bomo s police, podmazali, napumpali gume in obrisali z vlažno krpo.

Namizne različice Ubuntu tudi ni mogoče pravilno namestiti s podedovanim zagonskim nalagalnikom, vendar tukaj, kot pravijo, vsaj obstajajo možnosti.

In tako zberemo strojno opremo in naložimo sistem iz zagonskega bliskovnega pogona Ubuntu Live. Pakete bomo morali prenesti, zato bomo vzpostavili omrežje, ki bo delovalo za vas. Če ne deluje, lahko vnaprej naložite potrebne pakete na bliskovni pogon.

Gremo v namizno okolje, zaženemo terminalski emulator in gremo:

#sudo bash

Kako…?Zgornja vrstica je kanonični sprožilec za holiwars o sudo. C bоpridejo večje priložnosti inоvečja odgovornost. Vprašanje je, ali ga lahko sprejmeš sam. Mnogi ljudje mislijo, da uporaba sudo na ta način vsaj ni previdna. Vendar:

#apt-get install mdadm lvm2 thin-provisioning-tools btrfs-tools util-linux lsscsi nvme-cli mc

Zakaj ne ZFS...?Ko namestimo programsko opremo v svoj računalnik, svojo strojno opremo v bistvu posodimo razvijalcem te programske opreme, da jo poganjajo.
Ko tej programski opremi zaupamo varnost naših podatkov, najamemo posojilo v višini stroškov obnove teh podatkov, ki ga bomo nekoč morali odplačati.

S tega vidika je ZFS Ferrari, mdadm+lvm pa bolj kot kolo.

Subjektivno gledano avtor raje kot ferrarija neznanim osebam posodi kolo na kredit. Tam cena vprašanja ni visoka. Ni potrebe po pravicah. Enostavneje kot prometna pravila. Parkiranje je brezplačno. Tek na smučeh je boljši. Na kolo lahko vedno pritrdite noge in kolo lahko popravite z lastnimi rokami.

Zakaj potem BTRFS...?Za zagon operacijskega sistema potrebujemo datotečni sistem, ki je podprt v Legacy/BIOS GRUB iz škatle in hkrati podpira posnetke v živo. Uporabili ga bomo za particijo /boot. Poleg tega avtor raje uporablja ta FS za / (root), ne da bi pozabil omeniti, da lahko za katero koli drugo programsko opremo ustvarite ločene particije na LVM in jih namestite v potrebne imenike.

Na ta FS ne bomo shranjevali nobenih slik virtualnih strojev ali baz podatkov.
Ta FS bo uporabljen samo za ustvarjanje posnetkov sistema brez njegovega izklopa in nato prenos teh posnetkov na disk z varnostno kopijo s pošiljanjem/prejemanjem.

Poleg tega avtor na splošno raje obdrži najmanj programske opreme neposredno na strojni opremi in poganja vso drugo programsko opremo v virtualnih strojih z uporabo stvari, kot je posredovanje grafičnih procesorjev in gostiteljskih krmilnikov PCI-USB v KVM prek IOMMU.

Edino, kar ostane na strojni opremi, so shranjevanje podatkov, virtualizacija in varnostno kopiranje.

Če bolj zaupate ZFS, potem so načeloma za določeno aplikacijo zamenljivi.

Vendar pa avtor namenoma ignorira vgrajeno zrcaljenje/RAID in funkcije redundance, ki jih imajo ZFS, BRTFS in LVM.

Kot dodaten argument ima BTRFS možnost spreminjanja naključnih zapisov v zaporedne, kar izjemno pozitivno vpliva na hitrost sinhronizacije posnetkov/varnostnih kopij na HDD.

Ponovno pregledajmo vse naprave:

#udevadm control --reload-rules && udevadm trigger

Poglejmo naokoli:

#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

Postavitev diska

NVMe SSD

Vendar jih nikakor ne bomo označili. Kljub temu naš BIOS teh pogonov ne vidi. Torej bodo v celoti prešli na programski RAID. Tam niti razdelkov ne bomo ustvarili. Če želite slediti "canonu" ali "načeloma", ustvarite eno veliko particijo, kot je HDD.

SATA HDD

Tukaj ni treba izumiti ničesar posebnega. Ustvarili bomo en razdelek za vse. Ustvarili bomo particijo, ker BIOS vidi te diske in se lahko celo poskusi zagnati z njih. Kasneje bomo na te diske celo namestili GRUB, da bo lahko sistem kar naenkrat to naredil.

#cat >hdd.part << EOF
label: dos
label-id: 0x00000000
device: /dev/sdg
unit: sectors

/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

Tukaj postanejo stvari zanimive za nas.

Prvič, naši diski so veliki 2 TB. To je znotraj sprejemljivega obsega za MBR, ki ga bomo uporabili. Po potrebi se lahko zamenja z GPT. Diski GPT imajo združljivostno plast, ki omogoča sistemom, združljivim z MBR, da vidijo prve 4 particije, če se nahajajo znotraj prvih 2 terabajtov. Glavna stvar je, da sta zagonska particija in particija bios_grub na teh diskih na začetku. To vam omogoča celo zagon s pogonov GPT Legacy/BIOS.

Ampak to ni naš primer.

Tukaj bomo ustvarili dva razdelka. Prvi bo velik 1 GB in bo uporabljen za RAID 1/boot.

Drugi bo uporabljen za RAID 6 in bo zavzel ves preostali prosti prostor, razen majhnega nedodeljenega območja na koncu pogona.

Kaj je to neoznačeno območje?Glede na vire v omrežju imajo naši SSD diski SATA vgrajen dinamično razširljiv predpomnilnik SLC velikosti od 6 do 78 gigabajtov. Dobimo 6 gigabajtov »zastonj« zaradi razlike med »gigabajti« in »gibibajti« v podatkovnem listu pogona. Preostalih 72 gigabajtov je dodeljenih iz neuporabljenega prostora.

Tukaj je treba opozoriti, da imamo predpomnilnik SLC, prostor pa je zaseden v 4-bitnem načinu MLC. Kar za nas dejansko pomeni, da bomo za vsake 4 gigabajte prostega prostora dobili le 1 gigabajt predpomnilnika SLC.

Pomnožite 72 gigabajtov s 4 in dobite 288 gigabajtov. To je prosti prostor, ki ga ne bomo označili, da bi pogonom omogočili polno uporabo predpomnilnika SLC.

Tako bomo dejansko dobili do 312 gigabajtov predpomnilnika SLC iz skupno šestih pogonov. Od vseh pogonov bosta 2 uporabljena v RAID za redundanco.

Ta količina predpomnilnika nam bo omogočila, da se v resničnem življenju zelo redko srečamo s situacijo, ko pisanje ne gre v predpomnilnik. To izjemno dobro kompenzira najbolj žalostno pomanjkljivost pomnilnika QLC - izjemno nizko hitrost zapisovanja, ko se podatki zapisujejo mimo predpomnilnika. Če vaše obremenitve temu ne ustrezajo, vam priporočam, da dobro premislite, kako dolgo bo vaš SSD zdržal pod takšno obremenitvijo, upoštevajoč TBW iz podatkovne liste.

#cat >ssd.part << EOF
label: dos
label-id: 0x00000000
device: /dev/sda
unit: sectors

/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

Ustvarjanje nizov

Najprej moramo stroj preimenovati. To je potrebno, ker je ime gostitelja del imena polja nekje znotraj mdadm in nekje na nekaj vpliva. Seveda lahko nize kasneje preimenujemo, vendar je to nepotreben korak.

#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

Zakaj - domnevam - čist ...?Da bi se izognili inicializaciji nizov. To velja za obe ravni RAID 1 in 6. Vse lahko deluje brez inicializacije, če gre za novo polje. Poleg tega je inicializacija matrike SSD ob ustvarjanju izguba sredstev TBW. Kjer je mogoče, uporabljamo TRIM/DISCARD na sestavljenih poljih SSD, da jih "inicializiramo".

Za polja SSD je RAID 1 DISCARD podprt takoj.

Za polja SSD RAID 6 DISCARD ga morate omogočiti v parametrih modula jedra.

To je treba narediti le, če imajo vsi SSD-ji, ki se uporabljajo v nizih ravni 4/5/6 v tem sistemu, delujočo podporo za discard_zeroes_data. Včasih naletite na čudne pogone, ki sporočajo jedru, da je ta funkcija podprta, v resnici pa je ni ali pa funkcija ne deluje vedno. Trenutno je podpora na voljo skoraj povsod, vendar obstajajo stari pogoni in vdelana programska oprema z napakami. Zaradi tega je podpora za DISCARD privzeto onemogočena za RAID 6.

Pozor, naslednji ukaz bo uničil vse podatke na pogonih NVMe z "inicializacijo" polja z "ničlami".

#blkdiscard /dev/md0

Če gre kaj narobe, poskusite določiti korak.

#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

Zakaj tako velik...?Povečanje velikosti kosa pozitivno vpliva na hitrost naključnega branja v blokih do vključno velikosti kosa. To se zgodi, ker je mogoče eno operacijo ustrezne velikosti ali manjšo v celoti izvesti na eni sami napravi. Zato se IOPS iz vseh naprav seštejejo. Po statističnih podatkih 99% IO ne presega 512K.

RAID 6 IOPS na pisanje vedno manjše ali enako IOPS enega pogona. Ko je lahko kot naključno branje IOPS nekajkrat večji od enega pogona, pri čemer je velikost bloka ključnega pomena.
Avtor ne vidi smisla v poskusu optimizacije parametra, ki je slab v pri-zasnovi RAID 6, in namesto tega optimizira tisto, v čemer je RAID 6 dober.
Slabo naključno pisanje RAID 6 bomo nadomestili s predpomnilnikom NVMe in triki za tanko zagotavljanje.

Nismo še omogočili DISCARD za RAID 6. Zato za zdaj ne bomo "inicializirali" tega polja. To bomo storili kasneje, po namestitvi operacijskega sistema.

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

Zaradi hitrosti želimo postaviti korenski datotečni sistem na NVMe RAID 1, ki je /dev/md0.
Vendar bomo to hitro matriko še vedno potrebovali za druge potrebe, kot so izmenjava, metapodatki in LVM-cache ter LVM-thin metapodatki, zato bomo na tej matriki ustvarili LVM VG.

#pvcreate /dev/md0
#vgcreate root /dev/md0

Ustvarimo particijo za korenski datotečni sistem.

#lvcreate -L 128G --name root root

Ustvarimo particijo za zamenjavo glede na velikost RAM-a.

#lvcreate -L 32G --name swap root

namestitev OS

V celoti imamo vse potrebno za namestitev sistema.

Zaženite čarovnika za namestitev sistema iz okolja Ubuntu Live. Normalna namestitev. Samo v fazi izbire diskov za namestitev morate določiti naslednje:

  • /dev/md1, - točka priklopa /boot, FS - BTRFS
  • /dev/root/root (aka /dev/mapper/root-root), - točka priklopa / (root), FS - BTRFS
  • /dev/root/swap (aka /dev/mapper/root-swap), - uporabite kot izmenjalno particijo
  • Namestite zagonski nalagalnik na /dev/sda

Ko izberete BTRFS kot korenski datotečni sistem, bo namestitveni program samodejno ustvaril dva nosilca BTRFS z imenom "@" za / (root) in "@home" za /home.

Začnimo z namestitvijo ...

Namestitev se bo končala z modalnim pogovornim oknom, ki označuje napako pri namestitvi zagonskega nalagalnika. Na žalost ne boste mogli zapustiti tega pogovornega okna s standardnimi sredstvi in ​​nadaljevati namestitve. Odjavimo se iz sistema in se znova prijavimo ter končamo na čistem namizju Ubuntu Live. Odprite terminal in znova:

#sudo bash

Za nadaljevanje namestitve ustvarite chroot okolje:

#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

Konfigurirajmo omrežje in ime gostitelja 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

Pojdimo v okolje chroot:

#chroot /mnt/chroot

Najprej bomo dostavili pakete:

apt-get install --reinstall mdadm lvm2 thin-provisioning-tools btrfs-tools util-linux lsscsi nvme-cli mc debsums hdparm

Preverimo in popravimo vse pakete, ki so bili napačno nameščeni zaradi nepopolne namestitve sistema:

#CORRUPTED_PACKAGES=$(debsums -s 2>&1 | awk '{print $6}' | uniq)
#apt-get install --reinstall $CORRUPTED_PACKAGES

Če nekaj ne deluje, boste morda morali najprej urediti /etc/apt/sources.list

Prilagodimo parametre za modul RAID 6, da omogočimo TRIM/DISCARD:

#cat >/etc/modprobe.d/raid456.conf << EOF
options raid456 devices_handle_discard_safely=1
EOF

Malo prilagodimo naše nize:

#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

Kaj je bilo..?Ustvarili smo niz pravil udev, ki bodo naredili naslednje:

  • Nastavite velikost predpomnilnika blokov za RAID 2020, da bo ustrezna za leto 6. Zdi se, da se privzeta vrednost ni spremenila od nastanka Linuxa in že dolgo ni bila ustrezna.
  • Rezervirajte najmanj IO za čas preverjanj/sinhronizacij polja. S tem preprečite, da bi se vaši nizi pod obremenitvijo zataknili v stanju večne sinhronizacije.
  • Omejite največji IO med preverjanji/sinhronizacijo nizov. To je potrebno, da sinhronizacija/preverjanje SSD RAID-ov ne ocvre vaših diskov. To še posebej velja za NVMe. (Se spomnite radiatorja? Nisem se šalil.)
  • Prepovejte diskom zaustavitev vrtenja vretena (HDD) prek APM in nastavite časovno omejitev mirovanja za krmilnike diskov na 7 ur. APM lahko popolnoma onemogočite, če vaši pogoni to zmorejo (-B 255). S privzeto vrednostjo se pogoni ustavijo po petih sekundah. Nato OS želi ponastaviti predpomnilnik diska, diski se bodo znova zavrteli in vse se bo začelo znova. Diski imajo omejeno največje število vrtljajev vretena. Tako preprost privzeti cikel lahko zlahka uniči vaše diske v nekaj letih. Vsi diski tega ne trpijo, naši pa so »prenosni«, z ustreznimi privzetimi nastavitvami, zaradi katerih je RAID videti kot mini-MAID.
  • Namestite readahead na diske (rotacijske) 1 megabajt - dva zaporedna bloka/kos RAID 6
  • Onemogočite vnaprejšnje branje na samih nizih.

Uredimo /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

Zakaj je tako..?Particijo /boot bomo iskali po UUID. Poimenovanje nizov bi se lahko teoretično spremenilo.

Preostale razdelke bomo iskali po imenih LVM v zapisu /dev/mapper/vg-lv, ker dokaj edinstveno identificirajo particije.

Ne uporabljamo UUID za LVM, ker UUID nosilcev LVM in njihovih posnetkov je lahko enak.Namestite /dev/mapper/root-root.. dvakrat?ja Točno tako. Značilnost BTRFS. Ta datotečni sistem je mogoče večkrat namestiti z različnimi subvol.

Zaradi te iste funkcije priporočam, da nikoli ne ustvarite posnetkov LVM aktivnih nosilcev BTRFS. Ob ponovnem zagonu boste morda presenečeni.

Ponovno ustvarimo konfiguracijo mdadm:

#/usr/share/mdadm/mkconf | sed 's/#DEVICE/DEVICE/g' >/etc/mdadm/mdadm.conf

Prilagodimo nastavitve 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

Kaj je bilo..?Omogočili smo samodejno razširitev tankih bazenov LVM ob doseganju 90% zasedenega prostora za 5% volumna.

Povečali smo največje število blokov predpomnilnika za predpomnilnik LVM.

LVM smo preprečili iskanje nosilcev LVM (PV) na:

  • naprave, ki vsebujejo predpomnilnik LVM (cdata)
  • naprave, predpomnjene z uporabo predpomnilnika LVM, mimo predpomnilnika ( _corig). V tem primeru bo sama predpomnjena naprava še vedno skenirana skozi predpomnilnik (samo ).
  • naprave, ki vsebujejo metapodatke predpomnilnika LVM (cmeta)
  • vse naprave v VG z imenom slike. Tukaj bomo imeli slike diskov virtualnih strojev in ne želimo, da bi LVM na gostitelju aktiviral nosilce, ki pripadajo gostujočemu OS.
  • vse naprave v VG z imenom backup. Tukaj bomo imeli varnostne kopije slik virtualnih strojev.
  • vse naprave, katerih ime se konča z "gpv" (guest fizični nosilec)

Omogočili smo podporo DISCARD pri sproščanju prostega prostora na LVM VG. Bodi previden. Zaradi tega bo brisanje LV-jev na SSD-ju precej zamudno. To še posebej velja za SSD RAID 6. Vendar bomo po načrtu uporabljali tanko zagotavljanje, tako da nas to ne bo prav nič oviralo.

Posodobimo sliko initramfs:

#update-initramfs -u -k all

Namestite in konfigurirajte grub:

#apt-get install grub-pc
#apt-get purge os-prober
#dpkg-reconfigure grub-pc

Katere diske izbrati?Vsi, ki ste sd*. Sistem mora imeti možnost zagona s katerega koli delujočega pogona SATA ali SSD.

Zakaj so dodali os-prober..?Za pretirano samostojnost in igrive roke.

Ne deluje pravilno, če je eden od RAID-ov v slabšem stanju. Poskuša poiskati OS na particijah, ki se uporabljajo v virtualnih strojih, ki se izvajajo na tej strojni opremi.

Če ga potrebujete, ga lahko pustite, vendar ne pozabite na vse zgoraj navedeno. Priporočam, da recepte, kako se znebite porednih rok, poiščete na spletu.

S tem smo zaključili začetno namestitev. Čas je, da znova zaženete novo nameščen OS. Ne pozabite odstraniti zagonskega Live CD/USB.

#exit
#reboot

Za zagonsko napravo izberite katerega koli SSD diska SATA.

LVM na SATA SSD

Na tej točki smo že zagnali nov OS, konfigurirali omrežje, apt, odprli terminalski emulator in zagnali:

#sudo bash

Nadaljujmo.

"Inicializirajte" polje iz SSD SSD:

#blkdiscard /dev/md2

Če ne deluje, poskusite:

#blkdiscard --step 65536 /dev/md2
Ustvarite LVM VG na SSD SSD:

#pvcreate /dev/md2
#vgcreate data /dev/md2

Zakaj še en VG..?Pravzaprav že imamo VG z imenom root. Zakaj ne bi vsega dodali v eno VG?

Če je v VG več PV-jev, morajo biti vsi PV-ji prisotni (online), da se VG pravilno aktivira. Izjema je LVM RAID, ki ga namerno ne uporabljamo.

Resnično si želimo, da bi se operacijski sistem v primeru okvare (beri izgube podatkov) na katerem koli od nizov RAID 6 normalno zagnal in nam dal možnost, da rešimo težavo.

Da bi to naredili, bomo na prvi stopnji abstrakcije vsako vrsto fizičnega »medija« izolirali v ločeno VG.

Znanstveno gledano različni nizi RAID pripadajo različnim »zanesljivim domenam«. Ne bi smeli ustvarjati dodatne skupne točke neuspeha zanje tako, da bi jih strpali v en VG.

Prisotnost LVM na "strojni" ravni nam bo omogočila poljubno rezanje kosov različnih matrik RAID tako, da jih kombiniramo na različne načine. Na primer - teči hkrati bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, zapletena konfiguracija ZFS s predpomnilniki ali katera koli druga peklenska mešanica, da poskusite in primerjate vse.

Na ravni "strojne opreme" ne bomo uporabljali ničesar drugega kot dobre stare "debele" nosilce LVM. Izjema od tega pravila je lahko rezervna particija.

Mislim, da je do tega trenutka veliko bralcev že začelo nekaj sumiti o gnezdilnici.

LVM na trdem disku SATA

#pvcreate /dev/md3
#vgcreate backup /dev/md3

Spet novi VG..?Resnično si želimo, da bi naš operacijski sistem v primeru okvare diskovnega polja, ki ga bomo uporabili za varnostno kopiranje podatkov, še naprej normalno deloval, hkrati pa ohranil dostop do podatkov, ki niso varnostno kopirani, kot običajno. Zato, da bi se izognili težavam pri aktivaciji VG, ustvarimo ločen VG.

Nastavitev predpomnilnika LVM

Ustvarimo LV na NVMe RAID 1, da ga uporabimo kot napravo za predpomnjenje.

#lvcreate -L 70871154688B --name cache root

Zakaj je tako malo ...?Dejstvo je, da imajo naši NVMe SSD tudi predpomnilnik SLC. 4 gigabajti »brezplačnega« in 18 gigabajtov dinamičnega zaradi prostega prostora, ki ga zaseda 3-bitni MLC. Ko je ta predpomnilnik izčrpan, diski NVMe SSD ne bodo veliko hitrejši od našega SSD SSD s predpomnilnikom. Pravzaprav zaradi tega razloga nima smisla, da naredimo particijo predpomnilnika LVM veliko večjo od dvakratne velikosti predpomnilnika SLC pogona NVMe. Za uporabljene pogone NVMe avtor meni, da je smiselno narediti 32-64 gigabajtov predpomnilnika.

Dana velikost particije je potrebna za organizacijo 64 gigabajtov predpomnilnika, metapodatkov predpomnilnika in varnostne kopije metapodatkov.

Poleg tega ugotavljam, da bo LVM po umazani zaustavitvi sistema označil celoten predpomnilnik kot umazan in se bo znova sinhroniziral. Poleg tega se bo to ponovilo vsakič, ko bo v tej napravi uporabljen lvchange, dokler se sistem znova ne zažene. Zato priporočam, da takoj znova ustvarite predpomnilnik z ustreznim skriptom.

Ustvarimo LV na SATA RAID 6, da ga uporabimo kot predpomnjeno napravo.

#lvcreate -L 3298543271936B --name cache data

Zakaj samo tri terabajte..?Da lahko po potrebi SATA SSD RAID 6 uporabite še za kakšne druge potrebe. Velikost predpomnjenega prostora lahko povečate dinamično, sproti, brez zaustavitve sistema. Če želite to narediti, morate začasno ustaviti in znova omogočiti predpomnilnik, vendar je posebna prednost predpomnilnika LVM pred, na primer, bcacheom ta, da je to mogoče storiti sproti.

Ustvarimo nov VG za predpomnjenje.

#pvcreate /dev/root/cache
#pvcreate /dev/data/cache
#vgcreate cache /dev/root/cache /dev/data/cache

Ustvarimo LV na predpomnjeni napravi.

#lvcreate -L 3298539077632B --name cachedata cache /dev/data/cache

Tukaj smo takoj zavzeli ves prosti prostor na /dev/data/cache, tako da so bile vse druge potrebne particije ustvarjene takoj na /dev/root/cache. Če ste nekaj ustvarili na napačnem mestu, lahko to premaknete s pvmove.

Ustvarimo in omogočimo predpomnilnik:

#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

Zakaj taka velikost..?S praktičnimi poskusi je avtor lahko ugotovil, da je najboljši rezultat dosežen, če velikost bloka predpomnilnika LVM sovpada z velikostjo tankega bloka LVM. Poleg tega manjša kot je velikost, bolje se konfiguracija obnese pri naključnem snemanju.

64k je najmanjša dovoljena velikost bloka za tanki LVM.

Previdno pri povratnem pisanju..!ja Ta vrsta predpomnilnika odloži sinhronizacijo pisanja v predpomnjeno napravo. To pomeni, da če izgubite predpomnilnik, lahko izgubite podatke v predpomnjeni napravi. Kasneje vam bo avtor povedal, s katerimi ukrepi, poleg NVMe RAID 1, je mogoče nadomestiti to tveganje.

Ta vrsta predpomnilnika je bila izbrana namerno, da bi nadomestila slabo zmogljivost naključnega zapisovanja RAID 6.

Preverimo, kaj smo dobili:

#lvs -a -o lv_name,lv_size,devices --units B cache
LV LSize Devices
[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)

Samo [cachedata_corig] naj bo v /dev/data/cache. Če je kaj narobe, uporabite pvmove.

Po potrebi lahko predpomnilnik onemogočite z enim ukazom:

#lvconvert -y --uncache cache/cachedata

To se izvaja na spletu. LVM bo preprosto sinhroniziral predpomnilnik z diskom, ga odstranil in preimenoval cachedata_corig nazaj v cachedata.

Nastavitev LVM thin

V grobem ocenimo, koliko prostora potrebujemo za tanke metapodatke LVM:

#thin_metadata_size --block-size=64k --pool-size=6terabytes --max-thins=100000 -u bytes
thin_metadata_size - 3385794560 bytes estimated metadata area size for "--block-size=64kibibytes --pool-size=6terabytes --max-thins=100000"

Zaokrožite na 4 gigabajte: 4294967296B

Pomnožite z dva in dodajte 4194304B za metapodatke LVM PV: 8594128896B
Ustvarimo ločeno particijo na NVMe RAID 1, da vanjo postavimo tanke metapodatke LVM in njihovo varnostno kopijo:

#lvcreate -L 8594128896B --name images root

Za kaj..?Tu se lahko pojavi vprašanje: zakaj bi tanke metapodatke LVM postavljali ločeno, če bodo še vedno predpomnjeni na NVMe in bodo delovali hitro.

Čeprav je hitrost tu pomembna, še zdaleč ni glavni razlog. Stvar je v tem, da je predpomnilnik točka napake. Lahko se mu kaj zgodi in če so tanki metapodatki LVM predpomnjeni, bo to povzročilo popolno izgubo vsega. Brez popolnih metapodatkov bo skoraj nemogoče sestaviti tanke zvezke.

S premikanjem metapodatkov v ločen nepredpomnjen, a hiter nosilec zagotavljamo varnost metapodatkov v primeru izgube ali poškodbe predpomnilnika. V tem primeru bo vsa škoda, ki jo povzroči izguba predpomnilnika, lokalizirana znotraj tankih nosilcev, kar bo poenostavilo postopek obnovitve za velikostni red. Z veliko verjetnostjo bodo te poškodbe obnovljene z uporabo dnevnikov FS.

Poleg tega, če je bil predhodno narejen posnetek tankega nosilca in je bil po tem predpomnilnik vsaj enkrat v celoti sinhroniziran, potem bo zaradi notranje zasnove tankega LVM zagotovljena celovitost posnetka v primeru izgube predpomnilnika .

Ustvarimo nov VG, ki bo odgovoren za tanko zagotavljanje:

#pvcreate /dev/root/images
#pvcreate /dev/cache/cachedata
#vgcreate images /dev/root/images /dev/cache/cachedata

Ustvarimo bazen:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Zakaj -Z yPoleg tega, čemur je ta način pravzaprav namenjen – preprečitvi uhajanja podatkov iz enega virtualnega stroja v drug virtualni stroj pri prerazporeditvi prostora – se ničelnost dodatno uporablja za povečanje hitrosti naključnega pisanja v bloke, manjše od 64k. Vsak zapis, manjši od 64 K, na prej nedodeljeno območje tankega nosilca bo v predpomnilniku postal poravnan z robom 64 K. To bo omogočilo izvedbo operacije v celoti prek predpomnilnika, mimo predpomnjene naprave.

Premaknimo LV-je na ustrezne PV-je:

#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

Preveri:

#lvs -a -o lv_name,lv_size,devices --units B images
LV LSize Devices
[lvol0_pmspare] 4294967296B /dev/root/images(0)
thin-pool 274877906944B thin-pool_tdata(0)
[thin-pool_tdata] 274877906944B /dev/cache/cachedata(0)
[thin-pool_tmeta] 4294967296B /dev/root/images(1024)

Ustvarimo tanek volumen za teste:

#lvcreate -V 64G --thin-pool thin-pool --name test images

Namestili bomo pakete za testiranje in spremljanje:

#apt-get install sysstat fio

Takole lahko opazujete obnašanje naše konfiguracije shranjevanja v realnem času:

#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)'

Takole lahko preizkusimo našo konfiguracijo:

#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

Previdno! Vir!Ta koda bo izvajala 36 različnih testov, od katerih bo vsak trajal 4 sekunde. Polovica testov je za snemanje. Na NVMe lahko veliko posnameš v 4 sekundah. Do 3 gigabajte na sekundo. Tako vam lahko vsak zagon testov pisanja odvzame do 216 gigabajtov vira SSD.

Branje in pisanje mešano?ja Smiselno je izvajati teste branja in pisanja ločeno. Poleg tega je smiselno zagotoviti, da so vsi predpomnilniki sinhronizirani, tako da predhodno opravljeno pisanje ne vpliva na branje.

Rezultati se bodo med prvim zagonom in naslednjimi zelo razlikovali, ko se predpomnilnik in tanki nosilec polnita, pa tudi glede na to, ali je sistemu uspelo sinhronizirati predpomnilnike, napolnjene med zadnjim zagonom.

Med drugim priporočam merjenje hitrosti na že polnem tankem volumnu, iz katerega je bil pravkar narejen posnetek. Avtor je imel priložnost opazovati, kako se naključni zapisi močno pospešijo takoj po ustvarjanju prvega posnetka, zlasti ko predpomnilnik še ni popolnoma poln. To se zgodi zaradi semantike pisanja kopiranja ob pisanju, poravnave predpomnilnika in tankih blokov nosilca ter dejstva, da se naključno pisanje v RAID 6 spremeni v naključno branje iz RAID 6, ki mu sledi pisanje v predpomnilnik. V naši konfiguraciji je naključno branje iz RAID 6 do 6-krat (število diskov SSD SSD v polju) hitrejše od pisanja. Ker bloki za CoW se dodelijo zaporedno iz tankega bazena, potem se tudi snemanje večinoma spremeni v zaporedno.

Obe funkciji lahko uporabite v svojo korist.

Predpomnite "koherentne" posnetke

Da bi zmanjšali tveganje izgube podatkov v primeru poškodbe/izgube predpomnilnika, avtor predlaga uvedbo prakse vrtenja posnetkov, da se v tem primeru zagotovi njihova celovitost.

Prvič, ker se metapodatki tankega nosilca nahajajo v nepredpomnjeni napravi, bodo metapodatki dosledni in morebitne izgube bodo izolirane znotraj podatkovnih blokov.

Naslednji cikel vrtenja posnetkov zagotavlja celovitost podatkov znotraj posnetkov v primeru izgube predpomnilnika:

  1. Za vsak tanki nosilec z imenom <name> ustvarite posnetek z imenom <name>.cached
  2. Nastavimo prag selitve na razumno visoko vrednost: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. V zanki preverimo število umazanih blokov v predpomnilniku: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' dokler ne dobimo nule. Če ničla manjka predolgo, jo lahko ustvarite z začasnim preklopom predpomnilnika v način pisanja. Vendar pa boste ob upoštevanju hitrostnih značilnosti naših polj SSD SATA in NVMe ter njihovega vira TBW lahko hitro ujeli trenutek, ne da bi spremenili način predpomnilnika, ali pa bo vaša strojna oprema popolnoma požrla ves svoj vir v Nekaj ​​dni. Zaradi omejitev virov sistem načeloma ne more biti ves čas pod 100-odstotno zapisovalno obremenitvijo. Naši diski SSD NVMe pod 100-odstotno zapisovalno obremenitvijo bodo popolnoma izčrpali vir 3-4 dni. SSD diski SATA bodo zdržali le dvakrat dlje. Zato bomo domnevali, da gre večina obremenitve za branje, pri pisanju pa imamo relativno kratkotrajne izbruhe izjemno visoke aktivnosti v kombinaciji z nizko povprečno obremenitvijo.
  4. Takoj ko ujamemo (ali naredimo) ničlo, preimenujemo <name>.cached v <name>.committed. Stari <name>.committed je izbrisan.
  5. Po želji, če je predpomnilnik 100 % poln, ga lahko znova ustvari skript in ga tako počisti. Pri napol praznem predpomnilniku sistem med pisanjem deluje veliko hitreje.
  6. Nastavite prag selitve na nič: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata To bo začasno preprečilo sinhronizacijo predpomnilnika z glavnim medijem.
  7. Počakamo, da se v predpomnilniku nabere precej sprememb #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' ali pa se bo časovnik izklopil.
  8. Še enkrat ponovimo.

Zakaj težave z migracijskim pragom ...?Stvar je v tem, da v realni praksi »naključni« posnetek dejansko ni popolnoma naključen. Če smo nekaj zapisali v sektor velikosti 4 kilobajtov, obstaja velika verjetnost, da bo v naslednjih nekaj minutah narejen zapis v isti ali enega od sosednjih (+- 32K) sektorjev.

Z nastavitvijo praga selitve na nič, odložimo sinhronizacijo pisanja na SSD SSD in združimo več sprememb v en 64K blok v predpomnilniku. To znatno prihrani vir SSD SSD.

Kje je koda..?Žal se avtor meni, da je premalo kompetenten pri razvoju bash skriptov, ker je 100% samouk in izvaja “google” voden razvoj, zato meni, da strašne kode, ki prihaja izpod njegovih rok, ne bi smel uporabljati nihče. drugače.

Mislim, da bodo strokovnjaki na tem področju lahko samostojno prikazali vso zgoraj opisano logiko, če bo potrebno, in jo morda celo lepo oblikovali kot sistemsko storitev, kot je poskušal avtor.

Tako preprosta shema rotacije posnetkov nam bo omogočila ne le stalno popolno sinhronizacijo enega posnetka na SSD SSD, temveč nam bo omogočila tudi, da s pomočjo pripomočka thin_delta ugotovimo, kateri bloki so bili spremenjeni po njegovem ustvarjanju, in tako lokaliziramo poškodbe na glavne količine, kar močno poenostavi obnovitev.

OBREŽI/ZAVRZI v libvirt/KVM

Ker bo shramba podatkov uporabljena za KVM, ki poganja libvirt, potem bi bilo dobro, da naučimo naše VM-je ne samo, da zavzamejo prosti prostor, ampak tudi sprostijo tisto, kar ni več potrebno.

To se izvede z emulacijo podpore TRIM/DISCARD na virtualnih diskih. Če želite to narediti, morate spremeniti vrsto krmilnika v virtio-scsi in urediti 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'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>

<controller type='scsi' index='0' model='virtio-scsi'>
<alias name='scsi0'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
</controller>

Takšne ZAVRZKE iz gostujočih operacijskih sistemov LVM pravilno obdela, bloki pa so pravilno sproščeni tako v predpomnilniku kot v tankem bazenu. Pri nas se to zgodi predvsem z zamikom, ob brisanju naslednjega posnetka.

Varnostna kopija BTRFS

Uporabite že pripravljene skripte z ekstremno previdnost in na lastno odgovornost. Avtor je to kodo napisal sam in izključno zase. Prepričan sem, da ima veliko izkušenih uporabnikov Linuxa podobna orodja in ni treba kopirati nekoga drugega.

Ustvarimo nosilec na napravi za varnostno kopiranje:

#lvcreate -L 256G --name backup backup

Oblikujmo ga v BTRFS:

#mkfs.btrfs /dev/backup/backup

Ustvarimo točke priklopa in priklopimo korenske pododdelke datotečnega sistema:

#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

Ustvarimo imenike za varnostne kopije:

#mkdir /backup/btrfs/back/remote
#mkdir /backup/btrfs/back/remote/root
#mkdir /backup/btrfs/back/remote/boot

Ustvarimo imenik za varnostne skripte:

#mkdir /root/btrfs-backup

Kopirajmo skript:

Veliko strašljive bash kode. Uporabljajte na lastno odgovornost. Ne pišite jeznih pisem avtorju ...#cat >/root/btrfs-backup/btrfs-backup.sh << EOF
#!/bin/bash
PATH="/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 "Wating for lock..."
wait_lock || terminate "Failed to get lock. Exiting..."
echo "Got lock..."
}

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 found"
else
echo "$SOURCE_BASE_PATH File not found creating snapshot of $SOURCE_PATH to $SOURCE_BASE_PATH"
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_BASE_PATH
sync
if [ -d "$TARGET_BASE_PATH" ] then
echo "$TARGET_BASE_PATH found out of sync with source... removing..."
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
fi
fi
if [ -d "$TARGET_BASE_PATH" ] then
echo "$TARGET_BASE_PATH found"
else
echo "$TARGET_BASE_PATH not found. Synching to $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 found removing..."
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 found removing..."
btrfs subvolume delete -c $TARGET_PEND_PATH
sync
fi
echo "Sending $SOURCE_PEND_PATH to $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 "Help"
;;
"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 "None.."
;;
esac
) 98>$LOCK_FILE

EOF

Kaj sploh naredi..?Vsebuje nabor preprostih ukazov za ustvarjanje posnetkov BTRFS in njihovo kopiranje v drugo FS z uporabo pošiljanja/prejemanja BTRFS.

Prvi izstrelitev je lahko razmeroma dolg, saj... Na začetku bodo vsi podatki kopirani. Nadaljnji zagoni bodo zelo hitri, saj... Kopirane bodo samo spremembe.

Še en skript, ki ga bomo vstavili v cron:

Še nekaj bash kode#cat >/root/btrfs-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/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 day"
$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

Kaj to naredi..?Ustvari in sinhronizira inkrementalne posnetke navedenih nosilcev BTRFS na varnostnem FS. Po tem izbriše vse slike, ustvarjene pred 60 dnevi. Po zagonu se bodo datirani posnetki navedenih nosilcev pojavili v podimenikih /backup/btrfs/back/remote/.

Dajmo kodi pravice izvajanja:

#chmod +x /root/btrfs-backup/cron-daily.sh
#chmod +x /root/btrfs-backup/btrfs-backup.sh

Preverimo in vstavimo v cron:

#/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

Tanka varnostna kopija LVM

Ustvarimo tanek bazen na napravi za varnostno kopiranje:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T backup/thin-pool

Namestimo ddrescue, ker... skripti bodo uporabljali to orodje:

#apt-get install gddrescue

Ustvarimo imenik za skripte:

#mkdir /root/lvm-thin-backup

Kopirajmo skripte:

Notri veliko bahanja...#cat >/root/lvm-thin-backup/lvm-thin-backup.sh << EOF
#!/bin/bash
PATH="/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 "Wating for lock..."
wait_lock || terminate "Failed to get lock. Exiting..."
echo "Got lock..."
}

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 "Source LV is not thin.")
exit 1
fi

if [ "$DIFF_TARGET_POOL" == "" ] then
(>&2 echo "Target LV is not thin.")
exit 1
fi

if [ "$DIFF_SOURCE_POOL" != "$DIFF_TARGET_POOL" ] then
(>&2 echo "Source and target LVs belong to different thin pools.")
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 "Thin pool metadata snapshot already exist. Assuming stale one. Will release metadata snapshot in 5 seconds.")
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 "Failed to create thin pool metadata snapshot.")
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 found"
else
echo "$DISCARD_LV not found in $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 "Source base not found creating snapshot of $SOURCE_VG/$SOURCE_LV to $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 "Discarding $SOURCE_BASE_LV_PATH as we need to bootstrap."
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 found out of sync with source... removing..."
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 not found. Creating empty volume."
lvcreate --thin-pool "$BACKUPS_POOL" -V "$SOURCE_BASE_SIZE"B --name "$TARGET_BASE_LV" "$TARGET_VG" || exit 1
echo "Have to rebootstrap. Discarding source at $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 "Discarding target at $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 "Synching $SOURCE_PEND_LV_PATH to $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 Comparing "$SOURCE_BASE_LV_PATH" with "$TARGET_BASE_LV_PATH"
cmp "$SOURCE_BASE_LV_PATH" "$TARGET_BASE_LV_PATH"
echo Done...
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 Syncronizing "$SOURCE_BASE_LV_PATH" to "$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 "Synching $SYNC_LENGTH_BYTES bytes at $SYNC_OFFSET_BYTES from $SOURCE_BASE_LV_PATH to $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 Done...
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 "Help"
;;
"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 "None.."
;;
esac
) 98>$LOCK_FILE

EOF

Kaj to naredi...?Vsebuje nabor ukazov za upravljanje tankih posnetkov in sinhronizacijo razlike med dvema tankima posnetkoma, prejetima prek thin_delta v drugo blokovno napravo z uporabo ddrescue in blkdiscard.

Še en skript, ki ga bomo dali v cron:

Še malo bahanja#cat >/root/lvm-thin-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/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

Kaj to naredi...?Uporablja prejšnji skript za ustvarjanje in sinhronizacijo varnostnih kopij navedenih tankih nosilcev. Skript bo pustil neaktivne posnetke navedenih nosilcev, ki so potrebni za sledenje spremembam od zadnje sinhronizacije.

Ta skript je treba urediti in določiti seznam tankih nosilcev, za katere je treba narediti varnostne kopije. Navedena imena so zgolj ilustrativna. Če želite, lahko napišete skript, ki bo sinhroniziral vse nosilce.

Dajmo pravice:

#chmod +x /root/lvm-thin-backup/cron-daily.sh
#chmod +x /root/lvm-thin-backup/lvm-thin-backup.sh

Preverimo in vstavimo v cron:

#/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

Prva izstrelitev bo dolga, saj... tanki nosilci bodo v celoti sinhronizirani s kopiranjem celotnega uporabljenega prostora. Zahvaljujoč tankim metapodatkom LVM vemo, kateri bloki so dejansko v uporabi, zato bodo kopirani samo dejansko uporabljeni tanki bloki nosilca.

Naslednji zagoni bodo postopoma kopirali podatke zahvaljujoč sledenju spremembam prek tankih metapodatkov LVM.

Poglejmo, kaj se je zgodilo:

#time /root/btrfs-backup/cron-daily.sh
real 0m2,967s
user 0m0,225s
sys 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 мар 26 09:11 .
drwxr-xr-x 1 root root 16 мар 6 09:30 ..
drwxr-xr-x 1 root root 322 мар 26 02:00 .@base
drwxr-xr-x 1 root root 516 мар 6 09:39 [email protected]
drwxr-xr-x 1 root root 516 мар 6 09:39 [email protected]
...
/backup/btrfs/back/remote/root:
total 0
drwxr-xr-x 1 root root 2820 мар 26 09:11 .
drwxr-xr-x 1 root root 16 мар 6 09:30 ..
drwxr-xr-x 1 root root 240 мар 26 09:11 @.@base
drwxr-xr-x 1 root root 22 мар 26 09:11 @home.@base
drwxr-xr-x 1 root root 22 мар 6 09:39 @[email protected]
drwxr-xr-x 1 root root 22 мар 6 09:39 @[email protected]
...
drwxr-xr-x 1 root root 240 мар 6 09:39 @[email protected]
drwxr-xr-x 1 root root 240 мар 6 09:39 @[email protected]
...

#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

Kaj ima to opraviti z lutkami?

Najverjetneje glede na to, da so lahko logični nosilci LVM LV fizični nosilci LVM PV za druge VG. LVM je lahko rekurziven, kot gnezdeče lutke. To daje LVM izjemno prilagodljivost.

PS

V naslednjem članku bomo poskušali uporabiti več podobnih mobilnih pomnilniških sistemov/KVM kot osnovo za ustvarjanje geografsko porazdeljene shranjevalne/vm gruče z redundanco na več celinah z uporabo domačih namizij, domačega interneta in omrežij P2P.

Vir: www.habr.com

Dodaj komentar