Što LVM i Matryoshka imaju zajedničko?

Dobar dan.
Želio bih sa zajednicom podijeliti svoje praktično iskustvo izgradnje sustava za pohranu podataka za KVM koristeći md RAID + LVM.

Program će uključivati:

  • Izrada md RAID 1 iz NVMe SSD-a.
  • Sastavljanje md RAID 6 sa SATA SSD i običnih diskova.
  • Značajke operacije TRIM/DISCARD na SSD RAID 1/6.
  • Stvaranje md RAID 1/6 polja za podizanje sustava na zajedničkom skupu diskova.
  • Instaliranje sustava na NVMe RAID 1 kada u BIOS-u nema podrške za NVMe.
  • Korištenje LVM cache i LVM thin.
  • Korištenje BTRFS snimaka i slanje/primanje za sigurnosno kopiranje.
  • Korištenje LVM tankih snimaka i thin_delta za sigurnosne kopije u stilu BTRFS.

Ako ste zainteresirani, pogledajte kat.

Izjava

Autor ne snosi nikakvu odgovornost za posljedice korištenja ili nekorištenja materijala/primjera/kodova/savjeta/podataka iz ovog članka. Čitanjem ili korištenjem ovog materijala na bilo koji način preuzimate odgovornost za sve posljedice ovih radnji. Moguće posljedice uključuju:

  • Hrskavi NVMe SSD diskovi.
  • Potpuno potrošen resurs snimanja i kvar SSD diskova.
  • Potpuni gubitak svih podataka na svim pogonima, uključujući sigurnosne kopije.
  • Neispravan računalni hardver.
  • Potrošeno vrijeme, živci i novac.
  • Sve druge posljedice koje nisu gore navedene.

željezo

Na raspolaganju su bili:

Matična ploča iz otprilike 2013. sa Z87 čipsetom, zajedno s Intel Core i7 / Haswell.

  • Procesor 4 jezgre, 8 threadova
  • 32 GB DDR3 RAM
  • 1 x 16 ili 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 konektora

SAS adapter LSI SAS9211-8I bljeskao je u IT / HBA modu. Firmware s omogućenim RAID-om namjerno je zamijenjen HBA firmwareom za:

  1. Možete izbaciti ovaj adapter u bilo kojem trenutku i zamijeniti ga bilo kojim drugim na koji naiđete.
  2. TRIM/Discard je radio normalno na diskovima, jer... u RAID firmware-u te naredbe uopće nisu podržane, a HBA, općenito, nije briga koje se naredbe prenose sabirnicom.

Tvrdi diskovi - 8 komada HGST Travelstar 7K1000 kapaciteta 1 TB u formatu 2.5, kao za prijenosna računala. Ti su pogoni prethodno bili u RAID 6 polju. Oni će također imati koristi u novom sustavu. Za pohranu lokalnih sigurnosnih kopija.

Dodatno dodano:

6 komada SATA SSD model Samsung 860 QVO 2TB. Ovi SSD-ovi zahtijevali su veliki volumen, željena je prisutnost SLC predmemorije, pouzdanost i niska cijena. Potrebna je podrška za odbacivanje/nula, što se provjerava linijom u dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

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

Za ove SSD-ove važni su nasumična brzina čitanja/pisanja i kapacitet resursa za vaše potrebe. Radijator za njih. Obavezno. Apsolutno. Inače ih pržite dok ne postanu hrskavi tijekom prve RAID sinkronizacije.

StarTech PEX8M2E2 adapter za 2 x NVMe SSD instaliran u PCIe 3.0 8x utor. Ovo je, opet, samo HBA, ali za NVMe. Razlikuje se od jeftinih adaptera po tome što ne zahtijeva podršku za PCIe bifurkaciju s matične ploče zbog prisutnosti ugrađenog PCIe prekidača. Radit će čak iu najstarijem sustavu s PCIe, čak i ako je x1 PCIe 1.0 utor. Naravno, odgovarajućom brzinom. Tamo nema RAID-ova. Na ploči nema ugrađenog BIOS-a. Dakle, vaš sustav se neće magično naučiti pokrenuti s NVMe, a kamoli učiniti NVMe RAID zahvaljujući ovom uređaju.

Ova komponenta je nastala isključivo zbog prisutnosti samo jednog besplatnog 8x PCIe 3.0 u sustavu, a ako postoje 2 slobodna utora, lako se može zamijeniti s dva penija PEX4M2E1 ili analogima, koji se mogu kupiti bilo gdje po cijeni od 600 rubalja.

Odbacivanje svih vrsta hardvera ili ugrađenih čipset/BIOS RAID-ova napravljeno je namjerno, kako bi se mogao u potpunosti zamijeniti cijeli sustav, osim samih SSD/HDD, a da se sačuvaju svi podaci. U idealnom slučaju, tako da možete sačuvati čak i instalirani operativni sustav pri prelasku na potpuno novi/drugi hardver. Glavna stvar je da postoje SATA i PCIe portovi. To je poput live CD-a ili flash pogona za podizanje sustava, samo vrlo brzo i malo glomazno.

HumorInače, znate što se događa - ponekad morate hitno ponijeti cijeli niz sa sobom. Ali ne želim izgubiti podatke. Da biste to učinili, svi spomenuti mediji su prikladno smješteni na slajdovima u 5.25 ležištima standardnog kućišta.

Pa, i, naravno, za eksperimentiranje s različitim metodama SSD predmemoriranja u Linuxu.

Hardverski napadi su dosadni. Uključite ga. Ili radi ili ne radi. A s mdadmom uvijek ima opcija.

mekan

Prethodno je na hardver instaliran Debian 8 Jessie, koji je blizak EOL-u. RAID 6 je sastavljen od gore navedenih HDD-ova uparenih s LVM-om. Pokretao je virtualne strojeve u kvm/libvirt.

Jer Autor ima odgovarajuće iskustvo u stvaranju prijenosnih bootable SATA/NVMe flash pogona, a također, kako se ne bi pokvario uobičajeni apt predložak, Ubuntu 18.04 je odabran kao ciljni sustav, koji je već dovoljno stabiliziran, ali ima još 3 godine podrška u budućnosti.

Spomenuti sustav sadrži sve hardverske drajvere koji su nam potrebni odmah u kutiji. Ne trebamo softver ili upravljačke programe trećih strana.

Priprema za instalaciju

Za instalaciju sustava potrebna nam je Ubuntu Desktop slika. Poslužiteljski sustav ima nekakav žustri instalater, koji pokazuje pretjeranu neovisnost koja se ne može onemogućiti tako da se UEFI sistemska particija nagura na jedan od diskova, kvareći svu ljepotu. Sukladno tome, instaliran je samo u UEFI modu. Ne nudi nikakve mogućnosti.

Nismo zadovoljni s ovim.

Zašto?Nažalost, UEFI boot je izuzetno slabo kompatibilan sa RAID softverom za pokretanje, jer... Nitko nam ne nudi rezervacije za UEFI ESP particiju. Postoje recepti na mreži koji predlažu postavljanje ESP particije na flash pogon u USB priključak, ali to je točka neuspjeha. Postoje recepti koji koriste softver mdadm RAID 1 s verzijom metapodataka 0.9 koji ne sprječavaju UEFI BIOS da vidi ovu particiju, ali to traje do sretnog trenutka kada BIOS ili drugi hardverski OS zapiše nešto u ESP i zaboravi to sinkronizirati s drugim ogledala.

Osim toga, UEFI boot ovisi o NVRAM-u, koji se neće premjestiti zajedno s diskovima na novi sustav, jer dio je matične ploče.

Dakle, nećemo izmišljati novi kotač. Već imamo gotov, vremenski testiran djedov bicikl, sada nazvan Legacy/BIOS boot, koji nosi ponosno ime CSM na UEFI-kompatibilnim sustavima. Samo ćemo ga uzeti s police, podmazati, napumpati gume i obrisati vlažnom krpom.

Desktop verzija Ubuntua također se ne može ispravno instalirati s Legacy bootloaderom, ali ovdje, kako kažu, barem postoje opcije.

I tako, prikupljamo hardver i učitavamo sustav s Ubuntu Live flash pogona za podizanje sustava. Morat ćemo preuzeti pakete, pa ćemo postaviti mrežu koja vam odgovara. Ako ne uspije, možete unaprijed učitati potrebne pakete na flash pogon.

Idemo u okruženje radne površine, pokrećemo emulator terminala i krećemo:

#sudo bash

Kako…?Redak iznad je kanonski okidač za holiwars o sudo. C bоdolaze veće mogućnosti iоveću odgovornost. Pitanje je možete li to sami preuzeti. Mnogi ljudi misle da korištenje sudoa na ovaj način u najmanju ruku nije oprezno. Međutim:

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

Zašto ne ZFS...?Kada instaliramo softver na svoje računalo, u biti posuđujemo svoj hardver programerima tog softvera da ga pokreću.
Kada ovom softveru povjerimo sigurnost naših podataka, uzimamo zajam jednak trošku vraćanja tih podataka, koji ćemo jednog dana morati otplatiti.

S ove točke gledišta, ZFS je Ferrari, a mdadm+lvm je više poput bicikla.

Subjektivno, autor radije nepoznatim osobama posuđuje bicikl na kredit umjesto Ferrarija. Tu cijena pitanja nije visoka. Nema potrebe za pravima. Jednostavnije od prometnih pravila. Parking je besplatan. Prohodnost je bolja. Uvijek možete pričvrstiti noge na bicikl, a možete popraviti bicikl vlastitim rukama.

Zašto onda BTRFS...?Kako bismo pokrenuli operativni sustav, potreban nam je datotečni sustav koji je podržan u Legacy/BIOS GRUB-u odmah po otvaranju, au isto vrijeme podržava snimke uživo. Koristit ćemo ga za /boot particiju. Osim toga, autor radije koristi ovaj FS za / (root), ne zaboravljajući napomenuti da za bilo koji drugi softver možete stvoriti zasebne particije na LVM-u i montirati ih u potrebne direktorije.

Nećemo pohranjivati ​​nikakve slike virtualnih strojeva ili baza podataka na ovom FS-u.
Ovaj FS koristit će se samo za stvaranje snimki sustava bez isključivanja i zatim prijenosa tih snimki na rezervni disk koristeći slanje/primanje.

Osim toga, autor općenito preferira zadržati minimum softvera izravno na hardveru i pokrenuti sav ostali softver u virtualnim strojevima koristeći stvari poput prosljeđivanja GPU-a i PCI-USB Host kontrolera na KVM putem IOMMU-a.

Jedino što je ostalo na hardveru su pohrana podataka, virtualizacija i backup.

Ako više vjerujete ZFS-u, onda su, u načelu, za navedenu aplikaciju zamjenjivi.

Međutim, autor namjerno zanemaruje ugrađeno zrcaljenje/RAID i redundantne značajke koje ZFS, BRTFS i LVM imaju.

Kao dodatni argument, BTRFS ima mogućnost pretvaranja slučajnih zapisa u sekvencijalne, što izuzetno pozitivno utječe na brzinu sinkronizacije snapshotova/backupa na HDD-u.

Ponovno skenirajmo sve uređaje:

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

Pogledajmo okolo:

#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

Izgled diska

NVMe SSD diskovi

Ali nećemo ih označavati ni na koji način. Svejedno, naš BIOS ne vidi te pogone. Dakle, oni će u potpunosti prijeći na softverski RAID. Tamo nećemo ni stvarati odjeljke. Ako želite slijediti "canon" ili "načelno", napravite jednu veliku particiju, poput HDD-a.

SATA HDD

Ovdje ne treba ništa posebno izmišljati. Napravit ćemo jedan odjeljak za sve. Napravit ćemo particiju jer BIOS vidi te diskove i čak se može pokušati dignuti s njih. Kasnije ćemo čak instalirati GRUB na te diskove kako bi sustav odjednom to mogao učiniti.

#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

Ovdje stvari postaju zanimljive za nas.

Prvo, naši diskovi su veličine 2 TB. To je unutar prihvatljivog raspona za MBR, što ćemo i koristiti. Ako je potrebno, može se zamijeniti s GPT. GPT diskovi imaju sloj kompatibilnosti koji sustavima kompatibilnim s MBR-om omogućuje da vide prve 4 particije ako se nalaze unutar prva 2 terabajta. Glavno je da boot particija i bios_grub particija na ovim diskovima budu na početku. To vam čak omogućuje pokretanje s GPT Legacy/BIOS diskova.

Ali ovo nije naš slučaj.

Ovdje ćemo stvoriti dva odjeljka. Prvi će biti veličine 1 GB i koristit će se za RAID 1 /boot.

Drugi će se koristiti za RAID 6 i zauzet će sav preostali slobodni prostor osim malog nedodijeljenog područja na kraju pogona.

Što je ovo neoznačeno područje?Prema izvorima na mreži, naši SATA SSD-ovi imaju ugrađenu dinamički proširivu SLC predmemoriju veličine od 6 do 78 gigabajta. Dobivamo 6 gigabajta "besplatno" zbog razlike između "gigabajta" i "gibibajta" u podatkovnoj tablici pogona. Preostala 72 gigabajta dodijeljena su iz neiskorištenog prostora.

Ovdje treba napomenuti da imamo SLC cache, a prostor je zauzet u 4 bitnom MLC modu. Što za nas zapravo znači da ćemo za svaka 4 gigabajta slobodnog prostora dobiti samo 1 gigabajt SLC predmemorije.

Pomnožite 72 gigabajta s 4 i dobit ćete 288 gigabajta. Ovo je slobodni prostor koji nećemo označiti kako bismo omogućili pogonima da u potpunosti iskoriste SLC predmemoriju.

Tako ćemo efektivno dobiti do 312 gigabajta SLC predmemorije s ukupno šest diskova. Od svih pogona, 2 će se koristiti u RAID-u za redundantnost.

Ova količina predmemorije omogućit će nam da se iznimno rijetko u stvarnom životu susrećemo sa situacijom u kojoj zapis ne ide u predmemoriju. Ovo izuzetno dobro kompenzira najtužniji nedostatak QLC memorije - izuzetno nisku brzinu pisanja kada se podaci pišu zaobilazeći predmemoriju. Ako vaša opterećenja ne odgovaraju ovome, onda preporučujem da dobro razmislite o tome koliko će vaš SSD izdržati pod takvim opterećenjem, uzimajući u obzir TBW iz podatkovne tablice.

#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

Stvaranje nizova

Prvo, moramo preimenovati stroj. Ovo je neophodno jer je naziv glavnog računala dio naziva polja negdje unutar mdadm-a i negdje na nešto utječe. Naravno, nizovi se kasnije mogu preimenovati, ali to je nepotreban korak.

#mcedit /etc/hostname
#mcedit /etc/hosts
#hostname
vdesk0

NVMe SSD diskovi

#mdadm --create --verbose --assume-clean /dev/md0 --level=1 --raid-devices=2 /dev/nvme[0-1]n1

Zašto -pretpostaviti-čisti...?Da bi se izbjeglo inicijaliziranje nizova. Ovo vrijedi za obje RAID razine 1 i 6. Sve može raditi bez inicijalizacije ako je novi niz. Štoviše, inicijalizacija SSD polja nakon stvaranja je gubitak TBW resursa. Koristimo TRIM/DISCARD gdje je to moguće na sklopljenim SSD poljima kako bismo ih "inicijalizirali".

Za SSD nizove, RAID 1 DISCARD je podržan odmah.

Za SSD RAID 6 DISCARD polja, morate ga omogućiti u parametrima modula jezgre.

Ovo treba učiniti samo ako svi SSD-ovi koji se koriste u nizovima razine 4/5/6 u ovom sustavu imaju radnu podršku za discard_zeroes_data. Ponekad naiđete na čudne pogone koji govore kernelu da je ova funkcija podržana, ali zapravo je nema ili funkcija ne radi uvijek. Trenutačno je podrška dostupna gotovo posvuda, no postoje stari pogoni i firmware s pogreškama. Iz tog je razloga podrška za DISCARD onemogućena prema zadanim postavkama za RAID 6.

Pažnja, sljedeća naredba uništit će sve podatke na NVMe pogonima "inicijaliziranjem" polja s "nulama".

#blkdiscard /dev/md0

Ako nešto pođe po zlu, pokušajte navesti 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

Zašto tako velik...?Povećanje veličine chunk-a ima pozitivan učinak na brzinu nasumičnog čitanja u blokovima do veličine chunk-a uključujući. To se događa jer se jedna operacija odgovarajuće veličine ili manja može u potpunosti izvršiti na jednom uređaju. Stoga se zbraja IOPS sa svih uređaja. Prema statistikama, 99% IO ne prelazi 512K.

RAID ima 6 IOPS po pisanju uvijek manji ili jednak IOPS-u jednog pogona. Kada, kao slučajno čitanje, IOPS može biti nekoliko puta veći od jednog diska, a ovdje je veličina bloka od ključne važnosti.
Autor ne vidi smisao u pokušaju optimizacije parametra koji je loš u RAID 6 dizajnu i umjesto toga optimizira ono u čemu je RAID 6 dobar.
Loše nasumično pisanje RAID-a 6 nadoknadit ćemo NVMe predmemorijom i trikovima s tankom opskrbom.

Još nismo omogućili DISCARD za RAID 6. Stoga za sada nećemo "inicijalizirati" ovaj niz. To ćemo učiniti kasnije, nakon instalacije OS-a.

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-u

Radi brzine, želimo smjestiti korijenski datotečni sustav na NVMe RAID 1 koji je /dev/md0.
Međutim, i dalje ćemo trebati ovo brzo polje za druge potrebe, kao što su swap, metapodaci i LVM-cache i LVM-thin metapodaci, tako da ćemo stvoriti LVM VG na ovom polju.

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

Kreirajmo particiju za korijenski datotečni sustav.

#lvcreate -L 128G --name root root

Napravimo particiju za swap prema veličini RAM-a.

#lvcreate -L 32G --name swap root

Instalacija OS-a

Ukupno imamo sve potrebno za instalaciju sustava.

Pokrenite čarobnjaka za instalaciju sustava iz okruženja Ubuntu Live. Normalna instalacija. Samo u fazi odabira diskova za instalaciju morate navesti sljedeće:

  • /dev/md1, - točka montiranja /boot, FS - BTRFS
  • /dev/root/root (aka /dev/mapper/root-root), - točka montiranja / (root), FS - BTRFS
  • /dev/root/swap (aka /dev/mapper/root-swap), - koristiti kao swap particiju
  • Instalirajte bootloader na /dev/sda

Kada odaberete BTRFS kao korijenski datotečni sustav, instalacijski program će automatski stvoriti dva BTRFS volumena pod nazivom "@" za / (root) i "@home" za /home.

Počnimo s instalacijom...

Instalacija će završiti s modalnim dijaloškim okvirom koji ukazuje na pogrešku u instaliranju bootloadera. Nažalost, nećete moći izaći iz ovog dijaloškog okvira standardnim sredstvima i nastaviti instalaciju. Odjavljujemo se iz sustava i ponovno se logiramo, završavajući na čistom Ubuntu Live desktopu. Otvorite terminal i ponovno:

#sudo bash

Napravite chroot okruženje za nastavak instalacije:

#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 mrežu i naziv hosta u chroot-u:

#cat /etc/hostname >/mnt/chroot/etc/hostname
#cat /etc/hosts >/mnt/chroot/etc/hosts
#cat /etc/resolv.conf >/mnt/chroot/etc/resolv.conf

Idemo u chroot okruženje:

#chroot /mnt/chroot

Prije svega, dostavit ćemo pakete:

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

Provjerimo i popravimo sve pakete koji su krivo instalirani zbog nepotpune instalacije sustava:

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

Ako nešto ne uspije, možda ćete prvo morati urediti /etc/apt/sources.list

Prilagodimo parametre za RAID 6 modul kako bismo omogućili TRIM/DISCARD:

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

Dotjerajmo malo naše nizove:

#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

Što je to bilo..?Napravili smo skup udev pravila koja će učiniti sljedeće:

  • Postavite veličinu predmemorije bloka za RAID 2020 tako da bude primjerena za 6. Zadana vrijednost, čini se, nije se promijenila od stvaranja Linuxa, a nije bila odgovarajuća dugo vremena.
  • Rezervirajte minimalno IO za vrijeme trajanja provjera/sinkronizacija polja. Ovo je da spriječite da vaši nizovi zaglave u stanju vječne sinkronizacije pod opterećenjem.
  • Ograničite maksimalni IO tijekom provjera/sinkronizacije nizova. Ovo je neophodno kako sinkronizacija/provjera SSD RAID-ova ne bi spržila vaše pogone. To posebno vrijedi za NVMe. (Sjećate se radijatora? Nisam se šalio.)
  • Zabranite diskovima da zaustave rotaciju vretena (HDD) putem APM-a i postavite vrijeme mirovanja za kontrolere diska na 7 sati. Možete potpuno onemogućiti APM ako vaši pogoni to mogu (-B 255). Uz zadanu vrijednost, pogoni će se zaustaviti nakon pet sekundi. Tada OS želi resetirati predmemoriju diska, diskovi će se ponovno pokrenuti i sve će krenuti ispočetka. Diskovi imaju ograničen najveći broj okretaja vretena. Takav jednostavan zadani ciklus može lako uništiti vaše diskove za nekoliko godina. Ne pate svi diskovi od toga, ali naši su “laptop” s odgovarajućim zadanim postavkama, zbog kojih RAID izgleda kao mini-MAID.
  • Instalirajte readahead na diskove (rotirajuće) 1 megabajt - dva uzastopna bloka/komad RAID 6
  • Onemogućite čitanje unaprijed na samim nizovima.

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

Zašto je to..?/boot particiju tražit ćemo po UUID-u. Imenovanje polja bi se teoretski moglo promijeniti.

Preostale odjeljke tražit ćemo prema LVM imenima u /dev/mapper/vg-lv zapisu, jer oni identificiraju particije sasvim jedinstveno.

Ne koristimo UUID za LVM jer UUID LVM volumena i njihovih snimaka može biti isti.Montirati /dev/mapper/root-root.. dvaput?Da. Točno. Značajka BTRFS-a. Ovaj datotečni sustav može se montirati nekoliko puta s različitim subvolovima.

Zbog te iste značajke, preporučujem da nikad ne stvarate LVM snimke aktivnih BTRFS jedinica. Možda ćete dobiti iznenađenje kada ponovno pokrenete sustav.

Idemo ponovno generirati mdadm konfiguraciju:

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

Prilagodimo LVM postavke:

#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

Što je to bilo..?Omogućili smo automatsku ekspanziju LVM tankih bazena nakon dostizanja 90% zauzetog prostora za 5% volumena.

Povećali smo maksimalni broj blokova predmemorije za LVM predmemoriju.

Spriječili smo LVM da traži LVM volumene (PV) na:

  • uređaji koji sadrže LVM predmemoriju (cdata)
  • uređaji predmemorirani pomoću LVM predmemorije, zaobilazeći predmemoriju ( _corig). U tom će se slučaju sam predmemorirani uređaj i dalje skenirati kroz predmemoriju (samo ).
  • uređaji koji sadrže metapodatke LVM predmemorije (cmeta)
  • svi uređaji u VG s imenom slike. Ovdje ćemo imati slike diskova virtualnih strojeva i ne želimo da LVM na hostu aktivira volumene koji pripadaju gostujućem OS-u.
  • svi uređaji u VG s imenom backup. Ovdje ćemo imati sigurnosne kopije slika virtualnog stroja.
  • svi uređaji čije ime završava s "gpv" (gost fizički volumen)

Omogućili smo podršku DISCARD prilikom oslobađanja slobodnog prostora na LVM VG. Budi oprezan. Zbog toga će brisanje LV-ova na SSD-u oduzeti dosta vremena. To se posebno odnosi na SSD RAID 6. No, prema planu, koristit ćemo thin provisioning, tako da nas to neće nimalo ometati.

Ažurirajmo initramfs sliku:

#update-initramfs -u -k all

Instalirajte i konfigurirajte grub:

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

Koje diskove odabrati?Svi koji su sd*. Sustav se mora moći pokrenuti s bilo kojeg radnog SATA pogona ili SSD-a.

Zašto su dodali os-prober..?Za pretjeranu neovisnost i razigrane ruke.

Ne radi ispravno ako je jedan od RAID-ova u degradiranom stanju. Pokušava tražiti OS na particijama koje se koriste u virtualnim strojevima koji rade na ovom hardveru.

Ako vam treba, možete ga ostaviti, ali imajte na umu sve navedeno. Preporučujem da potražite recepte kako se riješiti nestašnih ruku na internetu.

Ovime smo završili početnu instalaciju. Vrijeme je za ponovno podizanje sustava u novoinstalirani OS. Ne zaboravite ukloniti Live CD/USB za podizanje sustava.

#exit
#reboot

Odaberite bilo koji SATA SSD kao uređaj za pokretanje.

LVM na SATA SSD

U ovom smo trenutku već pokrenuli novi OS, konfigurirali mrežu, apt, otvorili emulator terminala i pokrenuli:

#sudo bash

Nastavimo.

"Inicijalizirajte" niz sa SATA SSD-a:

#blkdiscard /dev/md2

Ako ne uspije, pokušajte:

#blkdiscard --step 65536 /dev/md2
Stvorite LVM VG na SATA SSD-u:

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

Zašto još jedan VG..?Zapravo, već imamo VG pod nazivom root. Zašto ne dodati sve u jednu VG?

Ako postoji nekoliko PV-ova u VG-u, tada da bi se VG ispravno aktivirao, svi PV-ovi moraju biti prisutni (online). Iznimka je LVM RAID, koji namjerno ne koristimo.

Zaista želimo da se operativni sustav normalno pokrene ako dođe do kvara (čitaj gubitak podataka) na bilo kojem od RAID 6 nizova i da nam da priliku da riješimo problem.

Da bismo to učinili, na prvoj razini apstrakcije svaku ćemo vrstu fizičkog "medija" izolirati u zaseban VG.

Znanstveno govoreći, različiti RAID nizovi pripadaju različitim "domenama pouzdanosti". Ne biste im trebali stvarati dodatnu zajedničku točku neuspjeha trpajući ih u jednu VG.

Prisutnost LVM-a na "hardverskoj" razini omogućit će nam proizvoljno rezanje dijelova različitih RAID polja kombinirajući ih na različite načine. Na primjer – trčanje istovremeno bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, složena ZFS konfiguracija s predmemorijama ili bilo koja druga paklena mješavina da probate i usporedite sve.

Na "hardverskoj" razini nećemo koristiti ništa osim dobrih starih "debelih" LVM volumena. Iznimka od ovog pravila može biti rezervna particija.

Mislim da su do tog trenutka mnogi čitatelji već počeli nešto sumnjati u lutku za gniježđenje.

LVM na SATA HDD

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

Opet novi VG..?Zaista želimo da ako diskovno polje koje ćemo koristiti za sigurnosno kopiranje podataka otkaže, naš operativni sustav nastavi normalno raditi, a da zadrži pristup podacima koji nisu sigurnosno kopirani kao i obično. Stoga, kako bismo izbjegli probleme s aktivacijom VG-a, stvaramo zaseban VG.

Postavljanje LVM predmemorije

Kreirajmo LV na NVMe RAID 1 da ga koristimo kao uređaj za predmemoriju.

#lvcreate -L 70871154688B --name cache root

Zašto je tako malo...?Činjenica je da naši NVMe SSD-ovi također imaju SLC predmemoriju. 4 gigabajta “slobodnog” i 18 gigabajta dinamičkog zbog slobodnog prostora zauzetog u 3-bitnom MLC-u. Nakon što se ova predmemorija iscrpi, NVMe SSD-ovi neće biti puno brži od našeg SATA SSD-a s predmemorijom. Zapravo, iz tog razloga, nema smisla da particiju LVM predmemorije učinimo puno većom od dvostruke veličine SLC predmemorije NVMe pogona. Za korištene NVMe pogone, autor smatra razumnim napraviti 32-64 gigabajta predmemorije.

Zadana veličina particije potrebna je za organiziranje 64 gigabajta predmemorije, metapodataka predmemorije i sigurnosne kopije metapodataka.

Dodatno, napominjem da će nakon prljavog gašenja sustava LVM označiti cijelu predmemoriju kao prljavu i ponovno će se sinkronizirati. Štoviše, ovo će se ponavljati svaki put kada se lvchange koristi na ovom uređaju dok se sustav ponovno ne pokrene. Stoga preporučujem da odmah ponovno izradite predmemoriju pomoću odgovarajuće skripte.

Kreirajmo LV na SATA RAID 6 da bismo ga koristili kao predmemorirani uređaj.

#lvcreate -L 3298543271936B --name cache data

Zašto samo tri terabajta..?Tako da po potrebi možete koristiti SATA SSD RAID 6 za neke druge potrebe. Veličina predmemoriranog prostora može se povećavati dinamički, u hodu, bez zaustavljanja sustava. Da biste to učinili, morate privremeno zaustaviti i ponovno omogućiti predmemoriju, ali izrazita prednost LVM-cachea u odnosu na, na primjer, bcache je ta što se to može učiniti u hodu.

Kreirajmo novi VG za predmemoriju.

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

Kreirajmo LV na predmemoriranom uređaju.

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

Ovdje smo odmah zauzeli sav slobodan prostor na /dev/data/cache tako da su sve ostale potrebne particije odmah stvorene na /dev/root/cache. Ako ste nešto stvorili na pogrešnom mjestu, možete to premjestiti pomoću pvmove.

Kreirajmo i omogućimo predmemoriju:

#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

Zašto takva veličina...?Kroz praktične pokuse autor je uspio otkriti da se najbolji rezultat postiže ako se veličina LVM cache bloka podudara s veličinom LVM tankog bloka. Štoviše, što je manja veličina, to je konfiguracija bolja u nasumičnim snimkama.

64k je minimalna dopuštena veličina bloka za LVM thin.

Budite oprezni pri povratnom odgovoru..!Da. Ova vrsta predmemorije odgađa sinkronizaciju pisanja na predmemorirani uređaj. To znači da ako se predmemorija izgubi, možete izgubiti podatke na predmemoriranom uređaju. Kasnije će vam autor reći koje se mjere, uz NVMe RAID 1, mogu poduzeti da se kompenzira ovaj rizik.

Ova vrsta predmemorije odabrana je namjerno kako bi se kompenzirala loša izvedba nasumičnog pisanja RAID-a 6.

Provjerimo što 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 se [cachedata_corig] treba nalaziti na /dev/data/cache. Ako nešto nije u redu, upotrijebite pvmove.

Ako je potrebno, možete onemogućiti predmemoriju jednom naredbom:

#lvconvert -y --uncache cache/cachedata

To se radi on-line. LVM će jednostavno sinkronizirati predmemoriju s diskom, ukloniti je i preimenovati cachedata_corig natrag u cachedata.

Postavljanje LVM tankog

Ugrubo procijenimo koliko prostora trebamo za LVM tanke metapodatke:

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

Zaokružite na 4 gigabajta: 4294967296B

Pomnožite s dva i dodajte 4194304B za LVM PV metapodatke: 8594128896B
Kreirajmo zasebnu particiju na NVMe RAID 1 kako bismo na nju postavili LVM tanke metapodatke i njihovu sigurnosnu kopiju:

#lvcreate -L 8594128896B --name images root

Za što..?Ovdje se može pojaviti pitanje: zašto postavljati LVM tanke metapodatke odvojeno ako će i dalje biti predmemorirani na NVMe i radit će brzo.

Iako je brzina ovdje bitna, daleko je od glavnog razloga. Stvar je u tome što je predmemorija točka kvara. Nešto bi mu se moglo dogoditi, a ako su LVM tanki metapodaci u predmemoriji, to će uzrokovati potpuni gubitak svega. Bez kompletnih metapodataka, bit će gotovo nemoguće sastaviti tanke sveske.

Premještanjem metapodataka u zaseban volumen bez predmemorije, ali brz, jamčimo sigurnost metapodataka u slučaju gubitka ili oštećenja predmemorije. U ovom slučaju, sva šteta uzrokovana gubitkom predmemorije bit će lokalizirana unutar tankih volumena, što će pojednostaviti postupak oporavka za redove veličine. Uz veliku vjerojatnost, ta će se oštećenja obnoviti korištenjem FS zapisa.

Štoviše, ako je prethodno snimljena snimka tankog volumena, a nakon toga je predmemorija u potpunosti sinkronizirana barem jednom, tada će, zbog internog dizajna tankog LVM-a, integritet snimke biti zajamčen u slučaju gubitka predmemorije .

Kreirajmo novi VG koji će biti odgovoran za tanko pružanje:

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

Kreirajmo bazen:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Zašto -Z yUz ono za što je ovaj način rada zapravo i namijenjen – spriječiti curenje podataka s jednog virtualnog stroja na drugi virtualni stroj prilikom redistribucije prostora – zeroing se dodatno koristi za povećanje brzine nasumičnog pisanja u blokove manje od 64k. Svako pisanje manje od 64K na prethodno nedodijeljeno područje tankog volumena postat će 64K rubno poravnato u predmemorij. To će omogućiti da se operacija u potpunosti izvede kroz predmemoriju, zaobilazeći predmemorirani uređaj.

Premjestimo LV-ove na odgovarajuće PV-ove:

#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

Provjerimo:

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

Kreirajmo tanki volumen za testove:

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

Instalirat ćemo pakete za testiranje i praćenje:

#apt-get install sysstat fio

Ovako možete promatrati ponašanje naše konfiguracije pohrane u stvarnom vremenu:

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

Ovako možemo testirati našu konfiguraciju:

#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

Pažljivo! Resurs!Ovaj kod će pokrenuti 36 različitih testova, a svaki će trajati 4 sekunde. Polovica testova je za snimanje. Možete puno snimiti na NVMe u 4 sekunde. Do 3 gigabajta u sekundi. Dakle, svako pokretanje testova pisanja može vam pojesti do 216 gigabajta SSD resursa.

Čitanje i pisanje pomiješano?Da. Ima smisla izvoditi testove čitanja i pisanja odvojeno. Štoviše, ima smisla osigurati da su sve predmemorije sinkronizirane tako da prethodno napravljeno pisanje ne utječe na čitanje.

Rezultati će uvelike varirati tijekom prvog pokretanja i sljedećih kako se predmemorija i tanki volumen budu punili, a također ovisno o tome je li sustav uspio sinkronizirati predmemorije ispunjene tijekom posljednjeg pokretanja.

Između ostalog, preporučam mjerenje brzine na već punom tankom volumenu s kojeg je upravo napravljena snimka. Autor je imao priliku promatrati kako se nasumična pisanja naglo ubrzavaju odmah nakon stvaranja prve snimke, osobito kada predmemorija još nije potpuno puna. To se događa zbog semantike pisanja kopiranja na pisanje, usklađivanja predmemorije i tankih blokova volumena i činjenice da se nasumično pisanje u RAID 6 pretvara u nasumično čitanje iz RAID-a 6 nakon čega slijedi pisanje u predmemoriju. U našoj konfiguraciji, nasumično čitanje iz RAID 6 je do 6 puta (broj SATA SSD-ova u nizu) brže od pisanja. Jer blokovi za CoW dodjeljuju se sekvencijalno iz tankog skupa, tada se snimanje, većim dijelom, također pretvara u sekvencijalno.

Obje ove značajke možete iskoristiti u svoju korist.

Predmemorirajte "koherentne" snimke

Kako bi se smanjio rizik od gubitka podataka u slučaju oštećenja/gubitka predmemorije, autor predlaže uvođenje prakse rotiranja snimki kako bi se u tom slučaju zajamčila njihova cjelovitost.

Prvo, budući da se metapodaci tankog volumena nalaze na uređaju bez predmemoriranja, metapodaci će biti dosljedni, a mogući gubici izolirani unutar podatkovnih blokova.

Sljedeći ciklus rotacije snimki jamči cjelovitost podataka unutar snimki u slučaju gubitka predmemorije:

  1. Za svaki tanki volumen s nazivom <name>, stvorite snimku s nazivom <name>.cached
  2. Postavimo prag migracije na razumno visoku vrijednost: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. U petlji provjeravamo broj prljavih blokova u cacheu: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' dok ne dobijemo nulu. Ako nula predugo nedostaje, može se stvoriti privremenim prebacivanjem predmemorije u način rada za pisanje. Međutim, uzimajući u obzir karakteristike brzine naših SATA i NVMe SSD polja, kao i njihov TBW resurs, ili ćete moći brzo uhvatiti trenutak bez promjene načina predmemorije ili će vaš hardver potpuno pojesti cijeli resurs u Nekoliko dana. Zbog ograničenja resursa, sustav u načelu ne može cijelo vrijeme biti pod 100% opterećenjem pisanja. Naši NVMe SSD diskovi pod opterećenjem pisanja od 100% u potpunosti će iscrpiti resurs 3-4 dana. SATA SSD diskovi trajat će samo dvostruko duže. Stoga ćemo pretpostaviti da najveći dio opterećenja ide na čitanje, a imamo relativno kratkoročne nalete iznimno visoke aktivnosti u kombinaciji s niskim prosječnim opterećenjem za pisanje.
  4. Čim uhvatimo (ili napravimo) nulu, preimenujemo <name>.cached u <name>.committed. Stari <name>.committed je izbrisan.
  5. Po izboru, ako je predmemorija 100% puna, može se ponovno stvoriti skriptom i tako je očistiti. Uz polupraznu predmemoriju, sustav radi puno brže pri pisanju.
  6. Postavite prag migracije na nulu: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Ovo će privremeno spriječiti sinkronizaciju predmemorije s glavnim medijem.
  7. Čekamo dok se dosta promjena ne nakupi u cacheu #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' ili će se mjerač vremena isključiti.
  8. Opet ponavljamo.

Zašto poteškoće s migracijskim pragom...?Stvar je u tome da u stvarnoj praksi "nasumična" snimka zapravo nije potpuno nasumična. Ako smo nešto upisali u sektor veličine 4 kilobajta, postoji velika vjerojatnost da će se u sljedećih nekoliko minuta napraviti zapis u isti ili neki od susjednih (+- 32K) sektora.

Postavljanjem praga migracije na nulu, odgađamo sinkronizaciju pisanja na SATA SSD i agregiramo nekoliko promjena na jedan blok od 64K u predmemoriju. Ovo značajno štedi resurs SATA SSD-a.

Gdje je šifra..?Nažalost, autor sebe smatra nedovoljno kompetentnim u razvoju bash skripti jer je 100% samouk i prakticira “google” vođen razvoj, stoga smatra da užasni kod koji izlazi iz njegovih ruku nitko ne bi trebao koristiti drugo.

Mislim da će stručnjaci u ovom području moći samostalno prikazati svu gore opisanu logiku, ako je potrebno, a možda čak i lijepo dizajnirati kao systemd uslugu, kao što je autor pokušao učiniti.

Takva jednostavna shema rotacije snimke omogućit će nam ne samo da stalno imamo jednu snimku potpuno sinkroniziranu na SATA SSD-u, već će nam također omogućiti da pomoću uslužnog programa thin_delta saznamo koji su blokovi promijenjeni nakon njegove izrade i tako lokaliziramo štetu na glavne količine, što uvelike pojednostavljuje oporavak.

TRIM/DISCARD u libvirt/KVM

Jer pohrana podataka će se koristiti za KVM koji pokreće libvirt, onda bi bilo dobro naučiti naše VM-ove ne samo da zauzimaju slobodan prostor, već i da oslobađaju ono što više nije potrebno.

To se postiže emulacijom TRIM/DISCARD podrške na virtualnim diskovima. Da biste to učinili, trebate promijeniti vrstu kontrolera u virtio-scsi i 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>

Takve DISCARD-ove iz gostujućih OS-ova LVM ispravno obrađuje, a blokovi se ispravno oslobađaju iu predmemorij iu tankom skupu. U našem slučaju to se događa uglavnom odgođeno, prilikom brisanja sljedeće snimke.

BTRFS sigurnosna kopija

Koristite gotove skripte sa ekstreman oprez i na vlastiti rizik. Autor je ovaj kod napisao sam i isključivo za sebe. Siguran sam da mnogi iskusni korisnici Linuxa imaju slične alate i nema potrebe kopirati tuđe.

Kreirajmo volumen na uređaju za sigurnosno kopiranje:

#lvcreate -L 256G --name backup backup

Formatirajmo ga u BTRFS:

#mkfs.btrfs /dev/backup/backup

Kreirajmo točke montiranja i montirajmo korijenske pododjeljke datotečnog sustava:

#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

Kreirajmo direktorije za sigurnosne kopije:

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

Kreirajmo direktorij za sigurnosne skripte:

#mkdir /root/btrfs-backup

Kopirajmo skriptu:

Puno zastrašujućeg bash koda. Koristite na vlastitu odgovornost. Ne piši ljutita pisma autoru...#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

Što uopće radi..?Sadrži skup jednostavnih naredbi za stvaranje BTRFS snimaka i njihovo kopiranje na drugi FS pomoću BTRFS slanja/primanja.

Prvo lansiranje može trajati relativno dugo, jer... Na početku će svi podaci biti kopirani. Daljnja lansiranja bit će vrlo brza, jer... Kopirat će se samo promjene.

Još jedna skripta koju ćemo staviti u cron:

Još malo bash koda#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

Što to radi..?Stvara i sinkronizira inkrementalne snimke navedenih BTRFS volumena na sigurnosnom FS-u. Nakon toga briše sve slike stvorene prije 60 dana. Nakon pokretanja, datirane snimke navedenih volumena pojavit će se u poddirektoriju /backup/btrfs/back/remote/.

Dajmo kodu prava za izvršavanje:

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

Provjerimo to i stavimo u 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

LVM tanka sigurnosna kopija

Kreirajmo tanki skup na uređaju za sigurnosno kopiranje:

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

Instalirajmo ddrescue, jer... skripte će koristiti ovaj alat:

#apt-get install gddrescue

Kreirajmo direktorij za skripte:

#mkdir /root/lvm-thin-backup

Kopirajmo skripte:

Puno galame unutra...#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

Što to radi...?Sadrži skup naredbi za manipuliranje tankim snimkama i sinkronizaciju razlike između dvije tanke snimke primljene putem thin_delta na drugi blok uređaj pomoću ddrescue i blkdiscard.

Još jedna skripta koju ćemo staviti u cron:

Još 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

Što to radi...?Koristi prethodnu skriptu za stvaranje i sinkronizaciju sigurnosnih kopija navedenih tankih volumena. Skripta će ostaviti neaktivne snimke navedenih volumena, koji su potrebni za praćenje promjena od zadnje sinkronizacije.

Ova se skripta mora urediti, specificirajući popis tankih volumena za koje treba izraditi sigurnosne kopije. Navedena imena služe samo u ilustrativne svrhe. Ako želite, možete napisati skriptu koja će sinkronizirati sve volumene.

Dajmo prava:

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

Provjerimo to i stavimo u 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

Prvo lansiranje će trajati dugo, jer... tanki volumeni bit će potpuno sinkronizirani kopiranjem cijelog iskorištenog prostora. Zahvaljujući LVM tankim metapodacima, znamo koji su blokovi stvarno u upotrebi, tako da će se kopirati samo stvarno korišteni tanki blokovi volumena.

Naknadna izvođenja će postupno kopirati podatke zahvaljujući praćenju promjena putem LVM tankih metapodataka.

Da vidimo što se dogodilo:

#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

Kakve to veze ima s lutkama?

Najvjerojatnije, s obzirom da LVM LV logički volumeni mogu biti LVM PV fizički volumeni za druge VG-ove. LVM može biti rekurzivan, poput lutkica. To daje LVM-u izuzetnu fleksibilnost.

PS

U sljedećem članku pokušat ćemo upotrijebiti nekoliko sličnih mobilnih sustava za pohranu/KVM kao osnovu za stvaranje geo-distribuiranog skladišnog/vm klastera sa redundancijom na nekoliko kontinenata koristeći kućna stolna računala, kućni Internet i P2P mreže.

Izvor: www.habr.com

Dodajte komentar