Wat hebben LVM en Matryoshka gemeen?

Goedendag.
Ik wil graag mijn praktische ervaring met het bouwen van een gegevensopslagsysteem voor KVM met de gemeenschap delen met behulp van md RAID + LVM.

Het programma omvat:

  • MD RAID 1 bouwen vanaf NVMe SSD.
  • Md RAID 6 samenstellen vanaf SATA SSD en gewone schijven.
  • Kenmerken van TRIM/DISCARD-werking op SSD RAID 1/6.
  • Een opstartbare md RAID 1/6-array maken op een gemeenschappelijke set schijven.
  • Het systeem installeren op NVMe RAID 1 als er geen NVMe-ondersteuning in het BIOS is.
  • Met behulp van LVM-cache en LVM thin.
  • BTRFS-snapshots gebruiken en verzenden/ontvangen voor back-up.
  • Gebruik van LVM thin snapshots en thin_delta voor back-ups in BTRFS-stijl.

Als u geïnteresseerd bent, zie cat.

Verklaring

De auteur draagt ​​geen enkele verantwoordelijkheid voor de gevolgen van het wel of niet gebruiken van materialen/voorbeelden/code/tips/gegevens uit dit artikel. Door dit materiaal op welke manier dan ook te lezen of te gebruiken, aanvaardt u de verantwoordelijkheid voor alle gevolgen van deze acties. Mogelijke gevolgen zijn onder meer:

  • Krokant gebakken NVMe SSD's.
  • Volledig opgebruikte opnamebronnen en uitval van SSD-schijven.
  • Volledig verlies van alle gegevens op alle schijven, inclusief back-ups.
  • Defecte computerhardware.
  • Verspilde tijd, zenuwen en geld.
  • Eventuele andere gevolgen die hierboven niet zijn vermeld.

ijzer

Beschikbaar waren:

Moederbord uit ca. 2013 met Z87 chipset, compleet met Intel Core i7/Haswell.

  • Processor 4 cores, 8 threads
  • 32 GB DDR3-RAM
  • 1 x 16 of 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3-connectoren

SAS-adapter LSI SAS9211-8I flitste naar IT/HBA-modus. Voor RAID geschikte firmware is opzettelijk vervangen door HBA-firmware om:

  1. U kunt deze adapter op elk moment weggooien en vervangen door een andere die u tegenkomt.
  2. TRIM/Discard werkte normaal op schijven, omdat... in RAID-firmware worden deze opdrachten helemaal niet ondersteund, en het maakt de HBA in het algemeen niet uit welke opdrachten via de bus worden verzonden.

Harde schijven - 8 stuks HGST Travelstar 7K1000 met een capaciteit van 1 TB in een 2.5-vormfactor, zoals voor laptops. Deze schijven bevonden zich voorheen in een RAID 6-array. Ze zullen ook van pas komen in het nieuwe systeem. Om lokale back-ups op te slaan.

Bovendien toegevoegd:

6 stuks SATA SSD model Samsung 860 QVO 2TB. Deze SSD's vereisten een groot volume, de aanwezigheid van een SLC-cache, betrouwbaarheid en een lage prijs waren gewenst. Ondersteuning voor throw/zero was vereist, wat wordt gecontroleerd door de regel in dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

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

Voor deze SSD's zijn willekeurige lees-/schrijfsnelheid en resourcecapaciteit voor uw behoeften belangrijk. Radiator voor hen. Nodig. Absoluut. Anders bakt u ze knapperig tijdens de eerste RAID-synchronisatie.

StarTech PEX8M2E2-adapter voor 2 x NVMe SSD geïnstalleerd in PCIe 3.0 8x-slot. Dit is wederom slechts een HBA, maar dan voor NVMe. Het verschilt van goedkope adapters doordat het geen PCIe-bifurcatie-ondersteuning van het moederbord vereist vanwege de aanwezigheid van een ingebouwde PCIe-switch. Het werkt zelfs in het oudste systeem met PCIe, zelfs als het een x1 PCIe 1.0-slot is. Uiteraard met de juiste snelheid. Er zijn daar geen RAID's. Er is geen ingebouwd BIOS aan boord. Uw systeem zal dus niet op magische wijze leren opstarten met NVMe, laat staan ​​NVMe RAID dankzij dit apparaat.

Dit onderdeel was uitsluitend te danken aan de aanwezigheid van slechts één gratis 8x PCIe 3.0 in het systeem, en als er 2 vrije slots zijn, kan deze eenvoudig worden vervangen door twee cent PEX4M2E1 of analogen, die overal te koop zijn voor een prijs van 600 roebel.

Het afwijzen van allerlei hardware of ingebouwde chipset/BIOS RAID's is bewust gedaan, om het gehele systeem, met uitzondering van de SSD/HDD zelf, volledig te kunnen vervangen met behoud van alle data. Idealiter zodat u zelfs het geïnstalleerde besturingssysteem kunt opslaan als u overstapt op geheel nieuwe/andere hardware. Het belangrijkste is dat er SATA- en PCIe-poorten zijn. Het is als een live-cd of een opstartbare flashdrive, alleen erg snel en een beetje omvangrijk.

ЮморAnders weet je wat er gebeurt - soms moet je dringend de hele array meenemen om mee te nemen. Maar ik wil geen gegevens verliezen. Om dit te doen, zijn alle genoemde media handig op de dia's in de 5.25-bays van de standaardbehuizing geplaatst.

Nou ja, en natuurlijk voor het experimenteren met verschillende methoden voor SSD-caching in Linux.

Hardware-invallen zijn saai. Zet het aan. Het werkt of het werkt niet. En bij mdadm zijn er altijd opties.

zacht

Voorheen werd Debian 8 Jessie op de hardware geïnstalleerd, wat bijna EOL is. RAID 6 werd samengesteld uit de bovengenoemde HDD's gecombineerd met LVM. Het draaide virtuele machines in kvm/libvirt.

Omdat De auteur heeft voldoende ervaring met het maken van draagbare, opstartbare SATA/NVMe-flashdrives, en om de gebruikelijke apt-sjabloon niet te doorbreken, werd Ubuntu 18.04 gekozen als doelsysteem, dat al voldoende gestabiliseerd is, maar nog steeds 3 jaar aan ervaring heeft. ondersteuning in de toekomst.

Het genoemde systeem bevat standaard alle hardwaredrivers die we nodig hebben. We hebben geen software of stuurprogramma's van derden nodig.

Voorbereiden voor installatie

Om het systeem te installeren hebben we Ubuntu Desktop Image nodig. Het serversysteem heeft een soort krachtig installatieprogramma, dat blijk geeft van een buitensporige onafhankelijkheid die niet kan worden uitgeschakeld door de UEFI-systeempartitie op een van de schijven te schuiven, waardoor al het moois wordt verpest. Dienovereenkomstig wordt het alleen in de UEFI-modus geïnstalleerd. Biedt geen opties.

Wij zijn hier niet blij mee.

Waarom?Helaas is UEFI-opstarten extreem slecht compatibel met opstartsoftware RAID, omdat... Niemand biedt ons reserveringen aan voor de UEFI ESP-partitie. Er zijn online recepten die suggereren om de ESP-partitie op een flashstation in een USB-poort te plaatsen, maar dit is een mislukking. Er zijn recepten die de software mdadm RAID 1 gebruiken met metadataversie 0.9 die niet voorkomen dat het UEFI BIOS deze partitie ziet, maar dit blijft bestaan ​​tot het gelukkige moment waarop het BIOS of een ander hardware-besturingssysteem iets naar de ESP schrijft en vergeet het met andere te synchroniseren spiegels.

Bovendien is het opstarten van UEFI afhankelijk van NVRAM, dat niet meegaat met de schijven naar het nieuwe systeem, omdat maakt deel uit van het moederbord.

We gaan dus geen nieuw wiel uitvinden. We hebben al een kant-en-klare, beproefde grootvaderfiets, nu Legacy/BIOS-boot genoemd, met de trotse naam CSM op UEFI-compatibele systemen. We halen hem gewoon uit de kast, smeren hem, pompen de banden op en vegen hem af met een vochtige doek.

De desktopversie van Ubuntu kan ook niet correct worden geïnstalleerd met de Legacy-bootloader, maar hier zijn, zoals ze zeggen, tenminste opties.

En dus verzamelen we de hardware en laden we het systeem vanaf de opstartbare Ubuntu Live-flashdrive. We moeten pakketten downloaden, dus we zullen het netwerk opzetten dat voor u werkt. Als het niet werkt, kunt u de benodigde pakketten vooraf op een flashstation laden.

We gaan naar de desktopomgeving, starten de terminalemulator en daar gaan we:

#sudo bash

Hoe…?De regel hierboven is de canonieke trigger voor holiwars over sudo. C bоgrotere kansen komen enоgrotere verantwoordelijkheid. De vraag is of je het zelf aankunt. Veel mensen denken dat het op deze manier gebruiken van sudo in ieder geval niet voorzichtig is. Echter:

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

Waarom niet ZFS...?Wanneer we software op onze computer installeren, lenen we in wezen onze hardware uit aan de ontwikkelaars van deze software om deze aan te sturen.
Wanneer we de veiligheid van onze gegevens aan deze software toevertrouwen, gaan we een lening aan die gelijk is aan de kosten voor het herstellen van deze gegevens, die we op een dag zullen moeten afbetalen.

Vanuit dit oogpunt is ZFS een Ferrari, en lijkt mdadm+lvm meer op een fiets.

Subjectief gezien geeft de auteur er de voorkeur aan om een ​​fiets op krediet uit te lenen aan onbekende personen in plaats van een Ferrari. Daar is de prijs van de uitgifte niet hoog. Geen behoefte aan rechten. Simpeler dan verkeersregels. Parkeren is gratis. Cross-country vermogen is beter. Je kunt altijd poten aan een fiets bevestigen en je kunt een fiets met je eigen handen repareren.

Waarom dan BTRFS...?Om het besturingssysteem op te starten, hebben we een bestandssysteem nodig dat standaard wordt ondersteund in Legacy/BIOS GRUB en tegelijkertijd live snapshots ondersteunt. We zullen het gebruiken voor de /boot partitie. Bovendien geeft de auteur er de voorkeur aan om deze FS te gebruiken voor / (root), en niet te vergeten dat je voor elke andere software aparte partities op LVM kunt maken en deze in de benodigde mappen kunt mounten.

We zullen geen afbeeldingen van virtuele machines of databases op deze FS opslaan.
Deze FS wordt alleen gebruikt om snapshots van het systeem te maken zonder het uit te schakelen en deze snapshots vervolgens over te dragen naar een back-upschijf met behulp van verzenden/ontvangen.

Bovendien geeft de auteur er over het algemeen de voorkeur aan om een ​​minimum aan software direct op de hardware te houden en alle andere software op virtuele machines te laten draaien, met behulp van zaken als het doorsturen van GPU's en PCI-USB Host-controllers naar KVM via IOMMU.

Het enige wat nog op de hardware staat zijn dataopslag, virtualisatie en back-up.

Als u ZFS meer vertrouwt, zijn ze in principe voor de opgegeven toepassing uitwisselbaar.

De auteur negeert echter opzettelijk de ingebouwde mirroring/RAID- en redundantiefuncties die ZFS, BRTFS en LVM hebben.

Als bijkomend argument heeft BTRFS de mogelijkheid om willekeurige schrijfbewerkingen om te zetten in sequentiële schrijfbewerkingen, wat een extreem positief effect heeft op de snelheid van het synchroniseren van snapshots/back-ups op de harde schijf.

Laten we alle apparaten opnieuw scannen:

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

Laten we eens rondkijken:

#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

Schijfindeling

NVMe SSD

Maar we zullen ze op geen enkele manier markeren. Toch ziet ons BIOS deze schijven niet. Ze gaan dus volledig over op software-RAID. We zullen daar niet eens secties maken. Als je de ‘canon’ of ‘principieel’ wilt volgen, maak dan één grote partitie aan, zoals een HDD.

SATA HDD

Het is niet nodig om hier iets speciaals te bedenken. We maken voor alles één sectie. We zullen een partitie maken omdat het BIOS deze schijven ziet en mogelijk zelfs probeert ervan op te starten. We zullen GRUB later zelfs op deze schijven installeren, zodat het systeem dit ineens kan doen.

#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

Dit is waar het voor ons interessant wordt.

Ten eerste zijn onze schijven 2 TB groot. Dit ligt binnen het acceptabele bereik voor MBR, wat we zullen gebruiken. Indien nodig kan het worden vervangen door GPT. GPT-schijven hebben een compatibiliteitslaag waarmee MBR-compatibele systemen de eerste 4 partities kunnen zien als deze zich binnen de eerste 2 terabytes bevinden. Het belangrijkste is dat de opstartpartitie en de bios_grub-partitie op deze schijven aan het begin moeten staan. Hierdoor kunt u zelfs opstarten vanaf GPT Legacy/BIOS-schijven.

Maar dit is niet ons geval.

Hier zullen we twee secties maken. De eerste is 1 GB groot en wordt gebruikt voor RAID 1 /boot.

De tweede wordt gebruikt voor RAID 6 en neemt alle resterende vrije ruimte in beslag, met uitzondering van een klein niet-toegewezen gebied aan het einde van de schijf.

Wat is dit ongemarkeerde gebied?Volgens bronnen op het netwerk hebben onze SATA SSD's een dynamisch uitbreidbare SLC-cache aan boord, variërend in grootte van 6 tot 78 gigabyte. We krijgen 6 gigabytes “gratis” vanwege het verschil tussen “gigabytes” en “gibibytes” in het gegevensblad van de schijf. De overige 72 gigabytes worden toegewezen uit ongebruikte ruimte.

Hier moet worden opgemerkt dat we een SLC-cache hebben en dat de ruimte bezet is in de 4-bits MLC-modus. Wat voor ons feitelijk betekent dat we voor elke 4 gigabyte vrije ruimte slechts 1 gigabyte SLC-cache krijgen.

Vermenigvuldig 72 gigabyte met 4 en krijg 288 gigabyte. Dit is de vrije ruimte die we niet zullen markeren, zodat de schijven volledig gebruik kunnen maken van de SLC-cache.

We halen dus effectief tot 312 gigabyte aan SLC-cache uit een totaal van zes schijven. Van alle schijven worden er 2 in RAID gebruikt voor redundantie.

Met deze hoeveelheid cache kunnen we in het echte leven uiterst zelden een situatie tegenkomen waarin een schrijfbewerking niet naar de cache gaat. Dit compenseert buitengewoon goed het treurigste nadeel van QLC-geheugen: de extreem lage schrijfsnelheid wanneer gegevens worden geschreven zonder de cache te omzeilen. Komen je belastingen hier niet mee overeen, dan raad ik je aan goed na te denken over hoe lang je SSD het volhoudt onder een dergelijke belasting, rekening houdend met de TBW uit het datablad.

#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

Arrays maken

Eerst moeten we de machine hernoemen. Dit is nodig omdat de hostnaam ergens in mdadm deel uitmaakt van de arraynaam en ergens iets beïnvloedt. Natuurlijk kunnen arrays later worden hernoemd, maar dit is een onnodige stap.

#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

Waarom -neem aan-schoon...?Om te voorkomen dat arrays worden geïnitialiseerd. Voor zowel RAID-niveau 1 als 6 geldt dit. Alles kan werken zonder initialisatie als het een nieuwe array is. Bovendien is het initialiseren van de SSD-array bij het maken een verspilling van TBW-bronnen. We gebruiken TRIM/DISCARD waar mogelijk op samengestelde SSD-arrays om ze te ‘initialiseren’.

Voor SSD-arrays wordt RAID 1 DISCARD standaard ondersteund.

Voor SSD RAID 6 DISCARD-arrays moet u dit inschakelen in de kernelmoduleparameters.

Dit mag alleen worden gedaan als alle SSD's die in niveau 4/5/6-arrays in dit systeem worden gebruikt, werkende ondersteuning hebben voor throw_zeroes_data. Soms kom je vreemde drives tegen die de kernel vertellen dat deze functie wordt ondersteund, maar die er feitelijk niet is, of dat de functie niet altijd werkt. Op dit moment is ondersteuning bijna overal beschikbaar, maar er zijn oude schijven en firmware met fouten. Om deze reden is DISCARD-ondersteuning standaard uitgeschakeld voor RAID 6.

Let op, de volgende opdracht zal alle gegevens op NVMe-schijven vernietigen door de array te “initialiseren” met “nullen”.

#blkdiscard /dev/md0

Als er iets misgaat, probeer dan een stap op te geven.

#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

Waarom zo groot...?Het vergroten van de chunkgrootte heeft een positief effect op de snelheid van het willekeurig lezen in blokken tot en met de chunkgrootte. Dit gebeurt omdat één handeling van de juiste omvang of kleiner volledig op één apparaat kan worden uitgevoerd. Daarom wordt de IOPS van alle apparaten opgeteld. Volgens statistieken overschrijdt 99% van de IO de 512K niet.

RAID 6 IOPS per schrijfbewerking altijd kleiner dan of gelijk aan de IOPS van één schijf. Wanneer, bij willekeurige lezing, IOPS meerdere malen groter kan zijn dan die van één schijf, en hier is de blokgrootte van cruciaal belang.
De auteur ziet het nut niet in van het optimaliseren van een parameter die slecht is in het ontwerp van RAID 6, maar optimaliseert in plaats daarvan waar RAID 6 goed in is.
We zullen het slechte willekeurige schrijven van RAID 6 compenseren met een NVMe-cache en thin-provisioning-trucs.

We hebben DISCARD nog niet ingeschakeld voor RAID 6. We zullen deze array voorlopig dus niet “initialiseren”. We zullen dit later doen, na installatie van het besturingssysteem.

SATA HDD

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

LVM op NVMe RAID

Voor snelheid willen we het rootbestandssysteem op NVMe RAID 1 plaatsen, namelijk /dev/md0.
We zullen deze snelle array echter nog steeds nodig hebben voor andere behoeften, zoals swap, metadata en LVM-cache en LVM-thin metadata, dus we zullen een LVM VG op deze array creëren.

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

Laten we een partitie maken voor het rootbestandssysteem.

#lvcreate -L 128G --name root root

Laten we een partitie maken voor het wisselen op basis van de grootte van het RAM-geheugen.

#lvcreate -L 32G --name swap root

OS-installatie

In totaal hebben wij alles wat nodig is om het systeem te installeren.

Start de systeeminstallatiewizard vanuit de Ubuntu Live-omgeving. Normale installatie. Alleen in de fase waarin u schijven selecteert voor installatie, moet u het volgende opgeven:

  • /dev/md1, - koppelpunt /boot, FS - BTRFS
  • /dev/root/root (ook bekend als /dev/mapper/root-root), - koppelpunt / (root), FS - BTRFS
  • /dev/root/swap (ook bekend als /dev/mapper/root-swap), - gebruik als swappartitie
  • Installeer de bootloader op /dev/sda

Wanneer u BTRFS als rootbestandssysteem selecteert, maakt het installatieprogramma automatisch twee BTRFS-volumes met de naam "@" voor / (root) en "@home" voor /home.

Laten we beginnen met de installatie...

De installatie eindigt met een modaal dialoogvenster dat een fout aangeeft bij het installeren van de bootloader. Helaas kunt u dit dialoogvenster niet op de standaard manier verlaten en doorgaan met de installatie. We loggen uit het systeem en loggen opnieuw in en komen terecht op een schone Ubuntu Live-desktop. Open de terminal en nogmaals:

#sudo bash

Maak een chroot-omgeving om door te gaan met de installatie:

#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

Laten we het netwerk en de hostnaam in chroot configureren:

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

Laten we naar de chroot-omgeving gaan:

#chroot /mnt/chroot

Allereerst komen wij de pakketten bezorgen:

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

Laten we alle pakketten controleren en repareren die verkeerd zijn geïnstalleerd vanwege een onvolledige systeeminstallatie:

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

Als iets niet lukt, moet u mogelijk eerst /etc/apt/sources.list bewerken

Laten we de parameters voor de RAID 6-module aanpassen om TRIM/DISCARD in te schakelen:

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

Laten we onze arrays een beetje aanpassen:

#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

Wat was het..?We hebben een set udev-regels gemaakt die het volgende doen:

  • Stel de blokcachegrootte voor RAID 2020 zo in dat deze geschikt is voor 6. De standaardwaarde is, zo lijkt het, niet veranderd sinds de creatie van Linux, en is al lange tijd niet meer toereikend.
  • Reserveer een minimum aan IO voor de duur van arraycontroles/synchronisaties. Dit is om te voorkomen dat uw arrays onder belasting vastlopen in een staat van eeuwige synchronisatie.
  • Beperk de maximale IO tijdens controles/synchronisatie van arrays. Dit is nodig zodat het synchroniseren/controleren van SSD RAID's uw schijven niet kapot maakt. Dit geldt vooral voor NVMe. (Weet je nog over de radiator? Ik maakte geen grapje.)
  • Verbied dat schijven de spindelrotatie (HDD) via APM stoppen en stel de slaaptime-out voor schijfcontrollers in op 7 uur. U kunt APM volledig uitschakelen als uw schijven dit kunnen (-B 255). Met de standaardwaarde stoppen de schijven na vijf seconden. Dan wil het besturingssysteem de schijfcache opnieuw instellen, de schijven zullen weer opstarten en alles zal opnieuw beginnen. Schijven hebben een beperkt maximaal aantal spilomwentelingen. Zo'n eenvoudige standaardcyclus kan uw schijven binnen een paar jaar gemakkelijk vernietigen. Niet alle schijven hebben hier last van, maar de onze zijn 'laptop'-schijven, met de juiste standaardinstellingen, waardoor de RAID op een mini-MAID lijkt.
  • Installeer readahead op schijven (roterend) 1 megabyte - twee opeenvolgende blokken/chunk RAID 6
  • Schakel readahead uit op de arrays zelf.

Laten we /etc/fstab bewerken:

#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

Waarom is dat..?We zullen zoeken naar de /boot-partitie op UUID. De naamgeving van de array zou theoretisch kunnen veranderen.

We zullen naar de overige secties zoeken op LVM-naam in de notatie /dev/mapper/vg-lv, omdat ze identificeren partities op een vrij unieke manier.

We gebruiken UUID niet voor LVM omdat De UUID van LVM-volumes en hun snapshots kunnen hetzelfde zijn./dev/mapper/root-root.. twee keer mounten?Ja. Precies. Kenmerk van BTRFS. Dit bestandssysteem kan meerdere keren worden gemount met verschillende subvols.

Vanwege dezelfde functie raad ik aan nooit LVM-snapshots van actieve BTRFS-volumes te maken. Mogelijk krijgt u een verrassing wanneer u opnieuw opstart.

Laten we de mdadm-configuratie opnieuw genereren:

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

Laten we de LVM-instellingen aanpassen:

#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

Wat was het..?We hebben automatische uitbreiding van LVM-dunne zwembaden mogelijk gemaakt zodra 90% van de bezette ruimte met 5% van het volume werd bereikt.

We hebben het maximale aantal cacheblokken voor LVM-cache verhoogd.

We hebben voorkomen dat LVM naar LVM-volumes (PV) zoekt op:

  • apparaten met LVM-cache (cdata)
  • apparaten die in de cache zijn opgeslagen met behulp van LVM-cache, waarbij de cache wordt omzeild ( _corig). In dit geval wordt het in de cache opgeslagen apparaat zelf nog steeds via de cache gescand (slechts ).
  • apparaten die LVM-cache-metagegevens bevatten (cmeta)
  • alle apparaten in VG met de naamafbeeldingen. Hier hebben we schijfkopieën van virtuele machines en we willen niet dat LVM op de host volumes activeert die bij het gastbesturingssysteem horen.
  • alle apparaten in VG met de naamback-up. Hier hebben we back-ups van afbeeldingen van virtuele machines.
  • alle apparaten waarvan de naam eindigt met “gpv” (fysiek gastenvolume)

We hebben DISCARD-ondersteuning ingeschakeld bij het vrijmaken van vrije ruimte op LVM VG. Wees voorzichtig. Dit maakt het verwijderen van LV's op de SSD behoorlijk tijdrovend. Dit geldt vooral voor SSD RAID 6. Volgens het plan gaan we echter gebruik maken van thin provisioning, dus daar hebben we geen hinder van.

Laten we de initramfs-afbeelding bijwerken:

#update-initramfs -u -k all

Grub installeren en configureren:

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

Welke schijven kiezen?Iedereen die sd* is. Het systeem moet kunnen opstarten vanaf elke werkende SATA-schijf of SSD.

Waarom hebben ze os-prober toegevoegd..?Voor buitensporige onafhankelijkheid en speelse handen.

Het werkt niet correct als een van de RAID's zich in een slechte staat bevindt. Er wordt geprobeerd het besturingssysteem te zoeken op partities die worden gebruikt in virtuele machines die op deze hardware draaien.

Als je het nodig hebt, kun je het laten staan, maar houd rekening met al het bovenstaande. Ik raad aan om online naar recepten te zoeken om van stoute handen af ​​te komen.

Hiermee hebben we de eerste installatie voltooid. Het is tijd om opnieuw op te starten in het nieuw geïnstalleerde besturingssysteem. Vergeet niet de opstartbare Live CD/USB te verwijderen.

#exit
#reboot

Selecteer een van de SATA SSD's als opstartapparaat.

LVM op SATA SSD

Op dit punt zijn we al opgestart in het nieuwe besturingssysteem, hebben we het netwerk geconfigureerd, apt, de terminalemulator geopend en gelanceerd:

#sudo bash

Laten we doorgaan.

“Initialiseer” de array vanaf een SATA SSD:

#blkdiscard /dev/md2

Als het niet werkt, probeer dan:

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

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

Waarom nog een VG..?In feite hebben we al een VG met de naam root. Waarom niet alles in één VG samenvoegen?

Als er meerdere PV's in een VG aanwezig zijn, moeten alle PV's (online) aanwezig zijn om de VG correct te kunnen activeren. De uitzondering is LVM RAID, die we bewust niet gebruiken.

We willen heel graag dat als er een fout optreedt (lees gegevensverlies) op een van de RAID 6-arrays, het besturingssysteem normaal opstart en ons de kans geeft het probleem op te lossen.

Om dit te doen, zullen we op het eerste abstractieniveau elk type fysieke ‘media’ isoleren in een afzonderlijke VG.

Wetenschappelijk gezien behoren verschillende RAID-arrays tot verschillende “betrouwbaarheidsdomeinen”. Je moet geen extra gemeenschappelijk faalpunt voor hen creëren door ze in één VG te proppen.

De aanwezigheid van LVM op ‘hardware’-niveau zal ons in staat stellen willekeurig stukken van verschillende RAID-arrays te knippen door ze op verschillende manieren te combineren. Bijvoorbeeld - rennen tegelijkertijd bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, een complexe ZFS-configuratie met caches, of een ander hels mengsel om alles te vergelijken.

Op ‘hardware’-niveau zullen we niets anders gebruiken dan de goede oude ‘dikke’ LVM-volumes. De uitzondering op deze regel kan de back-uppartitie zijn.

Ik denk dat veel lezers op dit moment al iets over de nestpop begonnen te vermoeden.

LVM op SATA-harde schijf

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

Weer nieuwe VG..?We willen echt dat als de disk-array die we gaan gebruiken voor gegevensback-up mislukt, ons besturingssysteem normaal blijft werken, terwijl de toegang tot niet-back-upgegevens zoals gewoonlijk behouden blijft. Om VG-activeringsproblemen te voorkomen, maken we daarom een ​​aparte VG.

LVM-cache instellen

Laten we een LV op NVMe RAID 1 maken om deze als caching-apparaat te gebruiken.

#lvcreate -L 70871154688B --name cache root

Waarom is er zo weinig...?Feit is dat onze NVMe SSD’s ook over een SLC cache beschikken. 4 gigabyte “gratis” en 18 gigabyte dynamisch vanwege de vrije ruimte die wordt ingenomen in de 3-bit MLC. Zodra deze cache leeg is, zullen NVMe SSD's niet veel sneller zijn dan onze SATA SSD met cache. Om deze reden heeft het eigenlijk geen zin om de LVM-cachepartitie veel groter te maken dan tweemaal de grootte van de SLC-cache van de NVMe-schijf. Voor de gebruikte NVMe-schijven acht de auteur het redelijk om 32-64 gigabyte aan cache te maken.

De opgegeven partitiegrootte is vereist om 64 gigabyte aan cache, cachemetagegevens en back-up van metagegevens te organiseren.

Bovendien merk ik op dat LVM na een vuile systeemafsluiting de hele cache als vuil zal markeren en opnieuw zal synchroniseren. Bovendien wordt dit elke keer herhaald als lvchange op dit apparaat wordt gebruikt, totdat het systeem opnieuw wordt opgestart. Daarom raad ik aan om de cache onmiddellijk opnieuw te maken met behulp van het juiste script.

Laten we een LV maken op SATA RAID 6 om deze te gebruiken als een apparaat in de cache.

#lvcreate -L 3298543271936B --name cache data

Waarom slechts drie terabytes..?Zodat u, indien nodig, SATA SSD RAID 6 voor andere doeleinden kunt gebruiken. De grootte van de ruimte in de cache kan dynamisch worden vergroot, zonder het systeem te stoppen. Om dit te doen, moet u de cache tijdelijk stoppen en opnieuw inschakelen, maar het onderscheidende voordeel van LVM-cache ten opzichte van bijvoorbeeld bcache is dat dit direct kan worden gedaan.

Laten we een nieuwe VG maken voor caching.

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

Laten we een LV maken op het apparaat in de cache.

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

Hier hebben we onmiddellijk alle vrije ruimte op /dev/data/cache in beslag genomen, zodat alle andere noodzakelijke partities onmiddellijk op /dev/root/cache werden aangemaakt. Als je iets op de verkeerde plaats hebt aangemaakt, kun je het verplaatsen met pvmove.

Laten we de cache maken en inschakelen:

#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

Waarom zo'n chunksize..?Door praktische experimenten kwam de auteur erachter dat het beste resultaat wordt bereikt als de grootte van het LVM-cacheblok samenvalt met de grootte van het LVM-dunne blok. Bovendien geldt: hoe kleiner het formaat, hoe beter de configuratie presteert bij een willekeurige opname.

64k is de minimaal toegestane blokgrootte voor LVM thin.

Wees voorzichtig met terugschrijven..!Ja. Dit type cache stelt de schrijfsynchronisatie naar het apparaat in de cache uit. Dit betekent dat als de cache verloren gaat, u mogelijk gegevens op het apparaat in de cache kwijtraakt. Later zal de auteur vertellen welke maatregelen er, naast NVMe RAID 1, genomen kunnen worden om dit risico te compenseren.

Dit cachetype is bewust gekozen om de slechte willekeurige schrijfprestaties van RAID 6 te compenseren.

Laten we eens kijken wat we hebben:

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

Alleen [cachedata_corig] mag zich in /dev/data/cache bevinden. Als er iets mis is, gebruik dan pvmove.

U kunt de cache indien nodig uitschakelen met één commando:

#lvconvert -y --uncache cache/cachedata

Dit gebeurt online. LVM synchroniseert eenvoudigweg de cache met schijf, verwijdert deze en hernoemt cachedata_corig terug naar cachedata.

LVM thin instellen

Laten we grofweg schatten hoeveel ruimte we nodig hebben voor dunne LVM-metagegevens:

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

Rond af naar 4 gigabyte: 4294967296B

Vermenigvuldig met twee en tel 4194304B op voor LVM PV-metagegevens: 8594128896B
Laten we een aparte partitie op NVMe RAID 1 maken om LVM thin metadata en hun back-upkopie erop te plaatsen:

#lvcreate -L 8594128896B --name images root

Waarvoor..?Hier kan de vraag rijzen: waarom LVM thin metadata afzonderlijk plaatsen als deze nog steeds in de cache op NVMe wordt opgeslagen en snel zal werken.

Hoewel snelheid hier belangrijk is, is dit verre van de belangrijkste reden. Het punt is dat de cache een faalpunt is. Er zou iets mee kunnen gebeuren, en als de dunne LVM-metagegevens in de cache worden opgeslagen, zal alles volledig verloren gaan. Zonder volledige metadata zal het vrijwel onmogelijk zijn om dunne volumes samen te stellen.

Door de metadata naar een apart, niet in de cache opgeslagen, maar snel volume te verplaatsen, garanderen we de veiligheid van de metadata in geval van cacheverlies of corruptie. In dit geval zal alle schade veroorzaakt door cacheverlies worden gelokaliseerd in dunne volumes, wat de herstelprocedure met ordes van grootte zal vereenvoudigen. Met een grote waarschijnlijkheid zal deze schade worden hersteld met behulp van FS-logboeken.

Bovendien, als eerder een snapshot van een thin volume werd gemaakt en daarna de cache minstens één keer volledig werd gesynchroniseerd, dan zal, dankzij het interne ontwerp van LVM thin, de integriteit van de snapshot gegarandeerd zijn in het geval van cacheverlies .

Laten we een nieuwe VG maken die verantwoordelijk is voor thin-provisioning:

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

Laten we een pool maken:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Waarom -Z yNaast waar deze modus eigenlijk voor bedoeld is - om te voorkomen dat gegevens van de ene virtuele machine naar een andere virtuele machine lekken bij het herverdelen van ruimte - wordt nulstelling bovendien gebruikt om de snelheid van willekeurig schrijven in blokken kleiner dan 64k te verhogen. Elke schrijfbewerking van minder dan 64k naar een voorheen niet-toegewezen gebied van het thin volume wordt 64K edge-uitgelijnd in de cache. Hierdoor kan de bewerking volledig via de cache worden uitgevoerd, waarbij het in de cache opgeslagen apparaat wordt omzeild.

Laten we de LV's naar de overeenkomstige PV's verplaatsen:

#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

Laten we het controleren:

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

Laten we een dun volume maken voor tests:

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

We zullen pakketten installeren voor tests en monitoring:

#apt-get install sysstat fio

Zo kunt u het gedrag van onze opslagconfiguratie in realtime observeren:

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

Dit is hoe we onze configuratie kunnen testen:

#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

Voorzichtig! Hulpbron!Deze code voert 36 verschillende tests uit, elk gedurende 4 seconden. De helft van de tests is voor opname. In 4 seconden kun je veel opnemen op NVMe. Tot 3 gigabyte per seconde. Elke reeks schrijftests kan dus tot 216 gigabyte aan SSD-bronnen van u opslokken.

Lezen en schrijven gemengd?Ja. Het is zinvol om de lees- en schrijftests afzonderlijk uit te voeren. Bovendien is het zinvol om ervoor te zorgen dat alle caches worden gesynchroniseerd, zodat een eerder gemaakte schrijfactie geen invloed heeft op het lezen.

De resultaten zullen sterk variëren tijdens de eerste lancering en de daaropvolgende lanceringen naarmate de cache en het dunne volume vol raken, en ook afhankelijk van de vraag of het systeem erin is geslaagd de caches te synchroniseren die tijdens de laatste lancering zijn gevuld.

Ik raad onder andere aan om de snelheid te meten op een al vol dun volume waarvan zojuist een momentopname is gemaakt. De auteur had de gelegenheid om te observeren hoe willekeurige schrijfbewerkingen scherp versnellen onmiddellijk na het maken van de eerste momentopname, vooral als de cache nog niet helemaal vol is. Dit gebeurt vanwege de copy-on-write-schrijfsemantiek, de uitlijning van cache- en dunne volumeblokken, en het feit dat willekeurig schrijven naar RAID 6 verandert in willekeurig lezen vanuit RAID 6, gevolgd door schrijven naar de cache. In onze configuratie is willekeurig lezen vanaf RAID 6 tot 6 keer (het aantal SATA SSD's in de array) sneller dan schrijven. Omdat blokken voor CoW worden opeenvolgend toegewezen vanuit een dunne pool, waarna de opname voor het grootste deel ook sequentieel wordt.

Beide functies kunnen in uw voordeel worden gebruikt.

Cache “coherente” momentopnamen

Om het risico op gegevensverlies in het geval van schade/verlies aan de cache te verminderen, stelt de auteur voor om de praktijk van het roteren van snapshots te introduceren om in dit geval hun integriteit te garanderen.

Ten eerste zullen de metadata consistent zijn, omdat de metadata op een niet in de cache opgeslagen apparaat zich op een dun volume bevinden en mogelijke verliezen binnen de datablokken worden geïsoleerd.

De volgende rotatiecyclus van snapshots garandeert de integriteit van de gegevens in de snapshots in geval van cacheverlies:

  1. Voor elk thin volume met de naam <naam> maakt u een momentopname met de naam <naam>.cached
  2. Laten we de migratiedrempel instellen op een redelijk hoge waarde: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. In de lus controleren we het aantal vuile blokken in de cache: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' totdat we nul krijgen. Als de nul te lang ontbreekt, kan deze worden gemaakt door de cache tijdelijk in de schrijfmodus te zetten. Als u echter rekening houdt met de snelheidskenmerken van onze SATA- en NVMe SSD-arrays, evenals met hun TBW-bronnen, kunt u óf snel het moment vastleggen zonder de cachemodus te wijzigen, óf uw hardware zal de hele bron volledig opslokken. een paar dagen. Vanwege beperkte bronnen kan het systeem in principe niet altijd onder de 100% schrijfbelasting blijven. Onze NVMe SSD's met een schrijfbelasting van 100% zullen de beschikbare bronnen volledig uitputten 3-4 dagen. SATA SSD's gaan slechts twee keer zo lang mee. Daarom gaan we ervan uit dat het grootste deel van de belasting naar lezen gaat, en dat we relatief korte perioden van extreem hoge activiteit hebben, gecombineerd met gemiddeld een lage belasting voor schrijven.
  4. Zodra we een nul hebben opgemerkt (of gemaakt), hernoemen we <naam>.cached naar <naam>.composed. De oude <naam>.composed wordt verwijderd.
  5. Als de cache 100% vol is, kan deze optioneel opnieuw worden aangemaakt door een script, waardoor deze wordt gewist. Met een halflege cache werkt het systeem veel sneller tijdens het schrijven.
  6. Stel de migratiedrempel in op nul: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Hierdoor wordt tijdelijk voorkomen dat de cache met de hoofdmedia wordt gesynchroniseerd.
  7. We wachten tot er behoorlijk wat veranderingen in de cache zijn verzameld #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' anders gaat de timer af.
  8. Wij herhalen het opnieuw.

Waarom problemen met de migratiedrempel...?Het punt is dat in de praktijk een “willekeurige” opname eigenlijk niet helemaal willekeurig is. Als we iets schrijven naar een sector van 4 kilobytes groot, is de kans groot dat er in de komende paar minuten een record wordt gemaakt naar dezelfde of een van de aangrenzende (+- 32K) sectoren.

Door de migratiedrempel op nul te zetten, stellen we de schrijfsynchronisatie op de SATA SSD uit en voegen we verschillende wijzigingen samen in één blok van 64 KB in de cache. Dit bespaart aanzienlijk de bron van SATA SSD.

Waar is de code..?Helaas acht de auteur zichzelf onvoldoende bekwaam in het ontwikkelen van bash-scripts omdat hij 100% autodidact is en aan “google”-gestuurde ontwikkeling doet, daarom is hij van mening dat de vreselijke code die uit zijn handen komt door niemand mag worden gebruikt anders.

Ik denk dat professionals op dit gebied in staat zullen zijn om indien nodig zelfstandig alle hierboven beschreven logica weer te geven, en misschien zelfs prachtig te ontwerpen als een systeemdienst, zoals de auteur probeerde te doen.

Zo'n eenvoudig snapshot-rotatieschema zal ons niet alleen in staat stellen om constant één snapshot volledig gesynchroniseerd te hebben op de SATA SSD, maar zal ons ook in staat stellen om, met behulp van het thin_delta-hulpprogramma, uit te vinden welke blokken na de creatie ervan zijn gewijzigd, en zo de schade aan de SATA SSD te lokaliseren. de belangrijkste volumes, waardoor het herstel aanzienlijk wordt vereenvoudigd.

TRIM/DISCARD in libvirt/KVM

Omdat de gegevensopslag zal worden gebruikt voor KVM waarop libvirt draait, dan zou het een goed idee zijn om onze VM's niet alleen te leren vrije ruimte in te nemen, maar ook om vrij te maken wat niet langer nodig is.

Dit wordt gedaan door TRIM/DISCARD-ondersteuning op virtuele schijven te emuleren. Om dit te doen, moet u het controllertype wijzigen in virtio-scsi en de xml bewerken.

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

Dergelijke DISCARD's van gastbesturingssystemen worden correct verwerkt door LVM, en blokken worden correct vrijgegeven, zowel in de cache als in de thin pool. In ons geval gebeurt dit voornamelijk op een vertraagde manier, bij het verwijderen van de volgende snapshot.

BTRFS-back-up

Gebruik kant-en-klare scripts met крайней voorzichtigheid en op eigen risico. De auteur heeft deze code zelf en exclusief voor zichzelf geschreven. Ik ben er zeker van dat veel ervaren Linux-gebruikers vergelijkbare tools hebben, en het is niet nodig om die van iemand anders te kopiëren.

Laten we een volume maken op het back-upapparaat:

#lvcreate -L 256G --name backup backup

Laten we het formatteren in BTRFS:

#mkfs.btrfs /dev/backup/backup

Laten we koppelpunten maken en de hoofdsubsecties van het bestandssysteem aankoppelen:

#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

Laten we mappen maken voor back-ups:

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

Laten we een map maken voor back-upscripts:

#mkdir /root/btrfs-backup

Laten we het script kopiëren:

Veel enge bash-code. Gebruik op eigen risico. Schrijf geen boze brieven naar de auteur...#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

Wat doet het eigenlijk..?Bevat een reeks eenvoudige opdrachten voor het maken van BTRFS-snapshots en het kopiëren ervan naar een andere FS met behulp van BTRFS send/receive.

De eerste lancering kan relatief lang duren, omdat... In het begin worden alle gegevens gekopieerd. Verdere lanceringen zullen erg snel zijn, omdat... Alleen wijzigingen worden gekopieerd.

Nog een script dat we in cron zullen plaatsen:

Nog wat bash-code#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

Wat doet het..?Creëert en synchroniseert incrementele snapshots van de vermelde BTRFS-volumes op de back-up-FS. Hierna worden alle foto's verwijderd die 60 dagen geleden zijn gemaakt. Na de lancering verschijnen gedateerde momentopnamen van de vermelde volumes in de submappen /backup/btrfs/back/remote/.

Laten we de code-uitvoeringsrechten geven:

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

Laten we het controleren en in de cron plaatsen:

#/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 dunne back-up

Laten we een thin pool maken op het back-upapparaat:

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

Laten we ddrescue installeren, omdat... scripts zullen deze tool gebruiken:

#apt-get install gddrescue

Laten we een map voor scripts maken:

#mkdir /root/lvm-thin-backup

Laten we de scripts kopiëren:

Veel bash binnen...#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

Wat doet het...?Bevat een reeks opdrachten voor het manipuleren van thin snapshots en het synchroniseren van het verschil tussen twee thin snapshots ontvangen via thin_delta naar een ander blokapparaat met behulp van ddrescue en blkdiscard.

Nog een script dat we in cron zullen plaatsen:

Nog een beetje bashen#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

Wat doet het...?Gebruikt het vorige script om back-ups van de vermelde thin volumes te maken en te synchroniseren. Het script laat inactieve momentopnamen achter van de vermelde volumes, die nodig zijn om de wijzigingen sinds de laatste synchronisatie bij te houden.

Dit script moet worden bewerkt, waarbij de lijst met thin volumes wordt gespecificeerd waarvoor back-upkopieën moeten worden gemaakt. De opgegeven namen zijn uitsluitend bedoeld ter illustratie. Als u wilt, kunt u een script schrijven dat alle volumes synchroniseert.

Laten we de rechten geven:

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

Laten we het controleren en in de cron plaatsen:

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

De eerste lancering zal lang duren, omdat... dunne volumes worden volledig gesynchroniseerd door alle gebruikte ruimte te kopiëren. Dankzij de dunne metadata van LVM weten we welke blokken daadwerkelijk in gebruik zijn, zodat alleen daadwerkelijk gebruikte dunne volumeblokken worden gekopieerd.

Bij daaropvolgende runs worden de gegevens stapsgewijs gekopieerd dankzij het bijhouden van wijzigingen via dunne LVM-metagegevens.

Laten we eens kijken wat er gebeurd is:

#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

Wat heeft dit met nestpoppen te maken?

Hoogstwaarschijnlijk, aangezien logische LVM LV-volumes fysieke LVM PV-volumes kunnen zijn voor andere VG's. LVM kan recursief zijn, zoals nestpoppen. Dit geeft LVM extreme flexibiliteit.

PS

In het volgende artikel zullen we proberen verschillende soortgelijke mobiele opslagsystemen/KVM te gebruiken als basis voor het creëren van een geo-gedistribueerd opslag/VM-cluster met redundantie op verschillende continenten met behulp van thuisdesktops, het thuisinternet en P2P-netwerken.

Bron: www.habr.com

Voeg een reactie