Was ist zwischen LVM und Matroschka gemeinsam?

Schönen Tag.
Ich möchte mit der Community praktische Erfahrungen beim Aufbau eines Speichersystems für KVM mit md RAID + LVM teilen.

Das Programm wird:

  • Erstellen Sie md RAID 1 von einer NVMe-SSD.
  • Erstellen Sie md RAID 6 von einer SATA-SSD und normalen Laufwerken.
  • Funktionen des TRIM / DISCARD auf SSD RAID 1/6.
  • Erstellen eines bootfähigen MD RAID 1/6 Arrays auf einem gemeinsamen Satz von Festplatten.
  • Installieren des Systems auf NVMe RAID 1, wenn im BIOS keine NVMe-Unterstützung vorhanden ist.
  • Verwenden von LVM-Cache und LVM Thin.
  • Verwenden von BTRFS-Snapshots und Senden / Empfangen zur Sicherung.
  • Verwenden von LVM Thin Snapshots und Thin_Delta für Backups im BTRFS-Stil.

Bei Interesse bitte unter Katze.

Aussage


Der Autor übernimmt keine Verantwortung für die Folgen der Verwendung oder Nichtverwendung der Materialien / Beispiele / Codes / Tipps / Daten aus diesem Artikel. Wenn Sie dieses Material lesen oder in irgendeiner Weise verwenden, übernehmen Sie die Verantwortung für alle Konsequenzen dieser Handlungen. Mögliche Folgen sind:

  • Knusprig gebratene NVMe SSD.
  • Vollständig verbrauchte Aufzeichnungsressource und Ausfall von SSD-Laufwerken.
  • Vollständiger Verlust aller Daten auf allen Laufwerken, einschließlich Backups.
  • Fehlerhafte Computerhardware.
  • Verbrachte Zeit, Nerven und Geld.
  • Alle anderen oben nicht aufgeführten Effekte.

Eisen


Auf Lager war:


Das Motherboard ist um 2013 auf dem Z87-Chipsatz mit Intel Core i7 / Haswell.

  • CPU 4 Kerne, 8 Threads
  • 32 Gigabyte DDR3-RAM
  • 1 x 16 oder 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • SATA 3-Anschlüsse mit 6 x 6 GBit / s

SAS-Adapter LSI SAS9211-8I wurde in den IT / HBA-Modus geflasht. RAID-fähige Firmware wurde absichtlich durch HBA-Firmware ersetzt, um:

  1. Es war jederzeit möglich, diesen Adapter zu werfen und durch einen anderen ersten zu ersetzen.
  2. TRIM / Discard funktionierte normal auf Festplatten, wie In der RAID-Firmware werden diese Befehle überhaupt nicht unterstützt, und HBA ist es im Allgemeinen egal, welche Befehle auf dem Bus gesendet werden sollen.

Festplatten - 8 Stück HGST Travelstar 7K1000 mit einem Volumen von 1 TB im Formfaktor 2,5, wie bei Laptops. Diese Laufwerke befanden sich zuvor in einem RAID 6-Array. Im neuen System finden sie auch Anwendung. Zum Speichern lokaler Backups.

Zusätzlich wurde hinzugefügt:


6 Stück SATA SSD Modell Samsung 860 QVO 2 TB. Diese SSDs erforderten eine große Menge, das Vorhandensein eines SLC-Cache, Zuverlässigkeit ist wünschenswert und einen niedrigen Preis. Obligatorisch war die Unterstützung für Discard / Zero, die durch eine Zeile in dmesg überprüft wird:

kernel: ata1.00: Enabling discard_zeroes_data

2 Stück NVMe SSD-Modell Samsung SSD 970 EVO 500 GB.

Für diese SSDs sind zufällige Lese- / Schreibgeschwindigkeit und eine Ressource für Ihre Anforderungen wichtig. Kühler zu ihnen. Verpflichtend. Absolut notwendig. Andernfalls braten Sie sie während der ersten RAIDa-Synchronisation knusprig.

StarTech PEX8M2E2-Adapter für 2 x NVMe-SSDs mit PCIe 3.0 8x-Steckplatz. Dies ist wiederum nur HBA, aber für NVMe. Es unterscheidet sich von billigen Adaptern dadurch, dass keine PCIe-Bifurkationsunterstützung vom Motherboard erforderlich ist, da ein integrierter PCIe-Switch vorhanden ist. Es funktioniert auch im ältesten System, in dem PCIe vorhanden ist, selbst wenn es sich um einen x1 PCIe 1.0-Steckplatz handelt. Natürlich mit der entsprechenden Geschwindigkeit. Es gibt dort keine RAIDs. Es ist kein integriertes BIOS an Bord. Ihr System lernt also nicht auf magische Weise, von NVMe zu booten, geschweige denn NVMe-RAID dank dieses Geräts.

Diese Komponente wurde ausschließlich durch das Vorhandensein von nur einem freien 8x PCIe 3.0 im System verursacht und kann mit 2 freien Steckplätzen leicht durch zwei billige PEX4M2E1 oder Analoga ersetzt werden, die überall zu einem Preis von 600 Rubel erhältlich sind.

Die Ablehnung aller Arten von Hardware oder integrierten RAID-Chipsätzen / BIOS wurde bewusst vorgenommen, um das gesamte System mit Ausnahme der SSD / HDD selbst vollständig ersetzen zu können und alle Daten zu speichern. Im Idealfall ist es möglich, auch das installierte Betriebssystem beizubehalten, wenn auf eine völlig neue / andere Hardware umgestellt wird. Hauptsache, es gibt SATA- und PCIe-Ports. Es ist wie eine Live-CD oder ein bootfähiges Flash-Laufwerk, nur sehr schnell und etwas übergroß.

Humor
, , — . . 5.25 .

Nun, und natürlich, um mit verschiedenen Methoden des SSD-Caching unter Linux zu experimentieren.
Hardware-Raids, es ist langweilig. Anschalten. Es funktioniert entweder oder nicht. Und mit mdadm gibt es immer Optionen.

Sanft


Zuvor war Debian 8 Jessie auf der Hardware installiert, die EOL nahe kommt. RAID 6 von den oben genannten Festplatten wurde mit LVM gekoppelt. Es wurden virtuelle Maschinen in kvm / libvirt ausgeführt.

weil Der Autor verfügt über die entsprechende Erfahrung bei der Erstellung von tragbaren bootfähigen SATA / NVMe-Flash-Laufwerken. Um die übliche apt-Vorlage nicht zu beschädigen, wurde Ubuntu 18.04 als Zielsystem ausgewählt, das sich bereits ausreichend stabilisiert hat, aber auch in Zukunft 3 Jahre Unterstützung bietet.

In dem genannten System sind alle Hardwaretreiber vorhanden, die wir sofort benötigen. Wir benötigen keine Software und Treiber von Drittanbietern.

Vorbereitung für die Installation


Zur Installation des Systems benötigen wir Ubuntu Desktop Image. Das Serversystem verfügt über eine Art leistungsstarkes Installationsprogramm, das eine übermäßige, nicht trennbare Unabhängigkeit aufweist und die UEFI-Systempartition immer auf eine der Festplatten schiebt, die die ganze Schönheit beeinträchtigen. Dementsprechend wird es nur im UEFI-Modus installiert. Es werden keine Optionen angeboten.

Das passt nicht zu uns.

Warum?
, UEFI RAID, .. UEFI ESP . , ESP USB , , . mdadm RAID 1 0.9 UEFI BIOS , , BIOS - ESP .

, UEFI NVRAM, , .. .

, . , Legacy/BIOS boot, CSM UEFI- . , , .

Die Desktop-Version von Ubuntu weiß auch nicht, wie man normal mit dem Legacy-Bootloader installiert, aber hier gibt es, wie sie sagen, zumindest Optionen.

Sammeln Sie also die Hardware und laden Sie das System vom bootfähigen Ubuntu Live-Flash-Laufwerk. Wir müssen Pakete herunterladen, also richten wir das Netzwerk ein, das Sie verdient hat. Wenn dies nicht funktioniert, können Sie die erforderlichen Pakete vorab auf das USB-Flash-Laufwerk herunterladen.

Wir gehen in die Desktop-Umgebung, führen den Terminalemulator aus und gehen:

#sudo bash

Wie...?
sudo. . , . sudo , . :


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

Warum nicht ZFS ...?
, — , .
, — , - .

ZFS — , mdadm+lvm .

. . . . . . , .

Warum dann BTRFS ...?
Legacy/BIOS GRUB , , , -. /boot . , / () , LVM .

, .
send/recieve.

, GPU PCI-USB Host- KVM IOMMU.

— , .

ZFS, , , .

, / RAID ZFS, BRTFS LVM.

, BTRFS , / HDD.

Scannen Sie alle Geräte erneut: Schauen wir uns um

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

:

#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

Partitionierung von "Laufwerken"


NVMe SSD


Aber in keiner Weise werden wir sie markieren. Trotzdem sieht unser BIOS diese Laufwerke nicht. Sie werden also vollständig auf Software-RAID umsteigen. Wir werden dort nicht einmal Partitionen erstellen. Wenn Sie nach dem "Kanon" oder "Prinzip" möchten, erstellen Sie eine große Partition wie eine Festplatte.

SATA-Festplatte


Es gibt nichts Besonderes zu erfinden. Wir werden für alles einen Abschnitt erstellen. Wir werden den Abschnitt erstellen, da das BIOS diese Datenträger sieht und möglicherweise sogar versucht, von ihnen zu booten. Wir werden GRUB später sogar auf diesen Festplatten installieren, damit das System plötzlich erfolgreich ist.

#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


Hier haben wir die interessantesten.

Erstens haben wir 2 TB-Laufwerke. Dies liegt innerhalb der zulässigen Grenzen für MBR, die wir verwenden werden. Kann bei Bedarf durch GPT ersetzt werden. GPT-Festplatten verfügen über eine Kompatibilitätsschicht, mit der MBR-kompatible Systeme die ersten 4 Partitionen anzeigen können, wenn sie sich innerhalb der ersten 2 Terabyte befinden. Die Hauptsache ist, dass die Boot-Partition und die bios_grub-Partition auf diesen Festplatten am Anfang stehen sollten. Auf diese Weise können Sie sogar vom GPT Legacy / BIOS-Laufwerk booten.

Dies ist jedoch nicht unser Fall.

Hier erstellen wir zwei Abschnitte. Die erste ist 1 GB groß und wird für RAID 1 / Boot verwendet.

Der zweite wird für RAID 6 verwendet und belegt den gesamten verbleibenden freien Speicherplatz mit Ausnahme eines kleinen nicht zugewiesenen Bereichs am Ende des Laufwerks.

Was ist der nicht zugewiesene Bereich?
SATA SSD SLC 6 78 . 6 «» «» «» . 72 .

, SLC, 4 bit MLC. , 4 1 SLC .

72 4 288 . , SLC .

, 312 SLC . 2 RAID .

, . QLC , — . , , , SSD TBW .

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


Zuerst müssen wir das Auto umbenennen. Dies ist erforderlich, da der Hostname irgendwo innerhalb von mdadm Teil des Array-Namens ist und irgendwo etwas beeinflusst. Arrays können natürlich später umbenannt werden, dies sind jedoch unnötige Aktionen.

#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

Warum - sauber machen ...?
. RAID 1 6 . , . , SSD — TBW. TRIM/DISCARD SSD «».

SSD RAID 1 DISCARD .

SSD RAID 6 DISCARD .

, SSD 4/5/6 discard_zeroes_data. , , , -, , . , , . DISCARD - RAID 6.

Achtung, der folgende Befehl zerstört alle Daten auf NVMe-Laufwerken, indem das Array mit "Nullen" "initialisiert" wird.

#blkdiscard /dev/md0

Wenn etwas schief gelaufen ist, geben Sie einen Schritt an.

#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

Warum so groß ...?
chunk-size chunk-size . , . , IOPS . 99% IO 512K.

RAID 6 IOPS IOPS . IOPS , .
RAID 6 by-design , RAID 6 .
RAID 6 NVMe thin-provisioning.

Wir haben DISCARD für RAID 6 noch nicht aktiviert. Daher werden wir dieses Array noch nicht "initialisieren". Wir werden es später nach der Installation des Betriebssystems tun.

SATA-Festplatte


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

LVM auf NVMe RAID


Aus Gründen der Geschwindigkeit möchten wir den Root-FS auf NVMe RAID 1 platzieren, das / dev / md0 ist.
Trotzdem benötigen wir dieses schnelle Array für andere Anforderungen wie Swap, Metadaten und LVM-Cache sowie LVM-Thin-Metadaten. Daher werden wir auf diesem Array LVM VG erstellen. Erstellen Sie eine Partition für den Root-FS. Erstellen Sie einen Abschnitt, um die Größe des Arbeitsspeichers zu ändern.

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




#lvcreate -L 128G --name root root



#lvcreate -L 32G --name swap root

Installation des Betriebssystems


Insgesamt haben wir alles Notwendige, um das System zu installieren.

Starten Sie den Installationsassistenten in der Ubuntu Live-Umgebung. Normale Installation. Erst in der Phase der Auswahl der Laufwerke für die Installation müssen Sie Folgendes angeben:

  • / dev / md1, - Mountpunkt / Boot, FS - BTRFS
  • / dev / root / root (auch bekannt als / dev / mapper / root-root), - Mountpunkt / (root), FS - BTRFS
  • / dev / root / swap (auch bekannt als / dev / mapper / root-swap), - als Swap-Partition verwenden
  • Bootloader-Installation unter / dev / sda

Wenn Sie BTRFS als Root-FS auswählen, erstellt das Installationsprogramm automatisch zwei BTRFS-Volumes mit den Namen "@" für / (root) und "@home" für / home.

Wir starten die Installation ... Die

Installation endet mit einem modalen Dialogfeld, das über den Installationsfehler des Bootloaders informiert. Leider schlägt es fehl, diesen Dialog regelmäßig zu verlassen und die Installation fortzusetzen. Wir melden uns vom System ab und wieder an, um auf den sauberen Ubuntu Live-Desktop zu gelangen. Öffnen Sie das Terminal und erneut:

#sudo bash

Erstellen Sie eine Chroot-Umgebung, um die Installation fortzusetzen: Richten Sie das Netzwerk und den Hostnamen in Chroot ein: Wechseln Sie zur Chroot-Umgebung: Liefern Sie zuerst die Pakete: Überprüfen und reparieren Sie alle Pakete, die aufgrund der unvollständigen Installation des Systems schief gelaufen sind:

#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



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



#chroot /mnt/chroot



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



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

Wenn etwas nicht zusammenwächst, müssen Sie möglicherweise vorher /etc/apt/sources.list

bearbeiten . Ändern Sie die Parameter für das RAID 6-Modul, um TRIM / DISCARD zu aktivieren: Wir werden unsere Arrays leicht anpassen:

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



#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=="sd[a-z]", ATTR{queue/rotational}=="0", RUN+="/sbin/blockdev --setra 0 /dev/%k"
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="nvme[0-9]n1", RUN+="/sbin/blockdev --setra 0 /dev/%k"
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="dm-*", ATTR{queue/rotational}=="0", RUN+="/sbin/blockdev --setra 0 /dev/%k"
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="md*", RUN+="/sbin/blockdev --setra 0 /dev/%k"

EOF

Was war das..?
udev :

  • 2020- RAID 6. -, , Linux, .
  • / IO. , .
  • / IO. , / SSD RAID- . NVMe. ( ? . )
  • APM (HDD) 7 . APM (-B 255). - . , , , -. . - . , , - «», -, RAID- mini-MAID-.
  • readahead () 1 — /chunk RAID 6
  • readahead SATA SSD
  • readahead NVMe SSD
  • readahead LVM SSD.
  • readahead RAID .


Bearbeiten Sie / 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

Warum so..?
/boot UUID .. .

LVM /dev/mapper/vg-lv, .. .

UUID LVM .. UUID LVM .
Zweimal mounten wir / dev / mapper / root-root ..?
. . BTRFS. subvol.

- LVM BTRFS . .

Wir generieren die mdadm-Konfiguration neu: Korrigieren Sie die LVM-Einstellungen:

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



#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

Was war das..?
LVM thin 90% 5% .

LVM cache.

LVM LVM (PV) :

  • LVM cache (cdata)
  • LVM cache (<lv_name>_corig). ( <lv_name>).
  • LVM cache (cmeta)
  • VG images. , , LVM .
  • VG backup. .
  • «gpv» ( guest physical volume )

DISCARD LVM VG. . LV SSD . SSD RAID 6. , , thin provisioning, , .

Aktualisieren Sie das initramfs-Image:

#update-initramfs -u -k all

Installieren und konfigurieren Sie grub:

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


Welche Laufwerke zur Auswahl?
sd*. SATA SSD.

Warum os-prober genagelt ..?
.

RAID- . , .

, , , . .

Damit haben wir die Erstinstallation abgeschlossen. Es ist Zeit, das neu installierte Betriebssystem neu zu starten. Denken Sie daran, die bootfähige Live-CD / USB zu entfernen. Wählen Sie als zu startendes Gerät eine der SATA-SSDs aus.

#exit
#reboot




LVM zu SATA SSD


Zu diesem Zeitpunkt haben wir bereits das neue Betriebssystem gestartet, das Netzwerk konfiguriert, apt, den Terminalemulator geöffnet und gestartet:

#sudo bash

Weiter.

"Initialisieren" eines Arrays von einer SATA-SSD:

#blkdiscard /dev/md2

Wenn dies nicht der Fall ist, versuchen Sie:

#blkdiscard --step 65536 /dev/md2
LVM-VG auf einer SATA-SSD erstellen:

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


Warum noch eine vg ..?
, VG root. VG?

VG PV, VG PV (online). LVM RAID, .

, ( ) RAID 6 .

, «» VG.

-, RAID « ». , VG.

LVM «» RAID - . , — bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, ZFS , .

«» , - «» LVM-, . , , .

, , - .

LVM zu SATA HDD


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


Wieder die neue VG ..?
, , , , - . , - VG, — VG.

Konfigurieren Sie den LVM-Cache


Erstellen Sie LV auf NVMe RAID 1, um es als Caching-Gerät zu verwenden.

#lvcreate -L 70871154688B --name cache root

Warum so wenig ...?
, NVMe SSD SLC . 4 «» 18 3-bit MLC. - NVMe SSD SATA SSD . , LVM cache SLC NVMe . NVMe 32-64 .

64 , .

, LVM . , lvchange . , .

Erstellen wir LV auf SATA RAID 6, um es als zwischengespeichertes Gerät zu verwenden.

#lvcreate -L 3298543271936B --name cache data

Warum nur drei Terabyte ..?
, , SATA SSD RAID 6 - . , , . , , LVM-cache , , bcache, , .

Erstellen Sie eine neue VG für das Caching. Erstellen Sie LV auf dem zwischengespeicherten Gerät. Hier haben wir sofort den gesamten freien Speicherplatz in / dev / data / cache belegt, sodass alle anderen erforderlichen Partitionen sofort in / dev / root / cache erstellt wurden. Wenn Sie dort etwas nicht erstellt haben, können Sie es mit pvmove verschieben. Erstellen und aktivieren Sie den Cache:

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




#lvcreate -L 3298539077632B --name cachedata cache /dev/data/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

Warum so Chunksize ..?
, LVM cache LVM thin. , , .

64 — LVM thin.

Achtung Rückschreiben ..!
. . , , , . , , NVMe RAID 1 , .

, RAID 6 .

Überprüfen wir, ob dies erfolgreich war: Nur [cachedata_corig] sollte sich in / dev / data / cache befinden. Wenn etwas nicht stimmt, verwenden Sie pvmove. Bei Bedarf können Sie den Cache mit einem Befehl deaktivieren: Dies erfolgt online. LVM synchronisiert einfach den Cache mit der Festplatte, löscht ihn und benennt cachedata_corig wieder in cachedata um.

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





#lvconvert -y --uncache cache/cachedata



LVM Thin Setup


Wir werden ungefähr schätzen, wie viel Speicherplatz wir für LVM-Thin-Metadaten benötigen: Auf 4 Gigabyte aufrunden: 4294967296B Mit zwei multiplizieren und 4194304B für LVM-Metadaten hinzufügen PV: 8594128896B Erstellen Sie eine separate Partition auf NVMe RAID 1, um LVM-Thin-Metadaten darauf zu markieren und zu sichern:

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







#lvcreate -L 8594128896B --name images root

Wozu..?
, LVM thin , NVMe .

, . , , . - , , LVM thin , . .

- -, , , . , . .

, , , , , , LVM thin, .

Erstellen Sie eine neue VG, die für die Thin-Bereitstellung verantwortlich ist: Erstellen Sie einen Pool:

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



#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Warum -Z y
, , — , — zeroing 64k. 64k 64K . .

Verschieben wir LV zu den entsprechenden PVs: Überprüfen: Erstellen Sie ein Thin Volume für Tests: Legen Sie Pakete für Tests und Beobachtungen ab: So können Sie das Verhalten unserer Speicherkonfiguration in Echtzeit beobachten: So können Sie unsere Konfiguration testen:

#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



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



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



#apt-get install sysstat fio



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



#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=256Kwrite --bs=256k --rw=write \
--name=128Kwrite --bs=128k --rw=write \
--name=64Kwrite --bs=64k --rw=write \
--name=32Kwrite --bs=32k --rw=write \
--name=16Kwrite --bs=16k --rw=write \
--name=8Kwrite --bs=8k --rw=write \
--name=4Kwrite --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

Vorsicht! Ressource!
36 , 4 . . 4 NVMe . 3 . , 216 SSD.

Shuffle lesen und schreiben?
. . , , , .

Die Ergebnisse variieren stark beim ersten Start und bei den nachfolgenden, wenn sich der Cache und das Thin Volume füllen. Dies hängt auch davon ab, ob das System die beim letzten Start gefüllten Caches synchronisieren konnte.

Ich empfehle unter anderem, die Geschwindigkeit an dem bereits gefüllten dünnen Volumen zu messen, aus dem der Schnappschuss gerade erstellt wurde. Der Autor hatte die Möglichkeit zu beobachten, wie sich die zufällige Aufzeichnung unmittelbar nach der Erstellung des ersten Schnappschusses stark beschleunigt, insbesondere wenn der Cache noch nicht voll ist. Dies liegt an der Schreibsemantik beim Schreiben, der Ausrichtung von Cache-Blöcken und Thin-Volumes sowie an der Tatsache, dass zufälliges Schreiben in RAID 6 zu zufälligem Lesen von RAID 6 und anschließendem Schreiben in den Cache wird. In unserer Konfiguration ist das zufällige Lesen von RAID 6 bis zu 6 Mal (die Anzahl der SATA-SSDs im Array) schneller als das Schreiben. weil Da CoW-Blöcke nacheinander aus einem Thin Pool zugewiesen werden, wird der Datensatz größtenteils auch zu einem sequentiellen Datensatz.

Diese beiden Merkmale können vorteilhaft genutzt werden.

Cache "kohärente" Schnappschüsse


Um das Risiko eines Datenverlusts bei Cache-Schäden / -Verlusten zu verringern, empfiehlt der Autor, die Praxis des Rotierens von Snapshots einzuführen, um deren Integrität in diesem Fall zu gewährleisten.

Erstens sind die Metadaten aufgrund der Tatsache, dass sich die Metadaten dünner Volumes auf einem nicht zwischengespeicherten Gerät befinden, konsistent und mögliche Verluste werden innerhalb der Datenblöcke isoliert.

Der folgende Snapshot-Rotationszyklus garantiert die Datenintegrität in Snapshots bei Cache-Verlust:

  1. Erstellen Sie für jedes Thin-Volume mit dem Namen <Name> einen Snapshot mit dem Namen <Name> .cached
  2. Stellen Sie den Migrationsschwellenwert auf einen angemessen hohen Wert ein: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. : #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' . , writethrough . , SATA NVMe SSD, , TBW, , . - 100% . NVMe SSD 100% 3-4 . SATA SSD - . , , , , — .
  4. ( ) — <>.cached <>.committed. <>.committed .
  5. , 100%, , . .
  6. migration threshold : #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata .
  7. , #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' .
  8. .

migration threshold...?
, «» . - 4 , , - (+- 32K) .

migration threshold SATA SSD 64K . SATA SSD.

..?
, bash 100% «google»-driven development, , , , .

, , , , systemd , .

Mit einem solchen einfachen Rotationsschema für Snapshots können wir nicht nur ständig einen Snapshot vollständig auf der SATA-SSD synchronisieren, sondern auch mithilfe des Dienstprogramms thin_delta herausfinden, welche Blöcke nach ihrer Erstellung geändert wurden, und so den Schaden auf den Hauptvolumes lokalisieren, wodurch die Wiederherstellung erheblich vereinfacht wird .

TRIM / DISCARD in libvirt / KVM


weil Da der Datenspeicher für KVM verwendet wird, auf dem libvirt ausgeführt wird, wäre es hilfreich, unseren VMs beizubringen, nicht nur freien Speicherplatz zu belegen, sondern auch das freizugeben, was nicht mehr benötigt wird.

Dies erfolgt durch Emulieren der TRIM / DISCARD-Unterstützung auf virtuellen Festplatten. Ändern Sie dazu den Controller-Typ in virtio-scsi und bearbeiten Sie die XML. Ähnliche DISCARDs von Gastbetriebssystemen werden von LVM korrekt verarbeitet, und Blöcke werden sowohl im Cache als auch im Thin Pool korrekt freigegeben. In unserem Fall geschieht dies hauptsächlich verschoben, wenn Sie den nächsten Schnappschuss löschen.

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



BTRFS-Sicherung


Verwenden Sie vorgefertigte Skripte mit äußerster Vorsicht und auf eigene Gefahr und Gefahr . Der Autor hat diesen Code selbst und exklusiv für sich selbst geschrieben. Ich bin sicher , dass viele erfahrene Linux - Anwender so haben Krücken von Erfahrung, und kopieren Sie andere nicht brauchen.

Erstellen Sie ein Volume auf dem Sicherungsgerät:

#lvcreate -L 256G --name backup backup

Formatieren Sie es in BTRFS:

#mkfs.btrfs /dev/backup/backup

Erstellen Sie Mount-Punkte und Mount-Root-Unterschlüssel des FS: Erstellen Sie Verzeichnisse für Backups: Erstellen Sie ein Verzeichnis für Backup-Skripte: Kopieren Sie das Skript:

#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



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



#mkdir /root/btrfs-backup



Viel gruseliger Bash-Code. Benutzung auf eigene Gefahr. Der Autor schreibt keine wütenden Briefe ...
#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 "%f\n" | 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


Was macht es überhaupt ..?
BTRFS BTRFS send/recieve.

Der erste Start kann relativ lang sein, weil Zu Beginn werden alle Daten kopiert. Weitere Starts werden sehr schnell sein, weil Es werden nur Änderungen kopiert.

Ein weiteres Skript, um Cron zu stopfen:

Noch etwas 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


Was macht es ..?
backup BTRFS-. 60 . /backup/btrfs/back/remote/ .

Geben wir dem Code das Recht zur Ausführung: Überprüfen und stopfen Sie die Kronen ein:

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



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


Erstellen Sie einen Thin Pool auf dem Sicherungsgerät:

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

Installieren Sie ddrescue, weil Skripte verwenden dieses Tool:

#apt-get install gddrescue

Erstellen Sie ein Verzeichnis für Skripte:

#mkdir /root/lvm-thin-backup

Kopieren Sie die Skripte:

Viel Bash drinnen ...
#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


Was macht es ...?
, thin_delta, ddrescue blkdiscard.

Ein weiteres Skript, das wir in Kronen packen werden:

Noch etwas 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


Was macht es ...?
, . , .

Dieses Skript muss bearbeitet werden und enthält eine Liste der Thin-Volumes, für die Sicherungen erforderlich sind. Die angegebenen Namen dienen nur zur Veranschaulichung. Wenn Sie möchten, können Sie ein Skript schreiben, das alle Volumes synchronisiert.

Lassen Sie uns Rechte geben: Überprüfen und in die Kronen stopfen: Der erste Start wird lang sein, weil Thin Volumes werden vollständig synchronisiert, indem der gesamte verwendete Speicherplatz kopiert wird. Dank der LVM-Thin-Metadaten wissen wir, welche Blöcke tatsächlich verwendet werden, sodass nur die tatsächlich verwendeten Blöcke mit Thin-Volumes kopiert werden. Bei nachfolgenden Starts werden die Daten schrittweise kopiert, indem Änderungen über LVM-Thin-Metadaten verfolgt werden.

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




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





Lass uns nachsehen, was passiert ist:


#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 .@snap.2020-03-06-09-39-37
drwxr-xr-x 1 root root 516 6 09:39 .@snap.2020-03-06-09-39-57
...
/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 @home.@snap.2020-03-06-09-39-35
drwxr-xr-x 1 root root 22 6 09:39 @home.@snap.2020-03-06-09-39-57
...
drwxr-xr-x 1 root root 240 6 09:39 @.@snap.2020-03-06-09-39-26
drwxr-xr-x 1 root root 240 6 09:39 @.@snap.2020-03-06-09-39-56
...

#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

Und was ist mit Nistpuppen?


Höchstwahrscheinlich können logische LVM-LV-Volumes physische LVM-PV-Volumes für andere VGs sein. LVM kann rekursiv sein, wie Nestpuppen. Dies gibt LVM extreme Flexibilität.

PS


Im nächsten Artikel werden wir versuchen, mehrere ähnliche mobile Speichersysteme / KVMs als Grundlage für die Erstellung eines geoverteilten Speicher- / VM-Clusters mit Redundanz auf mehreren Kontinenten über Heimdesktops, Heiminternet und P2P-Netzwerke zu verwenden.

All Articles