Çfarë kanë të përbashkët LVM dhe Matryoshka?

Mirëdita.
Unë do të doja të ndaj me komunitetin përvojën time praktike të ndërtimit të një sistemi të ruajtjes së të dhënave për KVM duke përdorur md RAID + LVM.

Programi do të përfshijë:

  • Ndërtimi i md RAID 1 nga NVMe SSD.
  • Montimi i md RAID 6 nga SATA SSD dhe disqet e rregullt.
  • Karakteristikat e funksionimit TRIM/DISCARD në SSD RAID 1/6.
  • Krijimi i një grupi të bootable md RAID 1/6 në një grup të përbashkët disqesh.
  • Instalimi i sistemit në NVMe RAID 1 kur nuk ka mbështetje NVMe në BIOS.
  • Përdorimi i cache LVM dhe LVM i hollë.
  • Duke përdorur fotografi të BTRFS dhe dërgoni/merrni për kopje rezervë.
  • Duke përdorur fotografi të hollë LVM dhe thin_delta për kopje rezervë të stilit BTRFS.

Nëse jeni të interesuar, ju lutemi shikoni cat.

Deklarata

Autori nuk mban asnjë përgjegjësi për pasojat e përdorimit ose mospërdorimit të materialeve/shembujve/kodit/këshillave/të dhënave nga ky artikull. Duke lexuar ose përdorur këtë material në çfarëdo mënyre, ju merrni përgjegjësinë për të gjitha pasojat e këtyre veprimeve. Pasojat e mundshme përfshijnë:

  • SSD NVMe të skuqura.
  • Burimi i regjistrimit i përdorur plotësisht dhe dështimi i disqeve SSD.
  • Humbje e plotë e të gjitha të dhënave në të gjitha disqet, duke përfshirë kopjet rezervë.
  • Pajisje kompjuterike me defekt.
  • Kohë, nerva dhe para të humbura.
  • Çdo pasojë tjetër që nuk është renditur më sipër.

hekur

Në dispozicion ishin:

Motherboard nga rreth 2013 me chipset Z87, i kompletuar me Intel Core i7 / Haswell.

  • Procesor 4 bërthama, 8 fije
  • 32 GB RAM DDR3
  • 1 x 16 ose 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 lidhëse

Përshtatësi SAS LSI SAS9211-8I ndezi në modalitetin IT / HBA. Firmware i aktivizuar me RAID është zëvendësuar qëllimisht me firmware HBA për të:

  1. Ju mund ta hidhni këtë përshtatës në çdo kohë dhe ta zëvendësoni me ndonjë tjetër që keni hasur.
  2. TRIM/Discard funksionoi normalisht në disqe, sepse... në firmware RAID këto komanda nuk mbështeten fare, dhe HBA, në përgjithësi, nuk i intereson se cilat komanda transmetohen përmes autobusit.

Hard disqe - 8 copë HGST Travelstar 7K1000 me kapacitet 1 TB në një faktor forme 2.5, si për laptopët. Këto disqe ishin më parë në një grup RAID 6. Ato do të kenë një përdorim edhe në sistemin e ri. Për të ruajtur kopje rezervë lokale.

Shtuar më tej:

6 copë SATA SSD model Samsung 860 QVO 2TB. Këto SSD kërkonin një vëllim të madh, dëshirohej prania e një cache SLC, besueshmëria dhe një çmim i ulët. Kërkohej mbështetje për hedhjen/zero, e cila kontrollohet nga rreshti në dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 copë NVMe SSD model Samsung SSD 970 EVO 500GB.

Për këto SSD, shpejtësia e rastësishme e leximit/shkrimit dhe kapaciteti i burimeve për nevojat tuaja janë të rëndësishme. Radiator për ta. Domosdoshmërisht. Absolutisht. Përndryshe, skuqini ato derisa të bëhen krokante gjatë sinkronizimit të parë RAID.

Përshtatës StarTech PEX8M2E2 për 2 x NVMe SSD të instaluar në slotin PCIe 3.0 8x. Kjo, përsëri, është vetëm një HBA, por për NVMe. Ai ndryshon nga adaptorët e lirë në atë që nuk kërkon mbështetje për bifurkacionin PCIe nga motherboard për shkak të pranisë së një ndërprerës të integruar PCIe. Do të funksionojë edhe në sistemin më të lashtë me PCIe, edhe nëse është një slot x1 PCIe 1.0. Natyrisht, me shpejtësinë e duhur. Nuk ka RAID atje. Nuk ka asnjë BIOS të integruar në bord. Pra, sistemi juaj nuk do të mësojë në mënyrë magjike të niset me NVMe, aq më pak NVMe RAID falë kësaj pajisjeje.

Ky komponent ishte vetëm për shkak të pranisë së vetëm një 8x PCIe 3.0 falas në sistem dhe, nëse ka 2 lojëra elektronike falas, mund të zëvendësohet lehtësisht me dy qindarkë PEX4M2E1 ose analoge, të cilat mund të blihen kudo për një çmim prej 600 rubla.

Refuzimi i të gjitha llojeve të harduerit ose të chipset-it të integruar/BIOS RAID-eve u bë qëllimisht, në mënyrë që të mund të zëvendësohej plotësisht i gjithë sistemi, me përjashtim të vetë SSD/HDD, duke ruajtur të gjitha të dhënat. Në mënyrë ideale, në mënyrë që të mund të ruani edhe sistemin operativ të instaluar kur kaloni në pajisje krejtësisht të reja/të ndryshme. Gjëja kryesore është se ka porte SATA dhe PCIe. Është si një CD e drejtpërdrejtë ose një flash drive bootable, vetëm shumë i shpejtë dhe pak i rëndë.

ЮморPërndryshe, ju e dini se çfarë ndodh - ndonjëherë ju duhet urgjentisht të merrni të gjithë grupin me vete për ta hequr. Por nuk dua të humbas të dhënat. Për ta bërë këtë, të gjitha mediat e përmendura janë të vendosura në mënyrë të përshtatshme në rrëshqitjet në 5.25 foletë e kasës standarde.

Epo, dhe, natyrisht, për të eksperimentuar me metoda të ndryshme të ruajtjes së memories SSD në Linux.

Bastisjet e harduerit janë të mërzitshëm. Ndize atë. Ose funksionon ose nuk funksionon. Dhe me mdadm ka gjithmonë opsione.

butë

Më parë, Debian 8 Jessie ishte instaluar në harduer, i cili është afër EOL. RAID 6 u grumbullua nga HDD-të e lartpërmendura të çiftuara me LVM. Ai drejtonte makina virtuale në kvm/libvirt.

Sepse Autori ka përvojë të përshtatshme në krijimin e disqeve portative bootable SATA/NVMe, dhe gjithashtu, për të mos prishur shabllonin e zakonshëm të përshtatshëm, Ubuntu 18.04 u zgjodh si sistemi i synuar, i cili tashmë është stabilizuar mjaftueshëm, por ka ende 3 vjet mbështetje në të ardhmen.

Sistemi i përmendur përmban të gjithë drejtuesit e harduerit që na duhen jashtë kutisë. Ne nuk kemi nevojë për ndonjë softuer ose drejtues të palëve të treta.

Përgatitja për instalim

Për të instaluar sistemin na duhet Ubuntu Desktop Image. Sistemi i serverit ka një lloj instaluesi të fuqishëm, i cili tregon pavarësi të tepruar që nuk mund të çaktivizohet duke futur ndarjen e sistemit UEFI në një nga disqet, duke prishur gjithë bukurinë. Prandaj, është instaluar vetëm në modalitetin UEFI. Nuk ofron asnjë opsion.

Ne nuk jemi të kënaqur me këtë.

Pse?Fatkeqësisht, boot UEFI është jashtëzakonisht i pajtueshëm me softuerin e nisjes RAID, sepse... Askush nuk na ofron rezervime për ndarjen UEFI ESP. Ka receta në internet që sugjerojnë vendosjen e ndarjes ESP në një flash drive në një port USB, por kjo është një pikë dështimi. Ka receta që përdorin softuerin mdadm RAID 1 me metadata versionin 0.9 që nuk e pengojnë UEFI BIOS-in të shohë këtë ndarje, por kjo jeton deri në momentin e lumtur kur BIOS ose një OS tjetër harduer shkruan diçka në ESP dhe harron ta sinkronizojë atë me të tjerët. pasqyrat.

Për më tepër, boot UEFI varet nga NVRAM, i cili nuk do të lëvizë së bashku me disqet në sistemin e ri, sepse është pjesë e motherboard.

Pra, ne nuk do të rishpikim një rrotë të re. Ne tashmë kemi një biçikletë të gatshme, të testuar me kohë, të quajtur tashmë çizme Legacy/BIOS, që mban emrin krenar të CSM në sistemet e pajtueshme me UEFI. Thjesht do ta heqim nga rafti, do ta lyejmë, pompojmë gomat dhe do ta fshijmë me një leckë të lagur.

Versioni i desktopit i Ubuntu gjithashtu nuk mund të instalohet siç duhet me ngarkuesin Legacy, por këtu, siç thonë ata, të paktën ka opsione.

Dhe kështu, ne mbledhim harduerin dhe ngarkojmë sistemin nga flash drive bootable Ubuntu Live. Do të na duhet të shkarkojmë paketa, kështu që do të konfigurojmë rrjetin që funksionon për ju. Nëse nuk funksionon, mund të ngarkoni paraprakisht paketat e nevojshme në një flash drive.

Shkojmë në mjedisin e Desktop-it, hapim emulatorin e terminalit dhe largohemi:

#sudo bash

Si…?Linja e mësipërme është shkasja kanonik për holiwarët rreth sudos. C bоvijnë mundësi më të mëdha dheоpërgjegjësi më të madhe. Pyetja është nëse mund ta marrësh vetë. Shumë njerëz mendojnë se përdorimi i sudos në këtë mënyrë është të paktën jo i kujdesshëm. Megjithatë:

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

Pse jo ZFS...?Kur instalojmë softuer në kompjuterin tonë, në thelb ne ua japim hua harduerit tonë zhvilluesve të këtij softueri për të drejtuar.
Kur i besojmë këtij softueri sigurinë e të dhënave tona, marrim një hua të barabartë me koston e rivendosjes së këtyre të dhënave, të cilën do të duhet ta paguajmë një ditë.

Nga ky këndvështrim, ZFS është një Ferrari, dhe mdadm+lvm është më shumë si një biçikletë.

Subjektivisht, autori preferon t'u huazojë një biçikletë me kredi personave të panjohur në vend të një Ferrari. As çmimi i emetimit nuk është i lartë. Nuk ka nevojë për të drejta. Më e thjeshtë se rregullat e trafikut. Parkimi është falas. Aftësia ndër-vend është më e mirë. Ju gjithmonë mund të lidhni këmbët në një biçikletë, dhe ju mund të riparoni një biçikletë me duart tuaja.

Pse atëherë BTRFS...?Për të nisur sistemin operativ, ne kemi nevojë për një sistem skedarësh që mbështetet në Legacy/BIOS GRUB jashtë kutisë, dhe në të njëjtën kohë mbështet fotografitë e drejtpërdrejta. Ne do ta përdorim atë për ndarjen /boot. Për më tepër, autori preferon të përdorë këtë FS për / (rrënjë), duke mos harruar të theksohet se për çdo softuer tjetër mund të krijoni ndarje të veçanta në LVM dhe t'i montoni ato në drejtoritë e nevojshme.

Ne nuk do të ruajmë asnjë imazh të makinave virtuale ose bazave të të dhënave në këtë FS.
Ky FS do të përdoret vetëm për të krijuar fotografi të sistemit pa e fikur dhe më pas do t'i transferojë këto fotografi në diskun rezervë duke përdorur dërgimin/marrjen.

Për më tepër, autori në përgjithësi preferon të mbajë një minimum të softuerit direkt në harduer dhe të ekzekutojë të gjithë softuerin e tjerë në makinat virtuale duke përdorur gjëra të tilla si përcjellja e GPU-ve dhe kontrollorët PCI-USB Host në KVM nëpërmjet IOMMU.

Të vetmet gjëra që mbeten në harduer janë ruajtja e të dhënave, virtualizimi dhe rezervimi.

Nëse i besoni më shumë ZFS, atëherë, në parim, për aplikacionin e specifikuar ato janë të këmbyeshme.

Sidoqoftë, autori qëllimisht shpërfill veçoritë e integruara të pasqyrimit/RAID dhe të tepërt që kanë ZFS, BRTFS dhe LVM.

Si një argument shtesë, BTRFS ka aftësinë për të kthyer shkrimet e rastësishme në ato të njëpasnjëshme, gjë që ka një efekt jashtëzakonisht pozitiv në shpejtësinë e sinkronizimit të fotografive / kopjeve rezervë në HDD.

Le të skanojmë të gjitha pajisjet:

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

Le të hedhim një vështrim përreth:

#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

Paraqitja e diskut

SSD NVMe

Por ne nuk do t'i shënojmë në asnjë mënyrë. Gjithsesi, BIOS-i ynë nuk i sheh këto disqe. Pra, ata do të shkojnë tërësisht në softuer RAID. Ne as nuk do të krijojmë seksione atje. Nëse dëshironi të ndiqni "kanunin" ose "kryesisht", krijoni një ndarje të madhe, si një HDD.

HDD SATA

Nuk ka nevojë të shpikni ndonjë gjë të veçantë këtu. Ne do të krijojmë një seksion për gjithçka. Ne do të krijojmë një ndarje sepse BIOS i sheh këto disqe dhe madje mund të përpiqet të niset prej tyre. Ne madje do të instalojmë GRUB në këto disqe më vonë në mënyrë që sistemi ta bëjë këtë papritmas.

#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

Këtu gjërat bëhen interesante për ne.

Së pari, disqet tona janë me madhësi 2 TB. Kjo është brenda intervalit të pranueshëm për MBR, që është ajo që ne do të përdorim. Nëse është e nevojshme, mund të zëvendësohet me GPT. Disqet GPT kanë një shtresë përputhshmërie që lejon sistemet e përputhshme me MBR të shohin 4 ndarjet e para nëse ato ndodhen brenda 2 terabajtit të parë. Gjëja kryesore është që ndarja e nisjes dhe ndarja bios_grub në këto disqe duhet të jenë në fillim. Kjo madje ju lejon të nisni nga disqet GPT Legacy/BIOS.

Por ky nuk është rasti ynë.

Këtu do të krijojmë dy seksione. E para do të jetë 1 GB në madhësi dhe do të përdoret për RAID 1 /boot.

E dyta do të përdoret për RAID 6 dhe do të zërë të gjithë hapësirën e mbetur të lirë, përveç një zone të vogël të pacaktuar në fund të diskut.

Çfarë është kjo zonë e pashënuar?Sipas burimeve në rrjet, SSD-të tona SATA kanë në bord një memorie SLC të zgjerueshme dinamike, me madhësi nga 6 në 78 gigabajt. Ne marrim 6 gigabajt "falas" për shkak të ndryshimit midis "gigabajt" dhe "gibibajt" në fletën e të dhënave të diskut. 72 gigabajt e mbetur janë ndarë nga hapësira e papërdorur.

Këtu duhet theksuar se kemi cache SLC, dhe hapësira është e zënë në modalitetin MLC 4 bit. Që për ne në mënyrë efektive do të thotë se për çdo 4 gigabajt hapësirë ​​të lirë do të marrim vetëm 1 gigabajt memorie SLC.

Shumëzoni 72 gigabajt me 4 dhe merrni 288 gigabajt. Kjo është hapësira e lirë që ne nuk do ta shënojmë në mënyrë që të lejojmë disqet të përdorin plotësisht cache-në SLC.

Kështu, ne do të marrim në mënyrë efektive deri në 312 gigabajt cache SLC nga gjithsej gjashtë disqe. Nga të gjithë disqet, 2 do të përdoren në RAID për tepricë.

Kjo sasi e cache do të na lejojë që jashtëzakonisht rrallë në jetën reale të hasim një situatë ku një shkrim nuk shkon në cache. Kjo kompenson jashtëzakonisht mirë pengesën më të trishtuar të memories QLC - shpejtësinë jashtëzakonisht të ulët të shkrimit kur të dhënat shkruhen duke anashkaluar cache. Nëse ngarkesat tuaja nuk korrespondojnë me këtë, atëherë ju rekomandoj të mendoni mirë se sa do të zgjasë SSD juaj nën një ngarkesë të tillë, duke marrë parasysh TBW nga fleta e të dhënave.

#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

Krijimi i vargjeve

Së pari, ne duhet të riemërtojmë makinën. Kjo është e nevojshme sepse emri i hostit është pjesë e emrit të grupit diku brenda mdadm dhe ndikon në diçka diku. Sigurisht, vargjet mund të riemërohen më vonë, por ky është një hap i panevojshëm.

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

SSD NVMe

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

Pse -supozoj-pastër...?Për të shmangur inicializimin e vargjeve. Për të dy nivelet RAID 1 dhe 6 kjo është e vlefshme. Çdo gjë mund të funksionojë pa inicializim nëse është një grup i ri. Për më tepër, inicializimi i grupit SSD pas krijimit është një humbje e burimit TBW. Ne përdorim TRIM/DISCARD aty ku është e mundur në grupet e montuara SSD për t'i "inicializuar" ato.

Për grupet SSD, RAID 1 DISCARD mbështetet jashtë kutisë.

Për grupet SSD RAID 6 DISCARD, duhet ta aktivizoni në parametrat e modulit të kernelit.

Kjo duhet të bëhet vetëm nëse të gjitha SSD-të e përdorura në grupet e nivelit 4/5/6 në këtë sistem kanë mbështetje pune për discard_zeroes_data. Ndonjëherë hasni disqe të çuditshëm që i tregojnë kernelit se ky funksion mbështetet, por në fakt nuk është aty, ose funksioni nuk funksionon gjithmonë. Për momentin, mbështetja është e disponueshme pothuajse kudo, megjithatë, ka disqe të vjetër dhe firmware me gabime. Për këtë arsye, mbështetja DISCARD është çaktivizuar si parazgjedhje për RAID 6.

Kujdes, komanda e mëposhtme do të shkatërrojë të gjitha të dhënat në disqet NVMe duke "inicializuar" grupin me "zero".

#blkdiscard /dev/md0

Nëse diçka shkon keq, provoni të specifikoni një hap.

#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

Pse kaq i madh...?Rritja e madhësisë së pjesës ka një efekt pozitiv në shpejtësinë e leximit të rastësishëm në blloqe deri në madhësinë e copës përfshirëse. Kjo ndodh sepse një operacion i madhësisë së duhur ose më i vogël mund të kryhet tërësisht në një pajisje të vetme. Prandaj, IOPS nga të gjitha pajisjet është përmbledhur. Sipas statistikave, 99% e IO nuk i kalon 512K.

RAID 6 IOPS për shkrim gjithmonë më pak se ose e barabartë me IOPS të një disku. Kur, si një lexim i rastësishëm, IOPS mund të jetë disa herë më i madh se ai i një disku, dhe këtu madhësia e bllokut është e një rëndësie kryesore.
Autori nuk e sheh pikën në përpjekjen për të optimizuar një parametër që është i keq në dizajnin e RAID 6 dhe në vend të kësaj optimizon atë në të cilën është i mirë RAID 6.
Ne do të kompensojmë për shkrimin e dobët të rastësishëm të RAID 6 me një memorie të fshehtë NVMe dhe truket e sigurimit të hollë.

Nuk e kemi aktivizuar ende DISCARD për RAID 6. Kështu që ne nuk do ta "inicializojmë" këtë grup për momentin. Këtë do ta bëjmë më vonë, pas instalimit të sistemit operativ.

HDD SATA

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

LVM në NVMe RAID

Për shpejtësi, ne duam të vendosim sistemin e skedarëve rrënjë në NVMe RAID 1 që është /dev/md0.
Megjithatë, ne do të na duhet ende ky grup i shpejtë për nevoja të tjera, të tilla si shkëmbimi, metadatat dhe metadata LVM-cache dhe LVM-thin metadata, kështu që ne do të krijojmë një LVM VG në këtë grup.

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

Le të krijojmë një ndarje për sistemin e skedarëve rrënjë.

#lvcreate -L 128G --name root root

Le të krijojmë një ndarje për shkëmbim sipas madhësisë së RAM-it.

#lvcreate -L 32G --name swap root

Instalimi i OS

Në total, ne kemi gjithçka të nevojshme për të instaluar sistemin.

Nisni magjistarin e instalimit të sistemit nga mjedisi Ubuntu Live. Instalim normal. Vetëm në fazën e zgjedhjes së disqeve për instalim, duhet të specifikoni sa vijon:

  • /dev/md1, - pika e montimit /boot, FS - BTRFS
  • /dev/root/root (aka /dev/mapper/root-root), - pika e montimit / (rrënja), FS - BTRFS
  • /dev/root/swap (a.k.a /dev/mapper/root-swap), - përdoret si ndarje shkëmbimi
  • Instaloni ngarkuesin në /dev/sda

Kur zgjidhni BTRFS si sistemin e skedarëve rrënjë, instaluesi do të krijojë automatikisht dy vëllime BTRFS të quajtura "@" për / (root) dhe "@home" për /home.

Le të fillojmë instalimin ...

Instalimi do të përfundojë me një kuti dialogu modal që tregon një gabim në instalimin e ngarkuesit. Fatkeqësisht, nuk do të mund të dilni nga ky dialog duke përdorur mjete standarde dhe të vazhdoni instalimin. Ne dalim nga sistemi dhe identifikohemi përsëri, duke përfunduar në një desktop të pastër Ubuntu Live. Hapni terminalin dhe përsëri:

#sudo bash

Krijo një mjedis chroot për të vazhduar instalimin:

#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

Le të konfigurojmë rrjetin dhe emrin e hostit në chroot:

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

Le të shkojmë në mjedisin chroot:

#chroot /mnt/chroot

Para së gjithash, ne do të dorëzojmë paketat:

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

Le të kontrollojmë dhe rregullojmë të gjitha paketat që janë instaluar gabimisht për shkak të instalimit jo të plotë të sistemit:

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

Nëse diçka nuk funksionon, mund t'ju duhet së pari të redaktoni /etc/apt/sources.list

Le të rregullojmë parametrat për modulin RAID 6 për të aktivizuar TRIM/HISCARD:

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

Le të shkulim pak vargjet tona:

#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

Çfarë ishte ajo..?Ne kemi krijuar një grup rregullash udev që do të bëjnë sa më poshtë:

  • Vendosni madhësinë e bllokut të cache-it për RAID 2020 të jetë adekuate për vitin 6. Vlera e paracaktuar, duket se nuk ka ndryshuar që nga krijimi i Linux dhe nuk ka qenë adekuate për një kohë të gjatë.
  • Rezervoni një minimum IO për kohëzgjatjen e kontrolleve/sinkronizimeve të grupeve. Kjo është për të parandaluar që vargjet tuaja të ngecin në një gjendje sinkronizimi të përjetshëm nën ngarkesë.
  • Kufizoni IO maksimale gjatë kontrolleve/sinkronizimit të vargjeve. Kjo është e nevojshme në mënyrë që sinkronizimi/kontrollimi i RAID-ve SSD të mos i skuqë disqet tuaja në një gjendje të freskët. Kjo është veçanërisht e vërtetë për NVMe. (Të kujtohet për radiatorin? Nuk po bëja shaka.)
  • Ndaloni disqet të ndalojnë rrotullimin e boshtit (HDD) nëpërmjet APM dhe caktoni kohën e gjumit për kontrollorët e diskut në 7 orë. Mund ta çaktivizoni plotësisht APM nëse disqet tuaja mund ta bëjnë këtë (-B 255). Me vlerën e paracaktuar, disqet do të ndalojnë pas pesë sekondash. Pastaj OS dëshiron të rivendosë cache-në e diskut, disqet do të rrotullohen përsëri dhe gjithçka do të fillojë përsëri. Disqet kanë një numër maksimal të kufizuar të rrotullimeve të gishtit. Një cikël i tillë i thjeshtë i paracaktuar mund të vrasë lehtësisht disqet tuaja në disa vjet. Jo të gjithë disqet vuajnë nga kjo, por disqet tanë janë "laptop", me cilësimet e duhura të paracaktuara, të cilat e bëjnë RAID-in të duket si një mini-MAID.
  • Instaloni leximin në disqe (rrotullues) 1 megabajt - dy blloqe të njëpasnjëshme/copë RAID 6
  • Çaktivizo leximin përpara vetë vargjeve.

Le të modifikojmë /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

Pse eshte ajo..?Ne do të kërkojmë për ndarjen /boot nga UUID. Emërtimi i grupeve teorikisht mund të ndryshojë.

Ne do të kërkojmë për seksionet e mbetura sipas emrave të LVM në shënimin /dev/mapper/vg-lv, sepse ata identifikojnë ndarjet në mënyrë mjaft unike.

Ne nuk përdorim UUID për LVM sepse UUID e vëllimeve LVM dhe fotografitë e tyre mund të jenë të njëjta.Montoni /dev/mapper/root-root.. dy herë?Po. Pikërisht. Veçori e BTRFS. Ky sistem skedari mund të montohet disa herë me nënvole të ndryshme.

Për shkak të kësaj veçorie të njëjtë, unë rekomandoj të mos krijoni kurrë fotografi të LVM të vëllimeve aktive BTRFS. Mund të keni një surprizë kur të rindizni.

Le të rigjenerojmë konfigurimin mdadm:

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

Le të rregullojmë cilësimet e LVM:

#cat >>/etc/lvm/lvmlocal.conf << EOF

activation {
thin_pool_autoextend_threshold=90
thin_pool_autoextend_percent=5
}
allocation {
cache_pool_max_chunks=2097152
}
devices {
global_filter=["r|^/dev/.*_corig$|","r|^/dev/.*_cdata$|","r|^/dev/.*_cmeta$|","r|^/dev/.*gpv$|","r|^/dev/images/.*$|","r|^/dev/mapper/images.*$|","r|^/dev/backup/.*$|","r|^/dev/mapper/backup.*$|"] issue_discards=1
}
EOF

Çfarë ishte ajo..?Ne kemi mundësuar zgjerimin automatik të pishinave të holla LVM me arritjen e 90% të hapësirës së zënë me 5% të volumit.

Ne kemi rritur numrin maksimal të blloqeve të cache-ve për cache LVM.

Ne e kemi penguar LVM të kërkojë vëllime LVM (PV) në:

  • pajisje që përmbajnë cache LVM (cdata)
  • pajisjet e memorizuara duke përdorur cache LVM, duke anashkaluar cache ( _corig). Në këtë rast, vetë pajisja e memorizuar do të skanohet ende përmes memories (vetëm ).
  • pajisjet që përmbajnë meta të dhëna të memories së LVM (cmeta)
  • të gjitha pajisjet në VG me imazhet e emrit. Këtu do të kemi imazhe të diskut të makinave virtuale dhe nuk duam që LVM në host të aktivizojë vëllimet që i përkasin sistemit operativ të ftuar.
  • të gjitha pajisjet në VG me emrin rezervë. Këtu do të kemi kopje rezervë të imazheve të makinës virtuale.
  • të gjitha pajisjet, emri i të cilave përfundon me "gpv" (vëllimi fizik i mysafirëve)

Ne kemi aktivizuar mbështetjen HISCARD kur liron hapësirë ​​të lirë në LVM VG. Bej kujdes. Kjo do ta bëjë fshirjen e LV-ve në SSD mjaft kohë. Kjo vlen veçanërisht për SSD RAID 6. Megjithatë, sipas planit, ne do të përdorim provizionim të hollë, kështu që kjo nuk do të na pengojë aspak.

Le të përditësojmë imazhin e initramfs:

#update-initramfs -u -k all

Instaloni dhe konfiguroni grub-in:

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

Cilat disqe të zgjidhni?Të gjithë ata që janë sd*. Sistemi duhet të jetë në gjendje të niset nga çdo disk SATA ose SSD që funksionon.

Pse shtuan os-prober..?Për pavarësi të tepruar dhe duar lozonjare.

Nuk funksionon siç duhet nëse një nga RAID-et është në gjendje të degraduar. Ai përpiqet të kërkojë për OS në ndarjet që përdoren në makinat virtuale që funksionojnë në këtë pajisje.

Nëse ju nevojitet, mund ta lini, por mbani parasysh të gjitha sa më sipër. Unë rekomandoj të kërkoni receta për të hequr qafe duart e këqija në internet.

Me këtë kemi përfunduar instalimin fillestar. Është koha për të rindezur në sistemin operativ të sapo instaluar. Mos harroni të hiqni CD/USB-në Live bootable.

#exit
#reboot

Zgjidhni ndonjë nga SATA SSD si pajisjen e nisjes.

LVM në SATA SSD

Në këtë pikë, ne kemi nisur tashmë në sistemin operativ të ri, kemi konfiguruar rrjetin, apt, kemi hapur emulatorin e terminalit dhe kemi nisur:

#sudo bash

Le te vazhdojme.

"Inicializoni" grupin nga SATA SSD:

#blkdiscard /dev/md2

Nëse nuk funksionon, atëherë provoni:

#blkdiscard --step 65536 /dev/md2
Krijoni LVM VG në SATA SSD:

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

Pse një tjetër VG..?Në fakt, ne tashmë kemi një VG të quajtur rrënjë. Pse të mos shtoni gjithçka në një VG?

Nëse ka disa PV në një VG, atëherë që VG të aktivizohet saktë, të gjitha PV-të duhet të jenë të pranishme (online). Përjashtim është LVM RAID, të cilin ne nuk e përdorim qëllimisht.

Ne vërtet duam që nëse ka një dështim (humbje të të dhënave të lexuara) në ndonjë nga grupet RAID 6, sistemi operativ të niset normalisht dhe të na japë mundësinë për të zgjidhur problemin.

Për ta bërë këtë, në nivelin e parë të abstraksionit ne do të izolojmë çdo lloj "media" fizike në një VG të veçantë.

Duke folur shkencërisht, grupe të ndryshme RAID i përkasin "domeneve të besueshmërisë" të ndryshme. Ju nuk duhet të krijoni një pikë shtesë të përbashkët dështimi për ta duke i grumbulluar në një VG.

Prania e LVM në nivelin "hardware" do të na lejojë të presim në mënyrë arbitrare pjesë të grupeve të ndryshme RAID duke i kombinuar ato në mënyra të ndryshme. Për shembull - vraponi njëherësh bcache + LVM i hollë, bcache + BTRFS, LVM cache + LVM i hollë, një konfigurim kompleks ZFS me cache, ose ndonjë përzierje tjetër djallëzore për të provuar dhe krahasuar të gjitha.

Në nivelin "hardware", ne nuk do të përdorim asgjë tjetër përveç vëllimeve të mira të vjetra "të trasha" LVM. Përjashtim nga ky rregull mund të jetë ndarja rezervë.

Unë mendoj se në këtë moment, shumë lexues kishin filluar të dyshonin për diçka në lidhje me kukullën fole.

LVM në SATA HDD

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

Përsëri VG e re..?Ne duam vërtet që nëse grupi i diskut që do të përdorim për kopjimin e të dhënave dështon, sistemi ynë operativ të vazhdojë të funksionojë normalisht, duke ruajtur aksesin në të dhënat jo rezervë si zakonisht. Prandaj, për të shmangur problemet e aktivizimit të VG, ne krijojmë një VG të veçantë.

Vendosja e cache LVM

Le të krijojmë një LV në NVMe RAID 1 për ta përdorur atë si një pajisje memorie.

#lvcreate -L 70871154688B --name cache root

Pse ka kaq pak...?Fakti është se SSD-të tona NVMe kanë gjithashtu një cache SLC. 4 gigabajt "falas" dhe 18 gigabajt dinamike për shkak të hapësirës së lirë të zënë në MLC 3-bit. Pasi të shterohet kjo memorie, SSD-të NVMe nuk do të jenë shumë më të shpejtë se sa SATA SSD-ja jonë me cache. Në fakt, për këtë arsye, nuk ka kuptim që ne ta bëjmë ndarjen e cache LVM shumë më të madhe se dyfishi i madhësisë së cache SLC të diskut NVMe. Për disqet NVMe të përdorura, autori e konsideron të arsyeshme krijimin e 32-64 gigabajt cache.

Madhësia e caktuar e ndarjes kërkohet për të organizuar 64 gigabajt cache, metadata cache dhe rezervë të meta të dhënave.

Për më tepër, vërej se pas një mbylljeje të sistemit të ndotur, LVM do të shënojë të gjithë cache-në si të ndotur dhe do të sinkronizohet përsëri. Për më tepër, kjo do të përsëritet sa herë që përdoret lvchange në këtë pajisje derisa sistemi të rindizet përsëri. Prandaj, unë rekomandoj që menjëherë të rikrijoni cache duke përdorur skriptin e duhur.

Le të krijojmë një LV në SATA RAID 6 për ta përdorur atë si një pajisje të memorizuar.

#lvcreate -L 3298543271936B --name cache data

Pse vetëm tre terabajt..?Kështu që, nëse është e nevojshme, mund të përdorni SATA SSD RAID 6 për disa nevoja të tjera. Madhësia e hapësirës së memories mund të rritet në mënyrë dinamike, në fluturim, pa ndalur sistemin. Për ta bërë këtë, ju duhet të ndaloni përkohësisht dhe të riaktivizoni cache, por përparësia dalluese e LVM-cache mbi, për shembull, bcache është se kjo mund të bëhet menjëherë.

Le të krijojmë një VG të re për caching.

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

Le të krijojmë një LV në pajisjen e memorizuar.

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

Këtu kemi zënë menjëherë të gjithë hapësirën e lirë në /dev/data/cache në mënyrë që të gjitha ndarjet e tjera të nevojshme të krijohen menjëherë në /dev/root/cache. Nëse keni krijuar diçka në vendin e gabuar, mund ta zhvendosni duke përdorur pvmove.

Le të krijojmë dhe aktivizojmë cache:

#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

Pse kaq chunksize..?Përmes eksperimenteve praktike, autori ishte në gjendje të zbulonte se rezultati më i mirë arrihet nëse madhësia e bllokut të cache LVM përkon me madhësinë e bllokut të hollë LVM. Për më tepër, sa më e vogël të jetë madhësia, aq më mirë funksionon konfigurimi në një regjistrim të rastësishëm.

64k është madhësia minimale e bllokut të lejuar për LVM të hollë.

Kini kujdes me shkruani..!Po. Ky lloj cache shtyn sinkronizimin e shkrimit në pajisjen e memorizuar. Kjo do të thotë që nëse cache humbet, ju mund të humbni të dhënat në pajisjen e memorizuar. Më vonë, autori do t'ju tregojë se çfarë masash, përveç NVMe RAID 1, mund të merren për të kompensuar këtë rrezik.

Ky lloj i cache-it u zgjodh qëllimisht për të kompensuar performancën e dobët të shkrimit të rastësishëm të RAID 6.

Le të kontrollojmë se çfarë kemi:

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

Vetëm [cachedata_corig] duhet të gjendet në /dev/data/cache. Nëse diçka nuk është në rregull, atëherë përdorni pvmove.

Mund ta çaktivizoni cache-në nëse është e nevojshme me një komandë:

#lvconvert -y --uncache cache/cachedata

Kjo bëhet on-line. LVM thjesht do të sinkronizojë cache-në në disk, do ta heqë atë dhe do ta riemërojë cachedata_corig përsëri në cachedata.

Konfigurimi i LVM të hollë

Le të vlerësojmë përafërsisht se sa hapësirë ​​na nevojitet për meta të dhënat e hollë LVM:

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

Rrumbullakosni deri në 4 gigabajt: 4294967296B

Shumëzojeni me dy dhe shtoni 4194304B për metadatat LVM PV: 8594128896B
Le të krijojmë një ndarje të veçantë në NVMe RAID 1 për të vendosur metadatat e hollë LVM dhe kopjen e tyre rezervë në të:

#lvcreate -L 8594128896B --name images root

Per cfare..?Këtu mund të lindë pyetja: pse t'i vendosni veçmas të dhënat e hollë të LVM nëse ato do të ruhen ende në memorien e fshehtë në NVMe dhe do të funksionojnë shpejt.

Edhe pse shpejtësia është e rëndësishme këtu, ajo është larg nga arsyeja kryesore. Puna është se cache është një pikë dështimi. Diçka mund të ndodhë me të dhe nëse meta të dhënat e hollë të LVM ruhen në memorien specifike, kjo do të bëjë që gjithçka të humbasë plotësisht. Pa meta të dhëna të plota, do të jetë pothuajse e pamundur të mblidhen vëllime të hollë.

Duke i zhvendosur meta të dhënat në një vëllim të veçantë jo të ruajtur në memorie, por të shpejtë, ne garantojmë sigurinë e meta të dhënave në rast të humbjes ose korrupsionit të meta të dhënave. Në këtë rast, të gjitha dëmtimet e shkaktuara nga humbja e cache-it do të lokalizohen brenda vëllimeve të hollë, gjë që do të thjeshtojë procedurën e rikuperimit me urdhra të madhësisë. Me një probabilitet të lartë, këto dëmtime do të rikthehen duke përdorur regjistrat FS.

Për më tepër, nëse më parë është marrë një fotografi e një vëllimi të hollë dhe pas kësaj cache është sinkronizuar plotësisht të paktën një herë, atëherë, për shkak të dizajnit të brendshëm të LVM thin, integriteti i fotografisë do të garantohet në rast të humbjes së cache .

Le të krijojmë një VG të re që do të jetë përgjegjëse për sigurimin e hollë:

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

Le të krijojmë një pishinë:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Pse -Z yPërveç asaj për çfarë synohet në të vërtetë kjo mënyrë - për të parandaluar rrjedhjen e të dhënave nga një makinë virtuale në një makinë tjetër virtuale kur rishpërndahet hapësira - zeroimi përdoret gjithashtu për të rritur shpejtësinë e shkrimit të rastësishëm në blloqe më të vogla se 64k. Çdo shkrim më pak se 64k në një zonë të pacaktuar më parë të volumit të hollë do të bëhet 64K e rreshtuar me skajet në cache. Kjo do të lejojë që operacioni të kryhet tërësisht përmes cache-it, duke anashkaluar pajisjen e memorizuar.

Le t'i zhvendosim LV-të në PV-të përkatëse:

#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

Le të kontrollojmë:

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

Le të krijojmë një vëllim të hollë për testet:

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

Ne do të instalojmë paketa për teste dhe monitorim:

#apt-get install sysstat fio

Kështu mund të vëzhgoni sjelljen e konfigurimit tonë të ruajtjes në kohë reale:

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

Kështu mund të testojmë konfigurimin tonë:

#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

Me kujdes! Burim!Ky kod do të ekzekutojë 36 teste të ndryshme, secili prej 4 sekondash. Gjysma e testeve janë për regjistrim. Mund të regjistroni shumë në NVMe në 4 sekonda. Deri në 3 gigabajt në sekondë. Pra, çdo ekzekutim i testeve të shkrimit mund të hajë deri në 216 gigabajt burim SSD nga ju.

Leximi dhe shkrimi i përzier?Po. Ka kuptim që testet e leximit dhe të shkrimit të ekzekutohen veçmas. Për më tepër, ka kuptim të sigurohet që të gjitha cache të sinkronizohen në mënyrë që një shkrim i bërë më parë të mos ndikojë në leximin.

Rezultatet do të ndryshojnë shumë gjatë nisjes së parë dhe atyre të mëvonshme kur mbushja e memories dhe vëllimi i hollë mbushet, dhe gjithashtu në varësi të faktit nëse sistemi arriti të sinkronizojë memoriet e mbushura gjatë lëshimit të fundit.

Ndër të tjera, unë rekomandoj matjen e shpejtësisë në një vëllim tashmë të plotë të hollë nga i cili sapo është marrë një fotografi. Autori pati mundësinë të vëzhgonte se si shkrimet e rastësishme përshpejtohen ndjeshëm menjëherë pas krijimit të fotografisë së parë, veçanërisht kur cache nuk është ende plotësisht e plotë. Kjo ndodh për shkak të semantikës së shkrimit të kopjimit në shkrim, shtrirjes së cache-së dhe blloqeve të volumit të hollë, dhe faktit që një shkrim i rastësishëm në RAID 6 kthehet në një lexim të rastësishëm nga RAID 6 i ndjekur nga një shkrim në cache. Në konfigurimin tonë, leximi i rastësishëm nga RAID 6 është deri në 6 herë (numri i SATA SSD në grup) më i shpejtë se shkrimi. Sepse blloqet për CoW ndahen në mënyrë sekuenciale nga një pishinë e hollë, pastaj regjistrimi, në pjesën më të madhe, shndërrohet gjithashtu në sekuencial.

Të dyja këto veçori mund të përdoren në avantazhin tuaj.

Fotot e çastit "koherente" në memorie

Për të reduktuar rrezikun e humbjes së të dhënave në rast të dëmtimit/humbjes së cache-it, autori propozon të prezantohet praktika e rrotullimit të fotografive për të garantuar integritetin e tyre në këtë rast.

Së pari, për shkak se të dhënat meta të volumit të hollë qëndrojnë në një pajisje të pakapshme, meta të dhënat do të jenë të qëndrueshme dhe humbjet e mundshme do të izolohen brenda blloqeve të të dhënave.

Cikli i mëposhtëm i rrotullimit të fotografive garanton integritetin e të dhënave brenda fotografive në rast të humbjes së cache-it:

  1. Për çdo vëllim të hollë me emrin <emri>, krijoni një fotografi me emrin <emri>.cached
  2. Le ta vendosim pragun e migrimit në një vlerë të arsyeshme të lartë: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Në lak kontrollojmë numrin e blloqeve të pista në cache: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' derisa të marrim zero. Nëse zero mungon për një kohë të gjatë, ajo mund të krijohet duke kaluar përkohësisht cache në modalitetin e shkrimit. Sidoqoftë, duke marrë parasysh karakteristikat e shpejtësisë së grupeve tona SSD SATA dhe NVMe, si dhe burimin e tyre TBW, ose do të jeni në gjendje të kapni shpejt momentin pa ndryshuar modalitetin e cache-it, ose pajisja juaj do të hajë plotësisht të gjithë burimin e tij në pak ditë. Për shkak të kufizimeve të burimeve, sistemi, në parim, nuk mund të jetë nën ngarkesën 100% të shkrimit gjatë gjithë kohës. SSD-të tona NVMe nën ngarkesën 100% të shkrimit do të shterojnë plotësisht burimin ditë 3 4-. SSD-të SATA do të zgjasin vetëm dy herë më shumë. Prandaj, do të supozojmë se pjesa më e madhe e ngarkesës shkon në lexim, dhe kemi shpërthime relativisht afatshkurtra të aktivitetit jashtëzakonisht të lartë të kombinuar me një ngarkesë të ulët mesatarisht për të shkruar.
  4. Sapo kapëm (ose bëmë) një zero, ne riemërtojmë .cached në .committed. E vjetër .committed fshihet.
  5. Opsionale, nëse cache është 100% e mbushur, ajo mund të rikrijohet nga një skript, duke e pastruar atë. Me një cache gjysmë të zbrazët, sistemi funksionon shumë më shpejt kur shkruan.
  6. Vendosni pragun e migrimit në zero: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Kjo do të parandalojë përkohësisht sinkronizimin e cache me median kryesore.
  7. Ne presim derisa të grumbullohen shumë ndryshime në cache #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' ose kohëmatësi do të fiket.
  8. E përsërisim përsëri.

Pse vështirësi me pragun e migrimit...?Gjë është se në praktikën reale, një regjistrim "i rastësishëm" në fakt nuk është plotësisht i rastësishëm. Nëse i shkruajmë diçka një sektori me madhësi 4 kilobajtë, ka një probabilitet të lartë që në dy minutat e ardhshme të bëhet një regjistrim në të njëjtin ose një nga sektorët fqinjë (+- 32K).

Duke vendosur pragun e migrimit në zero, ne shtyjmë sinkronizimin e shkrimit në SATA SSD dhe grumbullojmë disa ndryshime në një bllok 64K në cache. Kjo kursen ndjeshëm burimin e SATA SSD.

Ku eshte kodi..?Për fat të keq, autori e konsideron veten të pamjaftueshëm në zhvillimin e skripteve bash sepse ai është 100% autodidakt dhe praktikon zhvillimin e drejtuar nga "google", prandaj ai beson se kodi i tmerrshëm që i del nga duart nuk duhet të përdoret nga askush. tjetër.

Unë mendoj se profesionistët në këtë fushë do të jenë në gjendje të përshkruajnë në mënyrë të pavarur të gjithë logjikën e përshkruar më sipër, nëse është e nevojshme, dhe, ndoshta, edhe ta dizajnojnë bukur atë si një shërbim të sistemuar, siç u përpoq të bënte autori.

Një skemë e tillë e thjeshtë e rrotullimit të fotografive do të na lejojë jo vetëm që vazhdimisht të kemi një fotografi të sinkronizuar plotësisht në SATA SSD, por gjithashtu do të na lejojë, duke përdorur mjetin thin_delta, të zbulojmë se cilët blloqe janë ndryshuar pas krijimit të tij, dhe kështu të lokalizojmë dëmet në vëllimet kryesore, duke thjeshtuar shumë rikuperimin.

PRIM/HIQI në libvirt/KVM

Sepse ruajtja e të dhënave do të përdoret për ekzekutimin e libvirt të KVM, atëherë do të ishte një ide e mirë t'i mësojmë VM-të tona jo vetëm të zënë hapësirë ​​të lirë, por edhe të çlirojnë atë që nuk nevojitet më.

Kjo bëhet duke emuluar mbështetjen TRIM/DISCARD në disqet virtuale. Për ta bërë këtë, ju duhet të ndryshoni llojin e kontrolluesit në virtio-scsi dhe të modifikoni 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>

Të tilla HEQJE nga OS-të e ftuar përpunohen në mënyrë korrekte nga LVM dhe blloqet lirohen si duhet si në cache ashtu edhe në grupin e hollë. Në rastin tonë, kjo ndodh kryesisht në mënyrë të vonuar, kur fshihet fotografia e ardhshme.

Rezervimi i BTRFS

Përdorni skriptet e gatshme me ekstreme kujdes dhe me rrezikun e vet. Këtë kod autori e ka shkruar vetë dhe ekskluzivisht për vete. Jam i sigurt se shumë përdorues me përvojë të Linux kanë mjete të ngjashme dhe nuk ka nevojë të kopjoni ato të dikujt tjetër.

Le të krijojmë një vëllim në pajisjen rezervë:

#lvcreate -L 256G --name backup backup

Le ta formatojmë në BTRFS:

#mkfs.btrfs /dev/backup/backup

Le të krijojmë pika montimi dhe montojmë nënseksionet rrënjë të sistemit të skedarëve:

#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

Le të krijojmë drejtori për kopje rezervë:

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

Le të krijojmë një direktori për skriptet rezervë:

#mkdir /root/btrfs-backup

Le të kopjojmë skenarin:

Shumë kod të frikshëm bash. Përdoreni në rrezikun tuaj. Mos i shkruani letra të zemëruara autorit...#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

Madje çfarë bën..?Përmban një sërë komandash të thjeshta për krijimin e fotografive BTRFS dhe kopjimin e tyre në një FS tjetër duke përdorur BTRFS send/recieve.

Nisja e parë mund të jetë relativisht e gjatë, sepse... Në fillim, të gjitha të dhënat do të kopjohen. Lansimet e mëtejshme do të jenë shumë të shpejta, sepse... Vetëm ndryshimet do të kopjohen.

Një tjetër skenar që do ta vendosim në cron:

Pak më shumë kod bash#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

Çfarë bën..?Krijon dhe sinkronizon fotografitë shtesë të vëllimeve të listuara BTRFS në FS rezervë. Pas kësaj, fshin të gjitha fotografitë e krijuara 60 ditë më parë. Pas nisjes, fotografitë me datë të vëllimeve të listuara do të shfaqen në nëndrejtoritë /backup/btrfs/back/remote/.

Le t'i japim të drejtat e ekzekutimit të kodit:

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

Le ta kontrollojmë dhe ta vendosim në kronikë:

#/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 rezervë e hollë

Le të krijojmë një pishinë të hollë në pajisjen rezervë:

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

Le të instalojmë ddrescue, sepse... skriptet do të përdorin këtë mjet:

#apt-get install gddrescue

Le të krijojmë një drejtori për skriptet:

#mkdir /root/lvm-thin-backup

Le të kopjojmë skriptet:

Shumë zhurmë brenda...#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

Çfarë bën...?Përmban një grup komandash për manipulimin e fotografive të holla dhe sinkronizimin e diferencës midis dy fotografive të holla të marra nëpërmjet thin_delta në një pajisje tjetër bllok duke përdorur ddrescue dhe blkdiscard.

Një tjetër skenar që do të vendosim në cron:

Edhe pak bash#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

Çfarë bën...?Përdor skriptin e mëparshëm për të krijuar dhe sinkronizuar kopje rezervë të vëllimeve të hollë të listuara. Skripti do të lërë fotografi joaktive të vëllimeve të listuara, të cilat nevojiten për të gjurmuar ndryshimet që nga sinkronizimi i fundit.

Ky skenar duhet të modifikohet, duke specifikuar listën e vëllimeve të hollë për të cilat duhen bërë kopje rezervë. Emrat e dhënë janë vetëm për qëllime ilustruese. Nëse dëshironi, mund të shkruani një skenar që do të sinkronizojë të gjitha vëllimet.

Le të japim të drejtat:

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

Le ta kontrollojmë dhe ta vendosim në kronikë:

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

Nisja e parë do të jetë e gjatë, sepse... vëllimet e hollë do të sinkronizohen plotësisht duke kopjuar të gjithë hapësirën e përdorur. Falë meta të dhënave të hollë LVM, ne e dimë se cilët blloqe janë në të vërtetë në përdorim, kështu që vetëm blloqet e volumit të hollë të përdorur në të vërtetë do të kopjohen.

Ekzekutimet e mëvonshme do t'i kopjojnë të dhënat në mënyrë shtesë falë gjurmimit të ndryshimit nëpërmjet meta të dhënave të hollë LVM.

Le të shohim se çfarë ndodhi:

#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

Çfarë lidhje ka kjo me kukullat fole?

Me shumë mundësi, duke pasur parasysh se vëllimet logjike LVM LV mund të jenë vëllime fizike LVM PV për VG të tjera. LVM mund të jetë rekurzive, si kukulla fole. Kjo i jep LVM fleksibilitet ekstrem.

PS

Në artikullin vijues, do të përpiqemi të përdorim disa sisteme të ngjashme të ruajtjes celulare/KVM si bazë për krijimin e një grupi ruajtjeje/vm të shpërndarë gjeo-shpërndarë me tepricë në disa kontinente duke përdorur desktopët e shtëpisë, internetin në shtëpi dhe rrjetet P2P.

Burimi: www.habr.com

Shto një koment