Šta LVM i Matryoshka imaju zajedničko?

Vrsta vremena dana.
Želeo bih da podelim sa zajednicom svoje praktično iskustvo izgradnje sistema za skladištenje podataka za KVM koristeći md RAID + LVM.

Program će uključivati:

  • Izgradnja md RAID 1 sa NVMe SSD-a.
  • Sastavljanje md RAID 6 sa SATA SSD-a i običnih diskova.
  • Karakteristike rada TRIM/DISCARD na SSD RAID 1/6.
  • Kreiranje md RAID 1/6 niza za pokretanje na uobičajenom skupu diskova.
  • Instaliranje sistema na NVMe RAID 1 kada nema podrške za NVMe u BIOS-u.
  • Korištenje LVM keš memorije i LVM tanki.
  • Korištenje BTRFS snimaka i slanje/primanje radi sigurnosne kopije.
  • Korištenje LVM tankih snimaka i thin_delta za sigurnosne kopije u BTRFS stilu.

Ako ste zainteresovani, pogledajte kat.

Prijavni formular

Autor ne snosi nikakvu odgovornost za posljedice korištenja ili neupotrebe materijala/primjera/koda/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:

  • Prženi NVMe SSD diskovi.
  • Potpuno potrošen resurs za snimanje i kvar SSD diskova.
  • Potpuni gubitak svih podataka na svim diskovima, uključujući rezervne kopije.
  • Neispravan računarski hardver.
  • Potrošeno vrijeme, živci i novac.
  • Sve druge posljedice koje nisu gore navedene.

Gvožđe

Na raspolaganju su bili:

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

  • Procesor 4 jezgra, 8 niti
  • 32 GB DDR3 RAM-a
  • 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 je prešao na IT / HBA mod. Firmver sa RAID-om je namjerno zamijenjen HBA firmverom kako bi:

  1. Možete izbaciti ovaj adapter u bilo koje vrijeme i zamijeniti ga bilo kojim drugim na koji naiđete.
  2. TRIM/Discard je normalno radio na diskovima, jer... u RAID firmveru ove komande uopće nisu podržane, a HBA, općenito, nije briga koje se komande prenose preko magistrale.

Tvrdi diskovi - 8 komada HGST Travelstar 7K1000 kapaciteta 1 TB u faktoru 2.5, kao za laptope. Ovi diskovi su prethodno bili u RAID 6 nizu. Oni će takođe imati koristi u novom sistemu. Za pohranjivanje lokalnih sigurnosnih kopija.

Dodatno dodano:

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

kernel: ata1.00: Enabling discard_zeroes_data

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

Za ove SSD-ove važna je nasumična brzina čitanja/pisanja i kapacitet resursa za vaše potrebe. Radijator za njih. Neophodno. Apsolutno. U suprotnom, pržite ih dok ne postanu hrskavi tokom prve RAID sinhronizacije.

StarTech PEX8M2E2 adapter za 2 x NVMe SSD instaliran u PCIe 3.0 8x slot. 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 prisustva ugrađenog PCIe prekidača. Radit će čak iu najstarijem sistemu sa PCIe, čak i ako je to x1 PCIe 1.0 slot. Naravno, odgovarajućom brzinom. Tamo nema RAID-ova. Na ploči nema ugrađenog BIOS-a. Dakle, vaš sistem neće magično naučiti da se pokreće sa NVMe, a još manje da radi NVMe RAID zahvaljujući ovom uređaju.

Ova komponenta je nastala isključivo zbog prisustva samo jednog besplatnog 8x PCIe 3.0 u sistemu, a, ako postoje 2 slobodna slota, lako se može zamijeniti sa dva peni PEX4M2E1 ili analoga, koji se mogu kupiti bilo gdje po cijeni od 600 rublja.

Odbacivanje svih vrsta hardvera ili ugrađenih čipseta/BIOS RAID-ova napravljeno je namjerno, kako bi se u potpunosti mogao zamijeniti cijeli sistem, izuzev samih SSD/HDD-a, uz zadržavanje svih podataka. Idealno, tako da možete sačuvati čak i instalirani operativni sistem kada pređete na potpuno novi/drugačiji hardver. Glavna stvar je da postoje SATA i PCIe portovi. To je kao live CD ili fleš disk za pokretanje, samo veoma brz i malo glomazan.

HumorInače, znate šta se dešava - ponekad morate hitno poneti ceo niz sa sobom da ga odnesete. Ali ne želim da izgubim 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 keširanja u Linuxu.

Hardverske racije su dosadne. Uključite ga. Ili radi ili ne. A sa mdadm-om uvijek postoje opcije.

Softver

Ranije je Debian 8 Jessie bio instaliran na hardveru, koji je blizu EOL-a. RAID 6 je sastavljen od gore navedenih HDD-ova uparenih sa LVM-om. Pokrenuo je virtuelne mašine u kvm/libvirt.

Jer Autor ima odgovarajuće iskustvo u kreiranju prenosivih SATA/NVMe fleš diskova za pokretanje sistema, a takođe, da se ne bi narušio uobičajeni apt šablon, kao ciljni sistem je izabran Ubuntu 18.04, koji je već dovoljno stabilizovan, ali ima još 3 godine rada. podrška u budućnosti.

Pomenuti sistem sadrži sve hardverske drajvere koji su nam potrebni iz kutije. Ne trebamo softver ili drajvere treće strane.

Priprema za instalaciju

Za instalaciju sistema potrebna nam je Ubuntu slika radne površine. Serverski sistem ima neku vrstu snažnog instalatera, koji pokazuje preteranu nezavisnost koja se ne može onemogućiti guranjem UEFI sistemske particije na jedan od diskova, kvareći svu lepotu. Shodno tome, instaliran je samo u UEFI modu. Ne nudi nikakve opcije.

Nismo zadovoljni sa ovim.

Zašto?Nažalost, UEFI boot je izuzetno loše kompatibilan sa RAID softverom za pokretanje, jer... Niko nam ne nudi rezervacije za UEFI ESP particiju. Na mreži postoje recepti koji predlažu postavljanje ESP particije na fleš disk u USB port, ali ovo je tačka neuspjeha. Postoje recepti koji koriste softver mdadm RAID 1 sa metapodacima verzije 0.9 koji ne sprečavaju UEFI BIOS da vidi ovu particiju, ali to živi do srećnog trenutka kada BIOS ili neki drugi hardverski OS zapiše nešto u ESP i zaboravi da ga sinhronizuje sa drugim ogledala.

Osim toga, UEFI boot zavisi od NVRAM-a, koji se neće pomeriti zajedno sa diskovima na novi sistem, jer je dio matične ploče.

Dakle, nećemo izmisliti novi točak. Već imamo gotov, vremenski testiran dedin bicikl, koji se sada zove Legacy/BIOS boot, koji nosi ponosno ime CSM na UEFI kompatibilnim sistemima. Samo ćemo ga skinuti sa police, podmazati, napumpati gume i obrisati vlažnom krpom.

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

I tako, prikupljamo hardver i učitavamo sistem sa Ubuntu Live fleš diska za pokretanje. Trebat ćemo preuzeti pakete, tako da ćemo postaviti mrežu koja radi za vas. Ako ne uspije, možete unaprijed učitati potrebne pakete na fleš disk.

Ulazimo u Desktop okruženje, pokrećemo emulator terminala i krećemo:

#sudo bash

Kako…?Gornja linija je kanonski okidač za holivare o sudou. C bоdolaze veće prilike iоveća odgovornost. Pitanje je da li to možete preuzeti na sebe. Mnogi ljudi misle da korištenje sudoa na ovaj način barem nije oprezno. Kako god:

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

Zašto ne ZFS...?Kada instaliramo softver na naš računar, mi u suštini posuđujemo svoj hardver programerima ovog softvera za vožnju.
Kada ovom softveru povjerimo sigurnost naših podataka, uzimamo kredit jednak trošku vraćanja ovih podataka, koji ćemo jednog dana morati otplatiti.

Sa ove tačke gledišta, ZFS je Ferrari, a mdadm+lvm je više kao bicikl.

Subjektivno, autor više voli da pozajmi bicikl na kredit nepoznatim osobama umjesto Ferrarija. Tamo cijena izdanja nije visoka. Nema potrebe za pravima. Jednostavnije od saobraćajnih pravila. Parking je besplatan. Sposobnost trčanja je bolja. Uvijek možete pričvrstiti noge na bicikl, a bicikl možete popraviti vlastitim rukama.

Zašto onda BTRFS...?Da bismo pokrenuli operativni sistem, potreban nam je sistem datoteka koji je podržan u Legacy/BIOS GRUB-u iz kutije, a istovremeno podržava i live snapshotove. Koristić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 kreirati zasebne particije na LVM-u i montirati ih u potrebne direktorije.

Nećemo čuvati nikakve slike virtuelnih mašina ili baza podataka na ovom FS.
Ovaj FS će se koristiti samo za kreiranje snimaka sistema bez isključivanja, a zatim prenijeti ove snimke na disk rezervne kopije pomoću slanja/primanja.

Osim toga, autor općenito preferira da zadrži minimum softvera direktno na hardveru i pokrene sav drugi softver na virtuelnim mašinama koristeći stvari poput prosljeđivanja GPU-a i PCI-USB Host kontrolera na KVM preko IOMMU-a.

Jedine stvari koje su ostale na hardveru su pohrana podataka, virtualizacija i sigurnosna kopija.

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

Međutim, autor namjerno zanemaruje ugrađene funkcije preslikavanja/RAID-a i redundantnosti koje ZFS, BRTFS i LVM imaju.

Kao dodatni argument, BTRFS ima mogućnost da nasumično upisivanje pretvori u sekvencijalno, što ima izuzetno pozitivan učinak na brzinu sinhronizacije snimaka/sigurnosnih kopija na HDD-u.

Ponovo 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

Raspored diska

NVMe SSD-ovi

Ali nećemo ih ni na koji način obilježavati. Svejedno, naš BIOS ne vidi ove diskove. Dakle, oni će u potpunosti preći na softverski RAID. Nećemo čak ni kreirati sekcije tamo. Ako želite slijediti "kanon" ili "principijelno", napravite jednu veliku particiju, poput HDD-a.

SATA HDD

Nema potrebe izmišljati ništa posebno. Napravićemo jednu sekciju za sve. Napravićemo particiju jer BIOS vidi ove diskove i čak može pokušati da se pokrene sa njih. Čak ćemo kasnije instalirati i GRUB na ove diskove kako bi sistem to odjednom 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 nam stvari postaju zanimljive.

Prvo, naši diskovi su veličine 2 TB. Ovo je unutar prihvatljivog raspona za MBR, što ćemo koristiti. Ako je potrebno, može se zamijeniti GPT-om. GPT diskovi imaju sloj kompatibilnosti koji omogućava MBR-kompatibilnim sistemima da vide prve 4 particije ako se nalaze unutar prva 2 terabajta. Glavna stvar je da particija za pokretanje i particija bios_grub na ovim diskovima budu na početku. Ovo vam čak omogućava da pokrenete sistem sa GPT Legacy/BIOS disk jedinica.

Ali ovo nije naš slučaj.

Ovdje ćemo kreirati 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 male nedodijeljene površine na kraju diska.

Šta je ovo neobeleženo područje?Prema izvorima na mreži, naši SATA SSD-ovi imaju dinamički proširivu SLC keš memoriju veličine od 6 do 78 gigabajta. Dobijamo 6 gigabajta “besplatno” zbog razlike između “gigabajta” i “gibibajta” u tablici podataka diska. Preostala 72 gigabajta su dodijeljena iz neiskorištenog prostora.

Ovdje treba napomenuti da imamo SLC keš memoriju, a prostor je zauzet u 4-bitnom MLC modu. Što za nas efektivno znači da ćemo na svaka 4 gigabajta slobodnog prostora dobiti samo 1 gigabajt SLC keša.

Pomnožite 72 gigabajta sa 4 i dobijete 288 gigabajta. Ovo je slobodan prostor koji nećemo označavati kako bismo omogućili pogonima da u potpunosti iskoriste SLC keš memoriju.

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

Ova količina keš memorije će nam omogućiti da izuzetno rijetko u stvarnom životu naiđemo na situaciju da zapis ne ide u keš memoriju. Ovo izuzetno dobro kompenzuje najtužniji nedostatak QLC memorije - izuzetno nisku brzinu pisanja kada se podaci upisuju zaobilazeći keš memoriju. Ako vaša opterećenja ne odgovaraju ovome, preporučujem vam da dobro razmislite koliko dugo će vaš SSD izdržati pod takvim opterećenjem, uzimajući u obzir TBW iz podatkovnog lista.

#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

Kreiranje nizova

Prvo, moramo preimenovati mašinu. Ovo je neophodno jer je ime hosta dio imena niza negdje unutar mdadm-a i negdje utječe na nešto. Naravno, nizovi se mogu kasnije preimenovati, ali ovo je nepotreban korak.

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

NVMe SSD-ovi

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

Zašto -pretpostaviti-čistiti...?Da biste izbjegli inicijaliziranje nizova. Za oba nivoa RAID 1 i 6 ovo vrijedi. Sve može raditi bez inicijalizacije ako je novi niz. Štaviše, inicijalizacija SSD niza nakon kreiranja je gubitak TBW resursa. Koristimo TRIM/DISCARD gdje je to moguće na sastavljenim SSD nizovima da bismo ih „inicijalizirali“.

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

Za SSD RAID 6 DISCARD nizove, morate ga omogućiti u parametrima modula kernela.

Ovo treba uraditi samo ako svi SSD-ovi koji se koriste u nizovima nivoa 4/5/6 u ovom sistemu imaju radnu podršku za discard_zeroes_data. Ponekad naiđete na čudne pogone koji govore kernelu da je ova funkcija podržana, ali u stvari je nema ili funkcija ne radi uvijek. Trenutno je podrška dostupna gotovo svuda, međutim, postoje stari diskovi i firmver s greškama. Iz tog razloga, DISCARD podrška je onemogućena po defaultu za RAID 6.

Pažnja, sljedeća naredba će uništiti sve podatke na NVMe drajvovima „inicijalizacijom“ niza „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 veliki...?Povećanje veličine komada ima pozitivan učinak na brzinu nasumično čitanja u blokovima do uključujući veličinu komada. To se događa zato što se jedna operacija odgovarajuće veličine ili manje može u potpunosti izvršiti na jednom uređaju. Dakle, IOPS sa svih uređaja se sumira. Prema statistikama, 99% IO ne prelazi 512K.

RAID 6 IOPS po zapisu uvek manji ili jednak IOPS-u jednog diska. Kada, kao nasumično čitanje, IOPS može biti nekoliko puta veći od onog na jednom disku, i tu je veličina bloka od ključnog značaja.
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.
Nadoknadit ćemo loše nasumično upisivanje RAID-a 6 sa NVMe keš memorijom i trikovima tankog obezbjeđivanja.

Još nismo omogućili DISCARD za RAID 6. Tako da za sada nećemo "inicijalizirati" ovaj niz. To ćemo uraditi 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 da postavimo root fajl sistem na NVMe RAID 1 koji je /dev/md0.
Međutim, i dalje će nam trebati ovaj brzi niz za druge potrebe, kao što su swap, metapodaci i LVM-keš i LVM-tanki metapodaci, tako da ćemo kreirati LVM VG na ovom nizu.

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

Kreirajmo particiju za korijenski sistem datoteka.

#lvcreate -L 128G --name root root

Kreirajmo particiju za zamjenu prema veličini RAM-a.

#lvcreate -L 32G --name swap root

instalacija OS-a

Ukupno imamo sve što je potrebno za instalaciju sistema.

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

  • /dev/md1, - tačka montiranja /boot, FS - BTRFS
  • /dev/root/root (aka /dev/mapper/root-root), - tač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 osnovni sistem datoteka, instalater će automatski kreirati dva BTRFS volumena pod nazivom "@" za / (root) i "@home" za /home.

Krenimo sa instalacijom...

Instalacija će se završiti modalnim dijaloškim okvirom koji ukazuje na grešku u instalaciji bootloadera. Nažalost, nećete moći izaći iz ovog dijaloga standardnim sredstvima i nastaviti instalaciju. Odjavljujemo se sa sistema i ponovo se prijavljujemo, završavajući na čistom Ubuntu Live desktopu. Otvorite terminal i ponovo:

#sudo bash

Kreirajte 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 ime 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 dostavljamo 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 pogrešno instalirani zbog nepotpune instalacije sistema:

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

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

Podesite parametre za RAID 6 modul da omogućimo TRIM/DISCARD:

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

Hajde da malo podesimo 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

Šta je bilo..?Napravili smo skup udev pravila koja će raditi sljedeće:

  • Podesite veličinu keš memorije bloka za RAID 2020 da bude adekvatna za 6. Podrazumevana vrednost, čini se, nije se promenila od stvaranja Linuxa i nije bila adekvatna već duže vreme.
  • Rezervirajte minimalno IO za vrijeme trajanja provjera/sinhronizacija niza. Ovo je da spriječite da se vaši nizovi zaglave u stanju vječne sinhronizacije pod opterećenjem.
  • Ograničite maksimalni IO tokom provjera/sinhronizacije nizova. Ovo je neophodno kako sinhronizacija/provjera SSD RAID-ova ne bi spržila vaše diskove do oštrine. Ovo posebno važi za NVMe. (Sjećate se radijatora? Nisam se šalio.)
  • Zabranite diskovima da zaustave rotaciju vretena (HDD) preko APM-a i postavite vremensko ograničenje mirovanja za disk kontrolere na 7 sati. Možete potpuno onemogućiti APM ako vaši diskovi to mogu (-B 255). Sa zadanom vrijednošću, pogoni će se zaustaviti nakon pet sekundi. Tada OS želi da resetuje keš diska, diskovi će se ponovo pokrenuti i sve će početi iznova. Diskovi imaju ograničen maksimalni broj rotacija vretena. Takav jednostavan zadani ciklus može lako ubiti vaše diskove za nekoliko godina. Ne pate svi diskovi od ovoga, ali naši su “laptop” sa odgovarajućim podrazumevanim postavkama, zbog kojih RAID izgleda kao mini-MAID.
  • Instalirajte readahead na diskove (rotirajući) 1 megabajt - dva uzastopna bloka/komad RAID 6
  • Onemogućite readahead 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

Žašto je to..?Tražićemo /boot particiju prema UUID-u. Imenovanje niza bi se teoretski moglo promijeniti.

Preostale sekcije ćemo tražiti po LVM imenima u /dev/mapper/vg-lv notaciji, jer oni identifikuju particije sasvim jedinstveno.

Ne koristimo UUID za LVM jer UUID LVM volumena i njihovih snimaka mogu biti isti.Montirati /dev/mapper/root-root.. dvaput?Da. Upravo. Karakteristika BTRFS. Ovaj sistem datoteka se može montirati nekoliko puta sa različitim subvolovima.

Zbog ove iste funkcije, preporučujem da nikada ne kreirate LVM snimke aktivnih BTRFS volumena. Možete dobiti iznenađenje kada ponovo pokrenete sistem.

Regenerirajmo mdadm konfiguraciju:

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

Podesite 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

Šta je bilo..?Omogućili smo automatsko proširenje LVM tankih bazena po dostizanju 90% zauzetog prostora za 5% zapremine.

Povećali smo maksimalan broj keš blokova za LVM keš.

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

  • uređaji koji sadrže LVM keš memoriju (cdata)
  • uređaji keširani koristeći LVM keš, zaobilazeći keš ( _corig). U ovom slučaju, sam keširani uređaj će i dalje biti skeniran kroz keš memoriju (samo ).
  • uređaji koji sadrže LVM keš metapodatke (cmeta)
  • svi uređaji u VG sa imenom slike. Ovdje ćemo imati slike diskova virtuelnih mašina i ne želimo da LVM na hostu aktivira volumene koji pripadaju gostujućem OS-u.
  • svi uređaji u VG sa rezervnom kopijom imena. Ovdje ćemo imati rezervne kopije slika virtuelne mašine.
  • svi uređaji čiji naziv završava sa "gpv" (fizički volumen za goste)

Omogućili smo DISCARD podršku prilikom oslobađanja slobodnog prostora na LVM VG. Budi pazljiv. Ovo će učiniti brisanje LV-ova na SSD-u prilično dugotrajnim. To se posebno odnosi na SSD RAID 6. Međutim, po planu ćemo koristiti tanku proviziju, tako da nas to nimalo neće 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*. Sistem mora biti u mogućnosti da se pokrene sa bilo kojeg SATA diska ili SSD-a koji radi.

Zašto su dodali os-prober..?Za preteranu nezavisnost i razigrane ruke.

Ne radi ispravno ako je jedan od RAID-ova u degradiranom stanju. Pokušava da traži OS na particijama koje se koriste u virtuelnim mašinama koje rade na ovom hardveru.

Ako vam zatreba, možete ga ostaviti, ali imajte na umu sve gore navedeno. Preporučujem da potražite recepte za rješavanje nestašnih ruku na internetu.

Ovim smo završili početnu instalaciju. Vrijeme je da se ponovo pokrenete na novoinstalirani OS. Ne zaboravite da uklonite Live CD/USB za pokretanje.

#exit
#reboot

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

LVM na SATA SSD-u

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

#sudo bash

Hajde da nastavimo.

“Inicijalizirajte” niz sa SATA SSD-a:

#blkdiscard /dev/md2

Ako ne uspije, pokušajte:

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

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

Zašto još jedan VG..?U stvari, već imamo VG pod nazivom root. Zašto ne biste sve dodali u jedan VG?

Ako postoji nekoliko PV-a u VG-u, tada da bi VG bio ispravno aktiviran, svi PV-ovi moraju biti prisutni (online). Izuzetak je LVM RAID, koji namjerno ne koristimo.

Zaista želimo da ako dođe do kvara (gubitak podataka za čitanje) na bilo kojem od RAID 6 nizova, operativni sistem će se normalno pokrenuti i dati nam priliku da riješimo problem.

Da bismo to učinili, na prvom nivou apstrakcije izolovaćemo svaku vrstu fizičkog „medija” u poseban VG.

Naučno govoreći, različiti RAID nizovi pripadaju različitim „domenima pouzdanosti“. Ne biste trebali stvarati dodatnu zajedničku tačku neuspjeha za njih tako što ćete ih trpati u jedan VG.

Prisustvo LVM-a na "hardverskom" nivou omogućiće nam da proizvoljno isečemo delove različitih RAID nizova kombinujući ih na različite načine. Na primjer - trči u isto vreme bcache + LVM tanki, bcache + BTRFS, LVM cache + LVM tanki, složena ZFS konfiguracija sa kešovima, ili bilo koja druga paklena mješavina da pokušate sve to uporediti.

Na "hardverskom" nivou, nećemo koristiti ništa osim dobrih starih "debelih" LVM volumena. Izuzetak od ovog pravila može biti rezervna particija.

Mislim da su do ovog trenutka mnogi čitaoci već počeli da sumnjaju u nešto u vezi sa lutkom za gnezda.

LVM na SATA HDD

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

Opet novi VG..?Zaista želimo da ako diskovni niz koji ćemo koristiti za sigurnosnu kopiju podataka ne uspije, naš operativni sistem nastavi da radi normalno, uz održavanje pristupa podacima bez rezervne kopije kao i obično. Stoga, da bismo izbjegli probleme s aktivacijom VG-a, kreiramo poseban VG.

Postavljanje LVM keša

Kreirajmo LV na NVMe RAID 1 da bismo ga koristili kao uređaj za keširanje.

#lvcreate -L 70871154688B --name cache root

Zašto je tako malo...?Činjenica je da naši NVMe SSD-ovi također imaju SLC keš memoriju. 4 gigabajta "slobodnog" i 18 gigabajta dinamičkog zbog slobodnog prostora koji zauzima 3-bitni MLC. Kada se ova keš memorija iscrpi, NVMe SSD-ovi neće biti mnogo brži od našeg SATA SSD-a sa kešom. Zapravo, iz tog razloga, nema smisla da LVM keš particiju napravimo mnogo većom od dvostruke veličine SLC keša NVMe diska. Za korišćene NVMe diskove, autor smatra razumnim napraviti 32-64 gigabajta keš memorije.

Data veličina particije je potrebna za organiziranje 64 gigabajta keša, metapodataka keša i sigurnosne kopije metapodataka.

Dodatno, napominjem da će nakon gašenja prljavog sistema, LVM označiti cijelu keš memoriju kao prljavu i ponovo će se sinhronizirati. Štaviše, ovo će se ponavljati svaki put kada se lvchange koristi na ovom uređaju dok se sistem ponovo ne pokrene. Stoga preporučujem da odmah ponovo kreirate keš koristeći odgovarajuću skriptu.

Kreirajmo LV na SATA RAID 6 da bismo ga koristili kao keširani uređaj.

#lvcreate -L 3298543271936B --name cache data

Zašto samo tri terabajta?Tako da, ako je potrebno, možete koristiti SATA SSD RAID 6 za neke druge potrebe. Veličina keširanog prostora može se povećavati dinamički, u hodu, bez zaustavljanja sistema. Da biste to učinili, morate privremeno zaustaviti i ponovo omogućiti keš memoriju, ali karakteristična prednost LVM-cache-a nad, na primjer, bcache-om je ta što se to može učiniti u hodu.

Kreirajmo novi VG za keširanje.

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

Kreirajmo LV na keširanom 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 kreirane odmah na /dev/root/cache. Ako ste kreirali nešto na pogrešnom mjestu, možete ga premjestiti pomoću pvmove.

Kreirajmo i omogućimo keš memoriju:

#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 eksperimente, autor je uspio otkriti da se najbolji rezultat postiže ako se veličina LVM keš bloka poklapa s veličinom LVM tankog bloka. Štoviše, što je manja veličina, to je bolja izvedba konfiguracije u nasumičnom snimanju.

64k je minimalna dozvoljena veličina bloka za LVM tanki.

Budite oprezni pri pisanju..!Da. Ova vrsta keš memorije odgađa sinhronizaciju pisanja na keširani uređaj. To znači da ako se keš memorija izgubi, možete izgubiti podatke na keširanom uređaju. Kasnije će vam autor reći koje mjere, pored NVMe RAID 1, mogu biti poduzete da se nadoknadi ovaj rizik.

Ovaj tip keš memorije odabran je namjerno kako bi se kompenzirale loše performanse nasumičnog pisanja RAID-a 6.

Hajde da proverimo šta imamo:

#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] treba da se nalazi na /dev/data/cache. Ako nešto nije u redu, koristite pvmove.

Možete onemogućiti keš memoriju ako je potrebno jednom naredbom:

#lvconvert -y --uncache cache/cachedata

Ovo se radi on-line. LVM će jednostavno sinkronizirati keš sa diskom, ukloniti ga i preimenovati cachedata_corig natrag u cachedata.

Postavljanje LVM tanke

Procijenimo otprilike koliko nam je prostora potrebno 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 sa 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 rezervnu kopiju:

#lvcreate -L 8594128896B --name images root

Za što..?Ovdje se može postaviti pitanje: zašto postavljati LVM tanke metapodatke odvojeno ako će oni i dalje biti keširani na NVMe i brzo će raditi.

Iako je brzina ovdje bitna, to je daleko od glavnog razloga. Stvar je u tome što je keš tačka kvara. Nešto bi mu se moglo dogoditi, a ako se LVM tanki metapodaci keširaju, to će uzrokovati da se sve potpuno izgubi. Bez kompletnih metapodataka, biće gotovo nemoguće sastaviti tanke tomove.

Premještanjem metapodataka u zaseban ne-keširani, ali brzi volumen, garantujemo sigurnost metapodataka u slučaju gubitka ili oštećenja keš memorije. U ovom slučaju, sva oštećenja uzrokovana gubitkom keš memorije bit će lokalizirana unutar tankih volumena, što će pojednostaviti proceduru oporavka za redove veličine. Uz veliku vjerovatnoću, ova oštećenja će biti nadoknađena korištenjem FS dnevnika.

Štaviše, ako je prethodno napravljen snimak tankog volumena, a nakon toga je keš u potpunosti sinhronizovan barem jednom, tada će, zbog internog dizajna LVM tanke, integritet snimka biti zagarantovan u slučaju gubitka predmemorije .

Kreirajmo novi VG koji će biti odgovoran za tanku proviziju:

#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 yPored onoga čemu je ovaj način zapravo namijenjen - da spriječi curenje podataka iz jedne virtuelne mašine u drugu virtuelnu mašinu prilikom preraspodele prostora - nuliranje se dodatno koristi za povećanje brzine slučajnog pisanja u blokovima manjim od 64k. Svako pisanje manje od 64k u prethodno nedodijeljeno područje tankog volumena će postati 64K poravnato po rubovima u kešu. Ovo će omogućiti da se operacija u potpunosti izvrši kroz keš memoriju, zaobilazeći keširani 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)

Napravimo tanak 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 realnom 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, od kojih svaki radi 4 sekunde. Polovina testova je za snimanje. Možete puno snimiti na NVMe za 4 sekunde. Do 3 gigabajta u sekundi. Dakle, svako pokretanje testova pisanja može pojesti do 216 gigabajta SSD resursa od vas.

Čitanje i pisanje miješano?Da. Ima smisla izvoditi testove čitanja i pisanja odvojeno. Štaviše, ima smisla osigurati da su sve keš memorije sinhronizirane tako da prethodno napravljeno upisivanje ne utječe na čitanje.

Rezultati će značajno varirati tokom prvog i narednih pokretanja kako se keš memorija i tanki volumen popunjavaju, a takođe u zavisnosti od toga da li je sistem uspeo da sinhronizuje keš memorije popunjene tokom poslednjeg pokretanja.

Između ostalog, preporučujem mjerenje brzine na već punom tankom volumenu s kojeg je upravo napravljen snimak. Autor je imao priliku da uoči kako se nasumično upisivanje naglo ubrzava odmah nakon kreiranja prvog snimka, posebno kada keš još nije potpuno pun. Ovo se dešava zbog semantike pisanja kopiraj na upisivanje, poravnanja keša i tankih blokova volumena i činjenice da se nasumično upisivanje u RAID 6 pretvara u nasumično čitanje iz RAID 6 nakon čega slijedi upis u keš memoriju. U našoj konfiguraciji, nasumično čitanje sa RAID 6 je do 6 puta (broj SATA SSD-ova u nizu) brže od pisanja. Jer blokovi za CoW se dodeljuju sekvencijalno iz tankog bazena, tada se snimanje, uglavnom, takođe pretvara u sekvencijalno.

Obje ove karakteristike možete iskoristiti u svoju korist.

Keširajte "koherentne" snimke

Kako bi se smanjio rizik od gubitka podataka u slučaju oštećenja/gubitka keša, autor predlaže uvođenje prakse rotiranja snimaka kako bi se u ovom slučaju garantirao njihov integritet.

Prvo, budući da se metapodaci tankog volumena nalaze na nekomeširanom uređaju, metapodaci će biti konzistentni i mogući gubici će biti izolirani unutar blokova podataka.

Sljedeći ciklus rotacije snimaka jamči integritet podataka unutar snimaka u slučaju gubitka predmemorije:

  1. Za svaki tanki volumen s imenom <name>, kreirajte snimak s imenom <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 kešu: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' dok ne dobijemo nulu. Ako nula nedostaje predugo, može se stvoriti privremenim prebacivanjem keš memorije u način rada za pisanje. Međutim, uzimajući u obzir karakteristike brzine naših SATA i NVMe SSD nizova, kao i njihov TBW resurs, ili ćete moći brzo uhvatiti trenutak bez promjene načina keširanja, ili će vaš hardver u potpunosti pojesti cijeli svoj resurs u nekoliko dana. Zbog ograničenja resursa, sistem u principu ne može biti pod 100% opterećenjem pisanja cijelo vrijeme. Naši NVMe SSD-ovi pod opterećenjem pisanja od 100% će u potpunosti iscrpiti resurse 3-4 dana. SATA SSD-ovi će trajati samo dvostruko duže. Stoga ćemo pretpostaviti da najveći dio opterećenja ide na čitanje, a imamo relativno kratkotrajne navale ekstremno visoke aktivnosti u kombinaciji sa malim opterećenjem u prosjeku za pisanje.
  4. Čim uhvatimo (ili napravimo) nulu, preimenujemo <name>.cached u <name>.committed. Stari <name>.committed je izbrisan.
  5. Opciono, ako je keš memorija 100% puna, može se ponovo kreirati pomoću skripte, čime se briše. Sa polupraznim kešom, sistem radi mnogo brže pri pisanju.
  6. Postavite prag migracije na nulu: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Ovo će privremeno spriječiti sinkronizaciju keša s glavnim medijem.
  7. Čekamo da se dosta promjena akumulira u kešu #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' ili će se tajmer isključiti.
  8. Ponavljamo ponovo.

Zašto poteškoće sa pragom migracije...?Stvar je u tome da u stvarnoj praksi „slučajno“ snimanje zapravo nije sasvim slučajno. Ako smo nešto upisali u sektor veličine 4 kilobajta, velika je vjerovatnoća da će u narednih nekoliko minuta biti napravljen zapis u isti ili neki od susjednih (+- 32K) sektora.

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

Gdje je kod..?Nažalost, autor sebe smatra nedovoljno kompetentnim u razvoju bash skripti jer je 100% samouk i prakticira "google"-driven razvoj, stoga smatra da strašni kod koji izlazi iz njegovih ruku niko ne bi trebao koristiti ostalo.

Mislim da će profesionalci u ovoj oblasti moći samostalno opisati svu gore opisanu logiku, ako je potrebno, i, možda, čak i lijepo dizajnirati je kao sistemsku uslugu, kao što je autor pokušao učiniti.

Ovakva jednostavna shema rotacije snimka omogućit će nam ne samo da stalno imamo potpuno sinhroniziranu sliku na SATA SSD-u, već će nam omogućiti da pomoću uslužnog programa thin_delta saznamo koji su blokovi promijenjeni nakon njegovog kreiranja i tako lokaliziramo oštećenje na glavne količine, što uvelike pojednostavljuje oporavak.

TRIM/DISCARD u libvirt/KVM

Jer skladište podataka će se koristiti za KVM koji pokreće libvirt, onda bi bilo dobro da naučimo naše VM ne samo da zauzimaju slobodan prostor, već i da oslobode ono što više nije potrebno.

Ovo se radi emulacijom TRIM/DISCARD podrške na virtuelnim diskovima. Da biste to učinili, morate promijeniti tip 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-a ispravno obrađuje LVM, a blokovi se ispravno oslobađaju i u kešu i u tankom bazenu. U našem slučaju, to se dešava uglavnom sa zakašnjenjem, prilikom brisanja sljedećeg snimka.

BTRFS Backup

Koristite gotove skripte sa ekstremno oprez i na vlastitu odgovornost. 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 da kopirate tuđe.

Kreirajmo volumen na backup uređaju:

#lvcreate -L 256G --name backup backup

Formatirajmo ga u BTRFS:

#mkfs.btrfs /dev/backup/backup

Kreirajmo tačke montiranja i montirajmo korijenske podsekcije sistema datoteka:

#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 backup skripte:

#mkdir /root/btrfs-backup

Kopirajmo skriptu:

Mnogo strašnog bash koda. Koristite na vlastitu odgovornost. Nemojte pisati ljuta 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

Šta uopšte radi...?Sadrži skup jednostavnih naredbi za kreiranje BTRFS snimaka i njihovo kopiranje na drugi FS koristeći BTRFS slanje/primanje.

Prvo lansiranje može biti relativno dugo, jer... Na početku će svi podaci biti kopirani. Dalja lansiranja će biti veoma brza, jer... Samo promjene će biti kopirane.

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

Šta radi...?Kreira i sinhronizuje inkrementalne snimke navedenih BTRFS volumena na sigurnosnom FS-u. Nakon ovoga briše sve slike kreirane prije 60 dana. Nakon pokretanja, datirani snimci navedenih volumena će se pojaviti u poddirektorijumima /backup/btrfs/back/remote/.

Dajemo prava na izvršavanje koda:

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

Hajde da ga proverimo 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 tanak bazen na backup uređaju:

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

Hajde da instaliramo ddrescue, jer... skripte će koristiti ovaj alat:

#apt-get install gddrescue

Kreirajmo direktorij za skripte:

#mkdir /root/lvm-thin-backup

Kopirajmo skripte:

Puno sranja 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

Šta radi...?Sadrži skup naredbi za manipulaciju tankim snimcima i sinkronizaciju razlike između dva tanka snimka primljena putem tanke_delta na drugi blok uređaj koristeći ddrescue i blkdiscard.

Još jedna skripta koju ćemo staviti u cron:

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

Šta radi...?Koristi prethodnu skriptu za kreiranje i sinhronizaciju rezervnih kopija navedenih tankih volumena. Skripta će ostaviti neaktivne snimke navedenih volumena, koji su potrebni za praćenje promjena od posljednje sinhronizacije.

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

Dajemo prava:

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

Hajde da ga proverimo 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 biti dugo, jer... tanki volumeni će biti u potpunosti sinhronizirani kopiranjem cijelog iskorištenog prostora. Zahvaljujući LVM tankim metapodacima, znamo koji su blokovi zapravo u upotrebi, tako da će se kopirati samo stvarno korišteni blokovi tankog volumena.

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

Da vidimo šta se desilo:

#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 sa lutkama?

Najvjerovatnije, s obzirom da LVM LV logički volumeni mogu biti LVM PV fizički volumeni za druge VG. LVM može biti rekurzivan, kao lutke za gniježđenje. Ovo daje LVM-u izuzetnu fleksibilnost.

PS

U sljedećem članku pokušat ćemo koristiti nekoliko sličnih mobilnih sustava za pohranu/KVM kao osnovu za kreiranje geo-distribuiranog skladišta/vm klastera sa redundansom na nekoliko kontinenata koristeći kućne desktope, kućni internet i P2P mreže.

izvor: www.habr.com

Dodajte komentar