Kas bendro tarp LVM ir Matryoshka?

Laba diena.
Norėčiau pasidalinti su bendruomene savo praktine patirtimi kuriant duomenų saugojimo sistemą KVM naudojant md RAID + LVM.

Į programą bus įtraukta:

  • Md RAID 1 kūrimas iš NVMe SSD.
  • Md RAID 6 surinkimas iš SATA SSD ir įprastų diskų.
  • TRIM/DISCARD veikimo ypatybės SSD RAID 1/6.
  • Įkraunamo md RAID 1/6 masyvo sukūrimas bendrame diskų rinkinyje.
  • Sistemos diegimas NVMe RAID 1, kai BIOS nepalaiko NVMe.
  • Naudojant LVM talpyklą ir LVM ploną.
  • Naudojant BTRFS momentines nuotraukas ir siųsti / gauti atsarginę kopiją.
  • LVM plonų momentinių nuotraukų ir plonų_delta naudojimas BTRFS stiliaus atsarginėms kopijoms kurti.

Jei susidomėjote, žiūrėkite katę.

Pareiškimas

Autorius neprisiima jokios atsakomybės už šio straipsnio medžiagos/pavyzdžių/kodo/patarimų/duomenų naudojimo ar nenaudojimo pasekmes. Bet kokiu būdu skaitydami ar naudodami šią medžiagą prisiimate atsakomybę už visas šių veiksmų pasekmes. Galimos pasekmės:

  • Traškiai kepti NVMe SSD diskai.
  • Visiškai išnaudoti įrašymo ištekliai ir SSD diskų gedimai.
  • Visiškas visų duomenų praradimas visuose diskuose, įskaitant atsargines kopijas.
  • Sugedusi kompiuterio aparatinė įranga.
  • Sugaištas laikas, nervai ir pinigai.
  • Bet kokios kitos pasekmės, kurios nėra išvardytos aukščiau.

geležies

Galimi buvo:

Pagrindinė plokštė maždaug 2013 m. su Z87 mikroschemų rinkiniu, su Intel Core i7 / Haswell.

  • Procesorius 4 branduoliai, 8 gijos
  • 32 GB DDR3 RAM
  • 1 x 16 arba 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 jungtys

SAS adapteris LSI SAS9211-8I persijungė į IT / HBA režimą. RAID įgalinta programinė įranga buvo sąmoningai pakeista HBA programine įranga, kad:

  1. Galite bet kada išmesti šį adapterį ir pakeisti jį bet kuriuo kitu, su kuriuo susidūrėte.
  2. TRIM/Discard diskuose veikė normaliai, nes... RAID programinėje įrangoje šios komandos visiškai nepalaikomos, o HBA apskritai nerūpi, kokios komandos perduodamos magistrale.

Kietieji diskai - 8 vienetai HGST Travelstar 7K1000 su 1 TB talpa 2.5 formato koeficientu, kaip nešiojamiesiems kompiuteriams. Šie diskai anksčiau buvo RAID 6 masyve. Jie taip pat bus naudojami naujoje sistemoje. Vietinėms atsarginėms kopijoms saugoti.

Papildomai pridėta:

6 vnt SATA SSD modelis Samsung 860 QVO 2TB. Šiems SSD diskams reikėjo didelės apimties, SLC talpyklos buvimo, patikimumo ir mažos kainos. Reikalingas atmetimo/nulio palaikymas, kuris patikrinamas dmesg eilutėje:

kernel: ata1.00: Enabling discard_zeroes_data

2 vnt. NVMe SSD modelio Samsung SSD 970 EVO 500GB.

Šiems SSD diskams svarbu atsitiktinis skaitymo / rašymo greitis ir išteklių talpa, atitinkanti jūsų poreikius. Radiatorius jiems. Būtinai. absoliučiai. Kitu atveju kepkite juos, kol jie taps traškūs, pirmą kartą sinchronizuodami RAID.

StarTech PEX8M2E2 adapteris, skirtas 2 x NVMe SSD, įdiegtas PCIe 3.0 8x lizde. Tai vėlgi yra tik HBA, bet skirta NVMe. Nuo pigių adapterių jis skiriasi tuo, kad nereikalauja PCIe bifurkacijos palaikymo iš pagrindinės plokštės, nes yra įmontuotas PCIe jungiklis. Jis veiks net pačioje seniausioje sistemoje su PCIe, net jei tai yra x1 PCIe 1.0 lizdas. Natūralu, kad reikiamu greičiu. RAID ten nėra. Laive nėra įmontuoto BIOS. Taigi, šio įrenginio dėka jūsų sistema stebuklingai neišmoks paleisti NVMe, o tuo labiau – NVMe RAID.

Šis komponentas atsirado tik dėl to, kad sistemoje buvo tik vienas nemokamas 8x PCIe 3.0, o jei yra 2 laisvi lizdai, jį galima lengvai pakeisti dviem centais PEX4M2E1 arba analogais, kuriuos galima nusipirkti bet kur už 600 rublių.

Visų rūšių aparatinės įrangos ar įmontuotų mikroschemų rinkinių/BIOS RAID atmetimas buvo padarytas sąmoningai, kad būtų galima visiškai pakeisti visą sistemą, išskyrus pačius SSD/HDD, išsaugant visus duomenis. Idealiu atveju, kad pereinant prie visiškai naujos/kitokios techninės įrangos galėtumėte išsaugoti net įdiegtą operacinę sistemą. Svarbiausia, kad yra SATA ir PCIe prievadai. Tai tarsi tiesioginis kompaktinis diskas arba paleidžiama „flash drive“, tik labai greita ir šiek tiek didelė.

ЮморKitu atveju žinote, kas atsitiks – kartais reikia skubiai pasiimti visą masyvą, kad išsineštumėte. Bet aš nenoriu prarasti duomenų. Norėdami tai padaryti, visos minėtos laikmenos patogiai išdėstytos ant stiklelių, esančių standartinio korpuso 5.25 skyriuose.

Na, ir, žinoma, eksperimentuoti su skirtingais SSD talpyklos kaupimo metodais Linux sistemoje.

Aparatinės įrangos reidai yra nuobodūs. Įjunkite jį. Tai arba veikia, arba ne. O su mdadm visada yra variantų.

Programinė įranga

Anksčiau Debian 8 Jessie buvo įdiegta aparatinėje įrangoje, kuri yra artima EOL. RAID 6 buvo surinktas iš aukščiau paminėtų HDD, suporuotų su LVM. Jis paleido virtualias mašinas kvm/libvirt.

Nes Autorius turi tinkamos patirties kuriant nešiojamus įkraunamus SATA/NVMe „flash drives“, o taip pat, kad nebūtų pažeistas įprastas apt šablonas, tiksline sistema buvo pasirinkta „Ubuntu 18.04“, kuri jau pakankamai stabilizuota, tačiau dar turi 3 metus. paramą ateityje.

Minėtoje sistemoje yra visos mums reikalingos aparatinės įrangos tvarkyklės. Mums nereikia jokios trečiosios šalies programinės įrangos ar tvarkyklių.

Pasiruošimas montavimui

Norėdami įdiegti sistemą, mums reikia Ubuntu Desktop Image. Serverio sistema turi tam tikrą energingą diegimo programą, kuri rodo pernelyg didelę nepriklausomybę, kurios negalima išjungti įkišus UEFI sistemos skaidinį į vieną iš diskų, taip sugadindamas visą grožį. Atitinkamai, jis įdiegtas tik UEFI režimu. Nesiūlo jokių variantų.

Mes tuo nesame patenkinti.

Kodėl?Deja, UEFI įkrova itin prastai suderinama su įkrovos programinės įrangos RAID, nes... Niekas mums nesiūlo rezervacijų dėl UEFI ESP skaidinio. Internete yra receptų, kuriuose siūloma ESP skaidinį įdėti į USB prievadą esančią „flash drive“, tačiau tai yra nesėkmės taškas. Yra receptų naudojant programinę įrangą mdadm RAID 1 su metaduomenų versija 0.9, kurie netrukdo UEFI BIOS matyti šį skaidinį, tačiau tai gyvuoja iki laimingo momento, kai BIOS ar kita aparatinė OS ką nors įrašo į ESP ir pamiršta sinchronizuoti su kitu veidrodžiai.

Be to, UEFI įkrova priklauso nuo NVRAM, kuri kartu su diskais neperkels į naują sistemą, nes yra pagrindinės plokštės dalis.

Taigi, mes neišrasime naujo rato. Jau turime paruoštą, laiko patikrintą senelio dviratį, dabar vadinamą Legacy/BIOS bagažine, turintį didžiulį CSM pavadinimą su UEFI suderinamose sistemose. Tiesiog nuimsime nuo lentynos, sutepsime, pripumpuosime padangas ir nušluostysime drėgna šluoste.

Desktop Ubuntu versija taip pat negali būti tinkamai įdiegta naudojant Legacy bootloader, bet čia, kaip sakoma, bent jau yra galimybių.

Taigi, mes surenkame aparatinę įrangą ir įkeliame sistemą iš „Ubuntu Live“ įkrovos „flash drive“. Turėsime atsisiųsti paketus, todėl nustatysime jums tinkantį tinklą. Jei tai neveikia, galite iš anksto įkelti reikiamus paketus į "flash drive".

Einame į darbalaukio aplinką, paleidžiame terminalo emuliatorių ir einame:

#sudo bash

Kaip…?Aukščiau pateikta eilutė yra kanoninis holiwars apie sudo paleidiklis. C bоateina didesnės galimybės irоdidesnę atsakomybę. Kyla klausimas, ar galite tai priimti patys. Daugelis žmonių mano, kad naudojant sudo tokiu būdu bent jau nėra atsargumo. Tačiau:

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

Kodėl ne ZFS...Kai įdiegiame programinę įrangą savo kompiuteryje, mes iš esmės skoliname savo aparatinę įrangą šios programinės įrangos kūrėjams, kad jie galėtų vairuoti.
Kai patikime šiai programinei įrangai savo duomenų saugumą, imame paskolą, lygią šių duomenų atkūrimo išlaidoms, kurią kada nors turėsime sumokėti.

Šiuo požiūriu ZFS yra Ferrari, o mdadm+lvm labiau primena dviratį.

Subjektyviai autorius mieliau ne Ferrari, o dviratį skolina nepažįstamiems asmenims. Ten emisijos kaina nėra didelė. Nereikia teisių. Paprastesnis nei kelių eismo taisyklės. Automobilių stovėjimo aikštelė nemokama. Gebėjimas įveikti visas šalis yra geresnis. Prie dviračio visada galite pritvirtinti kojas, o dviratį suremontuoti galite savo rankomis.

Kodėl tada BTRFS...?Norint paleisti operacinę sistemą, mums reikia failų sistemos, kuri būtų palaikoma Legacy/BIOS GRUB ir tuo pat metu palaiko tiesiogines momentines nuotraukas. Mes naudosime jį /boot skaidiniui. Be to, autorius nori naudoti šį FS for / (root), nepamirštant pažymėti, kad bet kuriai kitai programinei įrangai galite sukurti atskirus LVM skaidinius ir prijungti juos reikiamuose kataloguose.

Šioje FS nesaugosime jokių virtualių mašinų ar duomenų bazių vaizdų.
Šis FS bus naudojamas tik sistemos momentinėms nuotraukoms kurti jos neišjungiant, o tada šias momentines nuotraukas perkelti į atsarginį diską naudojant siuntimo/gauti.

Be to, autorius paprastai renkasi minimalų programinės įrangos kiekį tiesiogiai aparatinėje įrangoje ir visą kitą programinę įrangą paleisti virtualiose mašinose naudodamas tokius dalykus kaip GPU ir PCI-USB pagrindinio kompiuterio valdiklių persiuntimas į KVM per IOMMU.

Aparatinėje įrangoje liko tik duomenų saugojimas, virtualizavimas ir atsarginė kopija.

Jei labiau pasitikite ZFS, tada iš esmės nurodytai programai jie yra keičiami.

Tačiau autorius sąmoningai ignoruoja ZFS, BRTFS ir LVM integruotas veidrodinio atspindėjimo / RAID ir atleidimo funkcijas.

Kaip papildomas argumentas BTRFS turi galimybę atsitiktinius įrašus paversti nuosekliais, o tai itin teigiamai veikia momentinių nuotraukų/atsarginių kopijų HDD sinchronizavimo greitį.

Iš naujo nuskaitykime visus įrenginius:

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

Pasižvalgykime aplinkui:

#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

Disko išdėstymas

„NVMe“ SSD

Bet mes jų jokiu būdu nežymėsime. Vis dėlto mūsų BIOS nemato šių diskų. Taigi, jie bus visiškai skirti programinės įrangos RAID. Ten net skyrių nekursime. Jei norite vadovautis „kanonu“ arba „iš esmės“, sukurkite vieną didelį skaidinį, pavyzdžiui, HDD.

SATA HDD

Čia nereikia nieko ypatingo išradinėti. Viskam sukursime vieną skyrių. Mes sukursime skaidinį, nes BIOS mato šiuos diskus ir gali net bandyti iš jų paleisti. Vėliau šiuose diskuose net įdiegsime GRUB, kad sistema staiga galėtų tai padaryti.

#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

Čia mums viskas darosi įdomūs.

Pirma, mūsų diskai yra 2 TB dydžio. Tai atitinka priimtiną MBR diapazoną, kurį mes ir naudosime. Jei reikia, galima pakeisti GPT. GPT diskai turi suderinamumo sluoksnį, kuris leidžia su MBR suderinamoms sistemoms matyti pirmuosius 4 skaidinius, jei jie yra per pirmuosius 2 terabaitus. Svarbiausia, kad šių diskų įkrovos skaidinys ir bios_grub skaidinys būtų pradžioje. Tai netgi leidžia paleisti iš GPT Legacy / BIOS diskų.

Bet tai ne mūsų atvejis.

Čia sukursime du skyrius. Pirmasis bus 1 GB dydžio ir naudojamas RAID 1 / įkrovai.

Antrasis bus naudojamas RAID 6 ir užims visą likusią laisvą vietą, išskyrus nedidelę nepaskirstytą vietą disko pabaigoje.

Kas yra ši nepažymėta sritis?Remiantis šaltiniais tinkle, mūsų SATA SSD diskuose yra dinamiškai plečiama SLC talpykla, kurios dydis svyruoja nuo 6 iki 78 gigabaitų. 6 gigabaitus gauname „nemokamai“ dėl skirtumo tarp „gigabaitų“ ir „gibibaitų“ disko duomenų lape. Likę 72 gigabaitai skiriami iš nepanaudotos vietos.

Čia reikia pažymėti, kad turime SLC talpyklą, o vieta yra užimta 4 bitų MLC režimu. O tai mums iš esmės reiškia, kad už kiekvienus 4 gigabaitus laisvos vietos gausime tik 1 gigabaitą SLC talpyklos.

Padauginkite 72 gigabaitus iš 4 ir gaukite 288 gigabaitus. Tai yra laisva vieta, kurios nepažymėsime, kad diskai galėtų visapusiškai išnaudoti SLC talpyklą.

Taigi iš šešių diskų efektyviai gausime iki 312 gigabaitų SLC talpyklos. Iš visų diskų 2 bus naudojami RAID atleidimui.

Toks talpyklos kiekis leis mums labai retai realiame gyvenime susidurti su situacija, kai įrašas nepatenka į talpyklą. Tai itin gerai kompensuoja liūdniausią QLC atminties trūkumą – itin mažą rašymo greitį, kai duomenys rašomi aplenkiant talpyklą. Jei jūsų apkrovos to neatitinka, rekomenduoju gerai pagalvoti, kiek laiko jūsų SSD veiks esant tokiai apkrovai, atsižvelgiant į TBW iš duomenų lapo.

#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

Masyvų kūrimas

Pirmiausia turime pervardyti mašiną. Tai būtina, nes pagrindinio kompiuterio pavadinimas yra masyvo pavadinimo dalis kažkur mdadm viduje ir kažkur kažką paveikia. Žinoma, masyvai gali būti pervadinti vėliau, tačiau tai yra nereikalingas žingsnis.

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

„NVMe“ SSD

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

Kodėl -manyti-švarus...?Kad būtų išvengta masyvų inicijavimo. Tai galioja ir 1, ir 6 RAID lygiams. Viskas gali veikti be inicijavimo, jei tai naujas masyvas. Be to, SSD masyvo inicijavimas sukūrimo metu yra TBW išteklių švaistymas. Surinktose SSD masyvuose, kur įmanoma, naudojame TRIM/DISCARD, kad juos „inicijuotume“.

SSD masyvuose RAID 1 DISCARD palaikoma iš karto.

Jei naudojate SSD RAID 6 DISCARD masyvus, turite jį įjungti branduolio modulio parametruose.

Tai turėtų būti daroma tik tuo atveju, jei visi SSD, naudojami šios sistemos 4/5/6 lygio masyvuose, palaiko discard_zeroes_data. Kartais susiduriate su keistais diskais, kurie praneša branduoliui, kad ši funkcija palaikoma, tačiau iš tikrųjų jos nėra arba funkcija ne visada veikia. Šiuo metu palaikymas pasiekiamas beveik visur, tačiau yra senų diskų ir programinės įrangos su klaidomis. Dėl šios priežasties pagal numatytuosius nustatymus RAID 6 DISCARD palaikymas yra išjungtas.

Dėmesio, ši komanda sunaikins visus NVMe diskų duomenis „inicijuodama“ masyvą „nuliais“.

#blkdiscard /dev/md0

Jei kas nors negerai, pabandykite nurodyti veiksmą.

#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

Kodėl toks didelis...Lukšto dydžio padidinimas teigiamai veikia atsitiktinio nuskaitymo blokuose greitį iki gabalo dydžio imtinai. Taip nutinka todėl, kad viename įrenginyje galima visiškai atlikti vieną atitinkamo dydžio ar mažesnę operaciją. Todėl visų įrenginių IOPS yra sumuojamas. Pagal statistiką, 99% IO neviršija 512K.

RAID 6 IOPS vienam rašymui visada mažesnis arba lygus vieno disko IOPS. Kai atsitiktinis skaitymas IOPS gali būti kelis kartus didesnis nei vieno disko, o čia bloko dydis yra labai svarbus.
Autorius nemato prasmės bandyti optimizuoti blogą RAID 6 projektavimo parametrą ir vietoj to optimizuoja tai, ką RAID 6 yra geras.
Prastą atsitiktinį RAID 6 įrašymą kompensuosime NVMe talpykla ir plonų aprūpinimo gudrybėmis.

RAID 6 dar neįjungėme DISCARD. Taigi kol kas šio masyvo „neinicijuosime“. Tai padarysime vėliau, įdiegę OS.

SATA HDD

#mdadm --create --verbose --assume-clean /dev/md3 --chunk-size=512 --level=6 --raid-devices=8 /dev/sd[g-n]1

LVM NVMe RAID

Dėl greičio norime įdėti šakninę failų sistemą į NVMe RAID 1, kuri yra /dev/md0.
Tačiau šio greito masyvo mums vis tiek reikės kitiems poreikiams, pvz., apsikeitimui, metaduomenų ir LVM talpyklos bei LVM plonų metaduomenų, todėl šiame masyve sukursime LVM VG.

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

Sukurkime šakninės failų sistemos skaidinį.

#lvcreate -L 128G --name root root

Sukurkime skaidinį keitimui pagal RAM dydį.

#lvcreate -L 32G --name swap root

OS diegimas

Iš viso turime viską, ko reikia sistemai įdiegti.

Paleiskite sistemos diegimo vedlį iš Ubuntu Live aplinkos. Įprastas montavimas. Tik pasirinkdami diegimo diskus, turite nurodyti šiuos dalykus:

  • /dev/md1, - prijungimo taškas /boot, FS - BTRFS
  • /dev/root/root (dar žinomas kaip /dev/mapper/root-root), - prijungimo taškas / (šaknis), FS - BTRFS
  • /dev/root/swap (dar žinomas kaip /dev/mapper/root-swap), - naudoti kaip apsikeitimo skaidinį
  • Įdiekite įkrovos įkroviklį /dev/sda

Kai pasirenkate BTRFS kaip šakninę failų sistemą, diegimo programa automatiškai sukurs du BTRFS tomus, pavadintus „@“ / (root) ir „@home“ /home.

Pradėkime diegimą...

Diegimas baigsis modaliniu dialogo langu, rodančiu įkrovos įkrovos diegimo klaidą. Deja, negalėsite išeiti iš šio dialogo lango naudodami standartines priemones ir tęsti diegimą. Atsijungiame nuo sistemos ir vėl prisijungiame, atsidurdami švariame Ubuntu Live darbalaukyje. Atidarykite terminalą ir dar kartą:

#sudo bash

Norėdami tęsti diegimą, sukurkite chroot aplinką:

#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

Sukonfigūruokime tinklą ir pagrindinio kompiuterio pavadinimą chroot:

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

Eikime į chroot aplinką:

#chroot /mnt/chroot

Visų pirma, pristatysime pakuotes:

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

Patikrinkime ir pataisykime visus paketus, kurie buvo įdiegti klaidingai dėl neužbaigto sistemos diegimo:

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

Jei kas nors nepavyksta, pirmiausia gali reikėti redaguoti /etc/apt/sources.list

Pakoreguokite RAID 6 modulio parametrus, kad įjungtumėte TRIM / DISCARD:

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

Šiek tiek pakoreguokime savo masyvus:

#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

Kas tai buvo..?Sukūrėme udev taisyklių rinkinį, kuris atliks šiuos veiksmus:

  • Nustatykite RAID 2020 bloko talpyklos dydį, kad jis būtų tinkamas 6 m. Numatytoji reikšmė, atrodo, nepasikeitė nuo Linux sukūrimo ir buvo netinkama ilgą laiką.
  • Rezervuokite mažiausiai IO masyvo patikrinimų / sinchronizacijų trukmei. Taip siekiama, kad jūsų masyvai neįstrigtų amžino sinchronizavimo būsenoje esant apkrovai.
  • Apribokite maksimalų IO tikrinant / sinchronizuojant masyvus. Tai būtina, kad sinchronizuojant / tikrinant SSD RAID diskai nesudegtų. Tai ypač pasakytina apie NVMe. (Prisimeni apie radiatorių? Aš nejuokauju.)
  • Uždrausti diskams sustabdyti suklio sukimąsi (HDD) per APM ir nustatyti disko valdiklių miego laiką iki 7 valandų. Galite visiškai išjungti APM, jei tai gali padaryti jūsų diskai (-B 255). Naudojant numatytąją vertę, diskai sustos po penkių sekundžių. Tada OS nori iš naujo nustatyti disko talpyklą, diskai vėl suksis ir viskas prasidės iš naujo. Diskai turi ribotą maksimalų veleno apsisukimų skaičių. Toks paprastas numatytasis ciklas gali lengvai nužudyti jūsų diskus per porą metų. Ne visi diskai nuo to kenčia, bet mūsų yra „nešiojamieji“ su atitinkamais numatytais nustatymais, dėl kurių RAID atrodo kaip mini-MAID.
  • Įdiekite skaitymo į priekį diskuose (sukamą) 1 megabaitą – du blokai iš eilės / RAID 6 dalis
  • Išjungti skaitymą į priekį pačiuose masyvuose.

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

Kodėl taip..?Ieškosime /boot skaidinio pagal UUID. Masyvo pavadinimai teoriškai gali pasikeisti.

Likusių skyrių ieškosime pagal LVM pavadinimus /dev/mapper/vg-lv žymėjime, nes jie gana unikaliai identifikuoja pertvaras.

Mes nenaudojame UUID LVM, nes LVM tomų ir jų momentinių nuotraukų UUID gali būti tas pats.Du kartus prijungti /dev/mapper/root-root..?Taip. Būtent. BTRFS funkcija. Ši failų sistema gali būti montuojama kelis kartus su skirtingais subvols.

Dėl tos pačios funkcijos rekomenduoju niekada nekurti LVM momentinių aktyvių BTRFS tomų. Kai paleisite iš naujo, galite sulaukti staigmenos.

Atkurkime mdadm konfigūraciją:

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

Pakoreguojame LVM nustatymus:

#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

Kas tai buvo..?Įgalinome automatinį LVM plonųjų baseinų išplėtimą, pasiekus 90% užimamo ploto 5% tūrio.

Padidinome maksimalų LVM talpyklos talpyklos blokų skaičių.

Neleidome LVM ieškoti LVM tomų (PV):

  • įrenginiai, kuriuose yra LVM talpykla (cdata)
  • įrenginiai talpykloje saugomi naudojant LVM talpyklą, apeinant talpyklą ( _corig). Tokiu atveju pats talpykloje esantis įrenginys vis tiek bus nuskaitomas per talpyklą (tiesiog ).
  • įrenginiai, kuriuose yra LVM talpyklos metaduomenų (cmeta)
  • visi VG įrenginiai su pavadinimų vaizdais. Čia turėsime virtualių mašinų disko vaizdus ir nenorime, kad LVM pagrindiniame kompiuteryje suaktyvintų svečių OS priklausančius tomus.
  • visi įrenginiai VG su atsargine pavadinimu. Čia turėsime atsargines virtualios mašinos vaizdų kopijas.
  • visi įrenginiai, kurių pavadinimas baigiasi „gpv“ (svečio fizinis tūris)

Atlaisvindami laisvos vietos LVM VG, įgalinome DISCARD palaikymą. Būk atsargus. Dėl to LVs ištrynimas iš SSD užtruks gana ilgai. Tai ypač pasakytina apie SSD RAID 6. Tačiau pagal planą naudosime ploną aprūpinimą, todėl tai mums visiškai netrukdys.

Atnaujinkime initramfs vaizdą:

#update-initramfs -u -k all

Įdiekite ir sukonfigūruokite grub:

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

Kokius diskus rinktis?Visi, kurie yra sd*. Sistema turi turėti galimybę paleisti iš bet kurio veikiančio SATA disko arba SSD.

Kodėl jie pridėjo os-prober..?Už perdėtą savarankiškumą ir žaismingas rankas.

Jis neveikia tinkamai, jei vienas iš RAID yra sugadintos būsenos. Jis bando ieškoti OS skaidiniuose, kurie naudojami virtualiose mašinose, kuriose veikia ši aparatinė įranga.

Jei jums to reikia, galite palikti, tačiau nepamirškite visų aukščiau išvardytų dalykų. Rekomenduoju ieškoti internete receptų, kaip atsikratyti išdykusių rankų.

Tuo mes baigėme pradinį diegimą. Atėjo laikas iš naujo paleisti į naujai įdiegtą OS. Nepamirškite išimti įkrovos Live CD / USB.

#exit
#reboot

Pasirinkite bet kurį iš SATA SSD kaip įkrovos įrenginį.

LVM SATA SSD diske

Šiuo metu mes jau paleidome naują OS, sukonfigūravome tinklą, apt, atidarėme terminalo emuliatorių ir paleidome:

#sudo bash

Tęskime.

„Inicijuoti“ masyvą iš SATA SSD:

#blkdiscard /dev/md2

Jei tai neveikia, pabandykite:

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

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

Kodėl dar VG..?Tiesą sakant, mes jau turime VG pavadinimu root. Kodėl nesudėjus visko į vieną VG?

Jei VG yra keli PV, tada, kad VG būtų tinkamai suaktyvintas, visi PV turi būti (internete). Išimtis yra LVM RAID, kurio mes sąmoningai nenaudojame.

Labai norime, kad įvykus gedimui (prarasti skaitymo duomenis) bet kuriame iš RAID 6 masyvų, operacinė sistema pradėtų normaliai ir suteiktų galimybę išspręsti problemą.

Norėdami tai padaryti, pirmame abstrakcijos lygyje mes išskirsime kiekvieną fizinės „medijos“ tipą į atskirą VG.

Moksliškai kalbant, skirtingi RAID masyvai priklauso skirtingoms „patikimumo sritims“. Neturėtumėte sukurti jiems papildomo bendro gedimo taško, sugrūdę juos į vieną VG.

LVM buvimas „aparatinės įrangos“ lygiu leis mums savavališkai iškirpti skirtingų RAID masyvų dalis, jas derinant skirtingais būdais. Pavyzdžiui – bėgioti tuo pat metu bcache + LVM plonas, bcache + BTRFS, LVM talpyklos + LVM plonas, sudėtinga ZFS konfigūracija su talpyklomis arba bet koks kitas pragariškas mišinys, kad galėtumėte viską palyginti.

„Aparatūros“ lygiu nenaudosime nieko kito, išskyrus senus gerus „storus“ LVM tomus. Šios taisyklės išimtis gali būti atsarginis skaidinys.

Manau, iki šios akimirkos daugelis skaitytojų jau pradėjo kažką įtarti apie lizdą lėlę.

LVM SATA HDD

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

Vėl naujas VG..?Labai norime, kad jei diskų masyvas, kurį naudosime kurdami duomenų atsarginę kopiją, sugestų, mūsų operacinė sistema ir toliau veiktų įprastai, išlaikydama prieigą prie ne atsarginių duomenų, kaip įprasta. Todėl, norėdami išvengti VG aktyvinimo problemų, sukuriame atskirą VG.

LVM talpyklos nustatymas

Sukurkime LV NVMe RAID 1, kad naudotume jį kaip talpyklos įrenginį.

#lvcreate -L 70871154688B --name cache root

Kodėl tiek mažai...?Faktas yra tas, kad mūsų NVMe SSD taip pat turi SLC talpyklą. 4 gigabaitai „laisvos“ ir 18 gigabaitų dinaminės dėl laisvos vietos, užimtos 3 bitų MLC. Išnaudojus šią talpyklą, NVMe SSD diskai nebus daug greitesni nei mūsų SATA SSD su talpykla. Tiesą sakant, dėl šios priežasties mums nėra prasmės LVM talpyklos skaidinį padaryti daug didesnį nei dvigubai daugiau nei NVMe disko SLC talpyklos dydis. Autorius mano, kad naudojamiems NVMe diskams tikslinga sukurti 32–64 gigabaitus talpyklos.

Nurodytas skaidinio dydis reikalingas norint sutvarkyti 64 gigabaitus talpyklos, talpyklos metaduomenų ir metaduomenų atsarginės kopijos.

Be to, atkreipiu dėmesį, kad po nešvaraus sistemos išjungimo LVM pažymės visą talpyklą kaip nešvarią ir vėl sinchronizuos. Be to, tai bus kartojama kiekvieną kartą, kai šiame įrenginyje bus naudojama lvchange, kol sistema vėl bus paleista iš naujo. Todėl rekomenduoju nedelsiant atkurti talpyklą naudojant atitinkamą scenarijų.

Sukurkime LV SATA RAID 6, kad naudotume jį kaip talpyklos įrenginį.

#lvcreate -L 3298543271936B --name cache data

Kodėl tik trys terabaitai..?Kad prireikus galėtumėte naudoti SATA SSD RAID 6 kitiems poreikiams. Talpykloje esančios erdvės dydį galima padidinti dinamiškai, greitai, nestabdant sistemos. Norėdami tai padaryti, turite laikinai sustabdyti ir iš naujo įjungti talpyklą, tačiau išskirtinis LVM talpyklos pranašumas, palyginti su, pavyzdžiui, bcache, yra tas, kad tai galima padaryti skrydžio metu.

Sukurkime naują VG talpykloje.

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

Talpykloje esančiame įrenginyje sukurkime LV.

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

Čia mes iš karto užėmėme visą laisvą vietą /dev/data/cache, kad visi kiti reikalingi skaidiniai būtų iškart sukurti /dev/root/cache. Jei ką nors sukūrėte netinkamoje vietoje, galite jį perkelti naudodami pvmove.

Sukurkime ir įgalinkime talpyklą:

#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

Kodėl tokie gabalai..?Atlikdamas praktinius eksperimentus, autorius sugebėjo išsiaiškinti, kad geriausias rezultatas pasiekiamas, jei LVM talpyklos bloko dydis sutampa su LVM plono bloko dydžiu. Be to, kuo mažesnis dydis, tuo geriau konfigūracija veikia atsitiktinio įrašymo metu.

64k yra mažiausias leistinas LVM plono bloko dydis.

Būkite atsargūs rašydami..!Taip. Šio tipo talpykla atideda rašymo sinchronizavimą talpykloje esančiame įrenginyje. Tai reiškia, kad jei prarandate talpyklą, galite prarasti duomenis talpykloje esančiame įrenginyje. Vėliau autorius jums pasakys, kokių priemonių, be NVMe RAID 1, galima imtis šiai rizikai kompensuoti.

Šis talpyklos tipas buvo pasirinktas sąmoningai, siekiant kompensuoti prastą atsitiktinio RAID 6 rašymo našumą.

Pažiūrėkime, ką gavome:

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

Tik [cachedata_corig] turėtų būti /dev/data/cache. Jei kažkas negerai, naudokite pvmove.

Jei reikia, talpyklą galite išjungti viena komanda:

#lvconvert -y --uncache cache/cachedata

Tai daroma internetu. LVM tiesiog sinchronizuos talpyklą su disku, pašalins ją ir pervadins cachedata_corig atgal į cachedata.

LVM plono nustatymas

Apytiksliai įvertinkime, kiek vietos mums reikia LVM ploniems metaduomenims:

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

Suapvalinti iki 4 gigabaitų: 4294967296B

Padauginkite iš dviejų ir pridėkite 4194304B LVM PV metaduomenų: 8594128896B
Sukurkime atskirą skaidinį NVMe RAID 1, kad į jį patalpintume plonus LVM metaduomenis ir jų atsarginę kopiją:

#lvcreate -L 8594128896B --name images root

Kam..?Čia gali kilti klausimas: kam LVM plonus metaduomenis dėti atskirai, jei jie vis tiek bus talpykloje NVMe ir veiks greitai.

Nors greitis čia svarbus, tai toli gražu nėra pagrindinė priežastis. Reikalas tas, kad talpykla yra gedimo taškas. Jam gali kažkas nutikti, o jei LVM ploni metaduomenys bus išsaugoti talpykloje, viskas bus visiškai prarasta. Be visų metaduomenų bus beveik neįmanoma surinkti plonų tomų.

Perkeldami metaduomenis į atskirą talpykloje neišsaugotą, bet greitą tomą, garantuojame metaduomenų saugumą talpyklos praradimo ar sugadinimo atveju. Tokiu atveju visa žala, kurią sukelia talpyklos praradimas, bus lokalizuota plonuose tomuose, o tai supaprastins atkūrimo procedūrą. Labai tikėtina, kad šie pažeidimai bus atstatyti naudojant FS žurnalus.

Be to, jei anksčiau buvo padaryta nedidelės apimties momentinė nuotrauka, o po to talpykla buvo visiškai sinchronizuota bent vieną kartą, dėl LVM plono vidinio dizaino momentinės nuotraukos vientisumas bus garantuotas praradus talpyklą. .

Sukurkime naują VG, kuris bus atsakingas už ploną aprūpinimą:

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

Sukurkime baseiną:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Kodėl -Z yBe to, kam šis režimas iš tikrųjų yra skirtas – kad perskirstant erdvę duomenims iš vienos virtualios mašinos nenutekėtų į kitą virtualią mašiną – papildomai naudojamas nulis, siekiant padidinti atsitiktinio rašymo greitį mažesniuose nei 64k blokuose. Bet koks įrašymas, mažesnis nei 64k į anksčiau nepaskirstytą plono tūrio sritį, talpykloje bus sulygiuotas su 64K kraštais. Tai leis visą operaciją atlikti per talpyklą, apeinant talpykloje saugomą įrenginį.

Perkelkime LV į atitinkamus PV:

#pvmove -n images/thin-pool_tdata /dev/root/images /dev/cache/cachedata
#pvmove -n images/lvol0_pmspare /dev/cache/cachedata /dev/root/images
#pvmove -n images/thin-pool_tmeta /dev/cache/cachedata /dev/root/images

Patikrinkime:

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

Sukurkime nedidelį tūrį bandymams:

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

Įdiegsime testų ir stebėjimo paketus:

#apt-get install sysstat fio

Štai kaip galite stebėti mūsų saugyklos konfigūracijos veikimą realiuoju laiku:

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

Taip galime išbandyti savo konfigūraciją:

#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

Atsargiai! Išteklius!Šis kodas vykdys 36 skirtingus testus, kurių kiekvienas veiks 4 sekundes. Pusė testų skirta įrašymui. NVMe galite įrašyti daug per 4 sekundes. Iki 3 gigabaitų per sekundę. Taigi, kiekviena rašymo testų eiga gali suvalgyti iki 216 gigabaitų SSD išteklių iš jūsų.

Skaityti ir rašyti maišyti?Taip. Tikslinga skaityti ir rašyti testus atlikti atskirai. Be to, prasminga užtikrinti, kad visos talpyklos būtų sinchronizuotos, kad anksčiau atliktas rašymas nepaveiktų skaitymo.

Rezultatai labai skirsis per pirmąjį paleidimą ir vėlesnius, kai užpildoma talpykla ir mažas tūris, taip pat priklausomai nuo to, ar sistemai pavyko sinchronizuoti talpyklas, užpildytas paskutinio paleidimo metu.

Be kita ko, rekomenduoju matuoti greitį jau visiškai ploname tūryje, iš kurio ką tik buvo padaryta momentinė nuotrauka. Autorius turėjo galimybę stebėti, kaip atsitiktinis rašymas smarkiai įsibėgėja iškart po pirmojo momentinio vaizdo sukūrimo, ypač kai talpykla dar nėra visiškai pilna. Taip nutinka dėl kopijavimo ir rašymo rašymo semantikos, talpyklos ir plonų tūrio blokų išlyginimo ir to, kad atsitiktinis įrašymas į RAID 6 virsta atsitiktiniu skaitymu iš RAID 6, po kurio seka įrašymas į talpyklą. Mūsų konfigūracijoje atsitiktinis skaitymas iš RAID 6 yra iki 6 kartų greitesnis nei rašymas. Nes blokai CoW paskirstomi nuosekliai iš plono telkinio, tada įrašymas didžiąja dalimi taip pat virsta nuosekliu.

Abi šios funkcijos gali būti panaudotos jūsų naudai.

Talpykloje saugokite „nuoseklias“ momentines nuotraukas

Siekiant sumažinti duomenų praradimo riziką talpyklos pažeidimo / praradimo atveju, autorius siūlo įvesti momentinių vaizdų sukimosi praktiką, kad tokiu atveju būtų užtikrintas jų vientisumas.

Pirma, kadangi nedidelės apimties metaduomenys yra talpykloje neišsaugotame įrenginyje, metaduomenys bus nuoseklūs ir galimi praradimai bus atskirti duomenų blokuose.

Šis momentinių nuotraukų pasukimo ciklas garantuoja momentinėse nuotraukose esančių duomenų vientisumą, jei prarandama talpykla:

  1. Kiekvienam plonam tomui, kurio pavadinimas yra <vardas>, sukurkite momentinę nuotrauką pavadinimu <vardas>.cached
  2. Nustatykime perėjimo slenkstį į pagrįstą didelę reikšmę: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Ciklo metu patikriname nešvarių blokų skaičių talpykloje: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' kol gausime nulį. Jei nulis trūksta per ilgai, jį galima sukurti laikinai perjungiant talpyklą į įrašymo režimą. Tačiau, atsižvelgiant į mūsų SATA ir NVMe SSD masyvų greičio charakteristikas, taip pat į jų TBW išteklius, galėsite greitai užfiksuoti akimirką nekeisdami talpyklos režimo, arba jūsų aparatinė įranga visiškai sunaudos visus savo išteklius. keletą dienų. Dėl išteklių apribojimų sistema iš esmės negali visą laiką būti mažesnė nei 100 % rašymo apkrova. Mūsų NVMe SSD diskai, esant 100% įrašymo apkrovai, visiškai išnaudos išteklius 3-4 dienas. SATA SSD tarnaus tik dvigubai ilgiau. Todėl manysime, kad didžioji apkrova tenka skaitymui, ir mes turime santykinai trumpalaikius itin didelio aktyvumo pliūpsnius ir vidutiniškai mažą rašymo apkrovą.
  4. Kai tik sugauname (arba padarome) nulį, pervadiname <vardas>.cached į <vardas>.įsipareigotas. Senasis <vardas>.committed yra ištrintas.
  5. Pasirinktinai, jei talpykla yra 100% pilna, ją galima atkurti naudojant scenarijų, taip ją išvalant. Turint pusiau tuščią talpyklą, rašant sistema veikia daug greičiau.
  6. Nustatykite perėjimo slenkstį į nulį: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Tai laikinai neleis talpyklai sinchronizuotis su pagrindine laikmena.
  7. Laukiame, kol talpykloje susikaups nemažai pakeitimų #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' arba laikmatis išsijungs.
  8. Dar kartą kartojame.

Kodėl kyla sunkumų dėl migracijos slenksčio...?Reikalas tas, kad iš tikrųjų „atsitiktinis“ įrašas iš tikrųjų nėra visiškai atsitiktinis. Jei ką nors parašytume į 4 kilobaitų dydžio sektorių, didelė tikimybė, kad per artimiausias porą minučių bus padarytas įrašas į tą patį arba vieną iš gretimų (+- 32K) sektorių.

Nustačius perkėlimo slenkstį į nulį, atidedame rašymo sinchronizavimą SATA SSD ir sujungiame kelis pakeitimus į vieną 64K bloką talpykloje. Tai žymiai sutaupo SATA SSD išteklius.

Kur kodas..?Deja, autorius laiko save nepakankamai kompetentingu kuriant bash scenarijus, nes yra 100% savamokslis ir praktikuoja „google“ varomą kūrimą, todėl mano, kad baisaus kodo, kuris išeina iš jo rankų, niekas neturėtų naudoti. Kitas.

Manau, kad šios srities profesionalai prireikus sugebės savarankiškai pavaizduoti visą aukščiau aprašytą logiką ir, galbūt, net gražiai ją suprojektuoti kaip sisteminę paslaugą, kaip bandė padaryti autorius.

Tokia paprasta momentinių nuotraukų pasukimo schema leis ne tik nuolat turėti vieną momentinį vaizdą, visiškai sinchronizuotą SATA SSD diske, bet ir leis, naudojant ploną_delta įrankį, sužinoti, kurie blokai buvo pakeisti po jo sukūrimo, ir taip lokalizuoti žalą pagrindinės apimties, labai supaprastinant atkūrimą.

TRIM/DISCARD programoje libvirt/KVM

Nes duomenų saugykla bus naudojama KVM, kurioje veikia libvirt, tada būtų gerai išmokyti mūsų VM ne tik užimti laisvą vietą, bet ir atlaisvinti tai, kas nebereikalinga.

Tai atliekama imituojant TRIM/DISCARD palaikymą virtualiuose diskuose. Norėdami tai padaryti, turite pakeisti valdiklio tipą į virtio-scsi ir redaguoti 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>

Tokius DISCARD iš svečių OS teisingai apdoroja LVM, o blokai tinkamai atlaisvinami tiek talpykloje, tiek plonajame telkinyje. Mūsų atveju tai dažniausiai atsitinka uždelsus, kai ištrinama kita momentinė nuotrauka.

BTRFS atsarginė kopija

Naudokite paruoštus scenarijus su ekstremalus atsargiai ir savo rizika. Šį kodą autorius parašė pats ir išskirtinai sau. Esu tikras, kad daugelis patyrusių „Linux“ vartotojų turi panašius įrankius ir nereikia kopijuoti kieno nors kito.

Sukurkime tomą atsarginiame įrenginyje:

#lvcreate -L 256G --name backup backup

Suformatuokime jį BTRFS:

#mkfs.btrfs /dev/backup/backup

Sukurkime prijungimo taškus ir prijunkite šakninius failų sistemos poskyrius:

#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

Sukurkime katalogus atsarginėms kopijoms:

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

Sukurkime atsarginių scenarijų katalogą:

#mkdir /root/btrfs-backup

Nukopijuokime scenarijų:

Daug baisaus bash kodo. Naudokite savo rizika. Nerašyk piktų laiškų autoriui...#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

Ką tai net daro..?Yra paprastų komandų rinkinys, skirtas BTRFS momentinėms nuotraukoms kurti ir jas nukopijuoti į kitą FS naudojant BTRFS siuntimą / gavimą.

Pirmasis paleidimas gali būti gana ilgas, nes... Pradžioje visi duomenys bus nukopijuoti. Tolesni paleidimai bus labai greiti, nes... Bus nukopijuoti tik pakeitimai.

Kitas scenarijus, kurį įtrauksime į cron:

Dar šiek tiek bash kodo#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

Ką tai daro..?Sukuria ir sinchronizuoja atsarginės kopijos FS sąraše esančių BTRFS tomų laipsniškas momentines kopijas. Po to ištrinamos visos nuotraukos, sukurtos prieš 60 dienų. Paleidus, išvardytų tomų momentinės nuotraukos bus rodomos pakatalogiuose /backup/btrfs/back/remote/.

Suteikime kodo vykdymo teises:

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

Patikrinkime ir įdėkime į 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 plona atsarginė kopija

Atsarginiame įrenginyje sukurkime ploną baseiną:

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

Įdiegkime ddrescue, nes... scenarijai naudos šį įrankį:

#apt-get install gddrescue

Sukurkime scenarijų katalogą:

#mkdir /root/lvm-thin-backup

Nukopijuokime scenarijus:

Viduje daug šlykštėjimo...#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

Ką tai daro...?Jame yra komandų rinkinys, skirtas manipuliuoti plonomis momentinėmis nuotraukomis ir sinchronizuoti skirtumą tarp dviejų plonų momentinių nuotraukų, gautų per thin_delta, su kitu blokiniu įrenginiu, naudojant ddrescue ir blkdiscard.

Kitas scenarijus, kurį įdėsime į cron:

Šiek tiek daugiau baisumo#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

Ką tai daro...?Naudoja ankstesnį scenarijų, kad sukurtų ir sinchronizuotų išvardytų plonų tomų atsargines kopijas. Scenarijus paliks neaktyvias išvardytų tomų momentines kopijas, kurių reikia norint stebėti pokyčius po paskutinio sinchronizavimo.

Šis scenarijus turi būti redaguojamas, nurodant plonų tomų, kurių atsargines kopijas reikia daryti, sąrašą. Pateikti pavadinimai yra tik iliustravimo tikslais. Jei norite, galite parašyti scenarijų, kuris sinchronizuos visus tomus.

Suteikime teises:

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

Patikrinkime ir įdėkime į 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

Pirmasis paleidimas bus ilgas, nes... ploni tomai bus visiškai sinchronizuoti nukopijavus visą panaudotą erdvę. Dėl LVM plonų metaduomenų žinome, kurie blokai iš tikrųjų naudojami, todėl bus kopijuojami tik faktiškai naudojami ploni tūrio blokai.

Vėlesnėse operacijose duomenys bus kopijuojami laipsniškai dėl pokyčių stebėjimo naudojant LVM plonus metaduomenis.

Pažiūrėkime, kas atsitiko:

#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

Ką tai turi bendro su lizdinėmis lėlėmis?

Labiausiai tikėtina, kad LVM LV loginiai tūriai gali būti LVM PV fiziniai tūriai kitiems VG. LVM gali būti rekursyvus, kaip lizdinės lėlės. Tai suteikia LVM ypatingo lankstumo.

PS

Kitame straipsnyje pabandysime panaudoti keletą panašių mobiliųjų saugojimo sistemų/KVM kaip pagrindą sukurti geografiškai paskirstytą saugyklos/VM klasterį su pertekliumi keliuose žemynuose, naudojant namų stalinius kompiuterius, namų internetą ir P2P tinklus.

Šaltinis: www.habr.com

Добавить комментарий