Qu'est-ce qui est commun entre LVM et matriochka?

Bonne journée.
Je veux partager avec la communauté une expérience pratique dans la construction d'un systÚme de stockage pour KVM utilisant md RAID + LVM.

Le programme:

  • Construisez md RAID 1 Ă  partir du SSD NVMe.
  • CrĂ©ez md RAID 6 Ă  partir de disques SSD SATA et de disques ordinaires.
  • CaractĂ©ristiques du TRIM / DISCARD sur SSD RAID 1/6.
  • CrĂ©ation d'une matrice RAID 1/6 md amorçable sur un ensemble commun de disques.
  • Installation du systĂšme sur NVMe RAID 1 s'il n'y a pas de prise en charge NVMe dans le BIOS.
  • Utilisation du cache LVM et du LVM thin.
  • Utilisation d'instantanĂ©s BTRFS et envoi / rĂ©ception pour la sauvegarde.
  • Utilisation d'instantanĂ©s lĂ©gers LVM et thin_delta pour la sauvegarde de style BTRFS.

Si vous ĂȘtes intĂ©ressĂ©, s'il vous plaĂźt, sous cat.

DĂ©claration


L'auteur n'assume aucune responsabilité pour les conséquences de l'utilisation ou de la non-utilisation des matériaux / exemples / code / conseils / données de cet article. En lisant ou en utilisant ce matériel de quelque maniÚre que ce soit, vous assumez la responsabilité de toutes les conséquences de ces actions. Les conséquences possibles incluent:

  • SSD Crispy Fried NVMe.
  • ComplĂštement Ă©puisĂ© les ressources d'enregistrement et les pannes de disques SSD.
  • Perte complĂšte de toutes les donnĂ©es sur tous les disques, y compris les sauvegardes.
  • MatĂ©riel informatique dĂ©fectueux.
  • A passĂ© du temps, des nerfs et de l'argent.
  • Tout autre effet non mentionnĂ© ci-dessus.

Le fer


En stock Ă©tait:


La carte mĂšre est vers 2013 sur le chipset Z87 complet avec Intel Core i7 / Haswell.

  • CPU 4 cƓurs, 8 threads
  • 32 gigaoctets de RAM DDR3
  • 1 x 16 ou 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • Connecteurs SATA 3 6 x 6 Go / s

L'adaptateur SAS LSI SAS9211-8I a flashé en mode IT / HBA. Le micrologiciel compatible RAID a été intentionnellement remplacé par le micrologiciel HBA pour:

  1. Il Ă©tait possible Ă  tout moment de jeter cet adaptateur et de le remplacer par tout autre premier.
  2. TRIM / Discard fonctionnait normalement sur les disques, dans le firmware RAID, ces commandes ne sont pas du tout prises en charge et HBA, en général, ne se soucie pas des commandes à envoyer sur le bus.

Disques durs - 8 piĂšces de HGST Travelstar 7K1000 avec un volume de 1 To au format 2,5, comme pour les ordinateurs portables. Ces disques Ă©taient auparavant dans une matrice RAID 6. Dans le nouveau systĂšme, ils trouveront Ă©galement une application. Pour stocker des sauvegardes locales.

De plus, il a été ajouté:


6 piÚces de SSD SATA modÚle Samsung 860 QVO 2 To. Ces SSD nécessitaient une grande quantité, la présence d'un cache SLC, la fiabilité est souhaitable et un prix bas. Obligatoire était la prise en charge de la suppression / zéro qui est vérifiée par une ligne en dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 piĂšces de modĂšle NVMe SSD Samsung SSD 970 EVO 500GB.

Pour ces SSD, une vitesse de lecture / écriture aléatoire et une ressource adaptée à vos besoins sont importantes. Radiateur à eux. Obligatoire. Absolument nécessaire. Sinon, faites-les frire jusqu'à ce qu'elles soient croustillantes lors de la premiÚre synchronisation RAIDa.

Adaptateur StarTech PEX8M2E2 pour 2 disques SSD NVMe avec emplacement PCIe 3.0 8x. Encore une fois, ce n'est que du HBA, mais pour NVMe. Il diffĂšre des adaptateurs bon marchĂ© en l'absence de la prise en charge de la bifurcation PCIe depuis la carte mĂšre en raison de la prĂ©sence d'un commutateur PCIe intĂ©grĂ©. Il fonctionnera mĂȘme dans le systĂšme le plus ancien oĂč il y a PCIe, mĂȘme s'il s'agit d'un emplacement x1 PCIe 1.0. Naturellement, avec la vitesse appropriĂ©e. Il n'y a pas de RAID lĂ -bas. Il n'y a pas de BIOS intĂ©grĂ© Ă  bord. Ainsi, votre systĂšme n'apprendra pas par magie Ă  dĂ©marrer Ă  partir de NVMe, et encore moins Ă  faire NVMe RAID grĂące Ă  cet appareil.

Ce composant a Ă©tĂ© causĂ© uniquement par la prĂ©sence d'un seul PCIe 3.0 8x gratuit dans le systĂšme et, en prĂ©sence de 2 emplacements libres, il est facilement remplacĂ© par deux PEX4M2E1 ou analogues bon marchĂ©, qui peuvent ĂȘtre achetĂ©s n'importe oĂč au prix de 600 roubles.

Le refus de tout type de matĂ©riel ou de chipsets RAID / BIOS intĂ©grĂ©s a Ă©tĂ© fait dĂ©libĂ©rĂ©ment, afin de pouvoir remplacer complĂštement l'ensemble du systĂšme, Ă  l'exception du SSD / HDD lui-mĂȘme, en sauvegardant toutes les donnĂ©es. IdĂ©alement, il serait possible de conserver mĂȘme le systĂšme d'exploitation installĂ© lors du passage Ă  un matĂ©riel complĂštement nouveau / diffĂ©rent. L'essentiel est qu'il existe des ports SATA et PCIe. C'est comme un CD live ou un lecteur flash amorçable, seulement trĂšs rapide et un peu surdimensionnĂ©.

Humour
, , — . . 5.25 .

Eh bien, et, bien sûr, pour expérimenter différentes méthodes de mise en cache SSD sous Linux.
Les incursions matérielles, c'est ennuyeux. Allumer. Cela fonctionne ou non. Et avec mdadm, il y a toujours des options.

Doux


Auparavant, Debian 8 Jessie était installée sur le matériel, qui est proche d'EOL. Le RAID 6 des disques durs mentionnés ci-dessus a été associé à LVM. Il exécutait des machines virtuelles dans kvm / libvirt.

Parce que L'auteur a l'expérience appropriée dans la création de lecteurs flash SATA / NVMe portables et également, afin de ne pas déchirer le modÚle apt habituel, Ubuntu 18.04 a été choisi comme systÚme cible, qui s'est déjà suffisamment stabilisé, mais a encore 3 ans de support à l'avenir.

Dans le systĂšme mentionnĂ©, tous les pilotes matĂ©riels dont nous avons besoin sont prĂȘts Ă  l'emploi. Nous n'avons besoin d'aucun logiciel et pilote tiers.

Préparation pour l'installation


Pour installer le systÚme, nous avons besoin d'Ubuntu Desktop Image. Le systÚme serveur possÚde une sorte de programme d'installation vigoureux qui présente une indépendance excessive et non déconnectable, poussant toujours la partition systÚme UEFI sur l'un des disques, gùchant toute la beauté. Par conséquent, il est installé uniquement en mode UEFI. Il n'offre pas d'options.

Cela ne nous convient pas.

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

, UEFI NVRAM, , .. .

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

La version de bureau d'Ubuntu ne sait pas non plus comment s'installer normalement avec le chargeur de démarrage hérité, mais ici, comme on dit, il y a au moins des options.

Et donc, collectez le matériel et chargez le systÚme à partir du lecteur flash Ubuntu Live amorçable. Nous devrons télécharger des packages, nous avons donc mis en place le réseau qui vous a valu. Si cela ne fonctionne pas, vous pouvez télécharger à l'avance les packages nécessaires sur la clé USB.

Nous allons dans l'environnement de bureau, exécutons l'émulateur de terminal et allons-y:

#sudo bash

Comment...?
sudo. . , . sudo , . :


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

Pourquoi pas ZFS ...?
, — , .
, — , - .

ZFS — , mdadm+lvm .

. . . . . . , .

Pourquoi alors BTRFS ...?
Legacy/BIOS GRUB , , , -. /boot . , / () , LVM .

, .
send/recieve.

, GPU PCI-USB Host- KVM IOMMU.

— , .

ZFS, , , .

, / RAID ZFS, BRTFS LVM.

, BTRFS , / HDD.

Analyser Ă  nouveau tous les appareils: regardons autour de nous

#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

Partitionnement des "lecteurs"


NVMe SSD


Mais en aucun cas nous ne les annotons. Tout de mĂȘme, notre BIOS ne voit pas ces disques. Ainsi, ils iront entiĂšrement au RAID logiciel. Nous n'y crĂ©erons mĂȘme pas de partitions. Si vous voulez selon le "canon" ou le "principe" - crĂ©ez une grande partition, comme un disque dur.

Disque dur SATA


Il n'y a rien de spĂ©cial Ă  inventer. Nous crĂ©erons une section pour tout. Nous allons crĂ©er la section car le BIOS voit ces disques et peut mĂȘme essayer de dĂ©marrer Ă  partir d'eux. Nous installerons mĂȘme GRUB plus tard sur ces disques afin que le systĂšme rĂ©ussisse soudainement.

#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

SSD SATA


Ici, nous avons le plus intéressant.

PremiĂšrement, nous avons 2 disques TB. Ceci est dans les limites autorisĂ©es pour MBR, que nous utiliserons. Si nĂ©cessaire, peut ĂȘtre remplacĂ© par GPT. Les disques GPT ont une couche de compatibilitĂ© qui permet aux systĂšmes compatibles MBR de voir les 4 premiĂšres partitions si elles se trouvent dans les 2 premiers tĂ©raoctets. L'essentiel est que la partition de dĂ©marrage et la partition bios_grub sur ces disques soient au dĂ©but. Cela vous permet mĂȘme de dĂ©marrer Ă  partir du lecteur GPT Legacy / BIOS.

Mais ce n'est pas notre cas.

Ici, nous allons créer deux sections. Le premier sera de 1 Go et utilisé pour RAID 1 / boot.

Le second sera utilisé pour RAID 6 et occupera tout l'espace libre restant à l'exception d'une petite zone non allouée à la fin du lecteur.

Quelle est la zone non allouée?
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

Création de tableaux


Nous devons d'abord renommer la voiture. Cela est nĂ©cessaire car le nom d'hĂŽte fait partie du nom du tableau quelque part dans mdadm et affecte quelque chose quelque part. Les tableaux, bien sĂ»r, peuvent ĂȘtre renommĂ©s plus tard, mais ce sont des actions inutiles.

#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

Pourquoi - assumer-nettoyer ...?
. 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.

Attention, la commande suivante détruira toutes les données sur les disques NVMe en «initialisant» la baie avec des «zéros».

#blkdiscard /dev/md0

En cas de problÚme, essayez de spécifier une étape.

#blkdiscard --step 65536 /dev/md0

SSD SATA


#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

Pourquoi si gros ...?
chunk-size chunk-size . , . , IOPS . 99% IO 512K.

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

Nous n'avons pas encore activé DISCARD pour RAID 6. Nous n'allons donc pas encore «initialiser» cette baie. Nous le ferons plus tard, aprÚs avoir installé le systÚme d'exploitation.

Disque dur SATA


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

LVM sur NVMe RAID


Pour la vitesse, nous voulons placer la racine FS sur NVMe RAID 1 qui est / dev / md0.
Néanmoins, nous avons toujours besoin de ce tableau rapide pour d'autres besoins, tels que le swap, les métadonnées et le cache LVM et les métadonnées LVM-thin, par conséquent, sur ce tableau, nous créerons LVM VG. Créez une partition pour le FS racine. Créez une section pour échanger la taille de la RAM.

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




#lvcreate -L 128G --name root root



#lvcreate -L 32G --name swap root

Installation du systĂšme d'exploitation


Au total, nous avons tout le nécessaire pour installer le systÚme.

Lancez l'assistant d'installation à partir de l'environnement Ubuntu Live. Installation normale. Seulement au stade de la sélection des lecteurs pour l'installation, vous devez spécifier les éléments suivants:

  • / dev / md1, - point de montage / dĂ©marrage, FS - BTRFS
  • / dev / root / root (alias / dev / mapper / root-root), - point de montage / (root), FS - BTRFS
  • / dev / root / swap (alias / dev / mapper / root-swap), - utiliser comme partition de swap
  • Installation du chargeur de dĂ©marrage sur / dev / sda

Si vous sélectionnez BTRFS comme racine FS, le programme d'installation crée automatiquement deux volumes BTRFS avec les noms "@" pour / (root) et "@home" pour / home.

Nous commençons l'installation ... L'

installation se terminera par une boßte de dialogue modale informant de l'erreur d'installation du chargeur de démarrage. Malheureusement, sortir de ce dialogue par des moyens réguliers et poursuivre l'installation échouera. Nous nous déconnectons du systÚme et nous nous connectons à nouveau, en entrant dans le bureau Ubuntu Live propre. Ouvrez le terminal, puis à nouveau:

#sudo bash

créez un environnement chroot pour continuer l'installation: configurez le réseau et le nom d'hÎte dans chroot: accédez à l'environnement chroot: commencez par livrer les packages: vérifiez et réparez tous les packages qui ont été tordus en raison de l'installation incomplÚte du systÚme:

#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

Si quelque chose ne se dĂ©veloppe pas ensemble, vous devrez peut-ĂȘtre

modifier /etc/apt/sources.list avant cela. Modifions les paramÚtres du module RAID 6 pour activer TRIM / DISCARD: Nous ajusterons légÚrement nos tableaux:

#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

Qu'est-ce que c'Ă©tait..?
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 .


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

Pourquoi donc..?
/boot UUID .. .

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

UUID LVM .. UUID LVM .
Nous montons deux fois / dev / mapper / root-root ..?
. . BTRFS. subvol.

- LVM BTRFS . .

Nous régénérons la configuration mdadm: Corrigez les paramÚtres LVM:

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

Qu'est-ce que c'Ă©tait..?
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, , .

Mettez Ă  jour l'image initramfs:

#update-initramfs -u -k all

Installez et configurez grub:

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


Quelles motivations choisir?
sd*. SATA SSD.

Pourquoi os-prober cloué ..?
.

RAID- . , .

, , , . .

Avec cela, nous avons terminé l'installation initiale. Il est temps de redémarrer dans le systÚme d'exploitation nouvellement installé. N'oubliez pas de retirer le Live CD / USB amorçable. Pour démarrer, sélectionnez l'un des SSD SATA.

#exit
#reboot




LVM vers SSD SATA


À ce stade, nous avons dĂ©jĂ  dĂ©marrĂ© dans le nouveau systĂšme d'exploitation, configurĂ© le rĂ©seau, apt, ouvert l'Ă©mulateur de terminal et commencĂ©:

#sudo bash

Continuer.

"Initialiser" une matrice Ă  partir d'un SSD SATA:

#blkdiscard /dev/md2

Si ce n'est pas le cas, essayez:

#blkdiscard --step 65536 /dev/md2
Créer LVM VG sur un SSD SATA:

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


Pourquoi un autre 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-, . , , .

, , - .

Disque dur LVM vers SATA


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


Encore une fois le nouveau VG ..?
, , , , - . , - VG, — VG.

Configurer le cache LVM


Créez LV sur NVMe RAID 1 pour l'utiliser comme périphérique de mise en cache.

#lvcreate -L 70871154688B --name cache root

Pourquoi si peu ...?
, NVMe SSD SLC . 4 «» 18 3-bit MLC. - NVMe SSD SATA SSD . , LVM cache SLC NVMe . NVMe 32-64 .

64 , .

, LVM . , lvchange . , .

Créons LV sur SATA RAID 6 pour l'utiliser comme périphérique mis en cache.

#lvcreate -L 3298543271936B --name cache data

Pourquoi seulement trois téraoctets ..?
, , SATA SSD RAID 6 - . , , . , , LVM-cache , , bcache, , .

Créez un nouveau VG pour la mise en cache. Créez LV sur le périphérique mis en cache. Ici, nous avons immédiatement pris tout l'espace libre sur / dev / data / cache afin que toutes les autres partitions nécessaires soient créées immédiatement sur / dev / root / cache. Si vous avez quelque chose qui n'y est pas créé, vous pouvez le déplacer à l'aide de pvmove. Créez et activez le 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

Pourquoi tant de gros morceaux ..?
, LVM cache LVM thin. , , .

64 — LVM thin.

Attention l'écriture différée ..!
. . , , , . , , NVMe RAID 1 , .

, RAID 6 .

Vérifions que nous avons réussi: seul [cachedata_corig] doit se trouver sur / dev / data / cache. Si quelque chose ne va pas, utilisez pvmove. Si nécessaire, vous pouvez désactiver le cache avec une seule commande: cela se fait en ligne. LVM synchronise simplement le cache sur le disque, le supprime et renomme cachedata_corig en cachedata.

#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



Configuration fine LVM


Nous allons approximativement estimer l'espace dont nous aurons besoin pour les métadonnées minces LVM : arrondir à 4 gigaoctets: 4294967296B Multiplier par deux et ajouter 4194304B pour les métadonnées LVM PV: 8594128896B Créez une partition distincte sur NVMe RAID 1 pour y délimiter les métadonnées minces LVM et les sauvegarder:

#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

Pourquoi..?
, LVM thin , NVMe .

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

- -, , , . , . .

, , , , , , LVM thin, .

Créez un nouveau VG qui sera responsable de l'allocation dynamique: Créez un 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
Pourquoi -Z y
, , — , — zeroing 64k. 64k 64K . .

Déplaçons LV vers les PV correspondants: Vérifiez: Créez un volume mince pour les tests: Mettez des packages pour les tests et les observations: Voici comment vous pouvez observer le comportement de notre configuration de stockage en temps réel: Voici comment vous pouvez tester notre configuration:

#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

Mise en garde! Ressource!
36 , 4 . . 4 NVMe . 3 . , 216 SSD.

Lecture et écriture aléatoire?
. . , , , .

Les résultats varient considérablement au premier démarrage et aux suivants à mesure que le cache et le volume léger se remplissent, et également, selon que le systÚme a réussi à synchroniser les caches remplis au dernier démarrage.

Entre autres choses, je recommande de mesurer la vitesse sur le volume mince dĂ©jĂ  rempli Ă  partir duquel l'instantanĂ© vient d'ĂȘtre rĂ©alisĂ©. L'auteur a eu l'occasion d'observer comment un enregistrement alĂ©atoire accĂ©lĂšre fortement immĂ©diatement aprĂšs la crĂ©ation du premier instantanĂ©, en particulier lorsque le cache n'est pas encore plein. Cela est dĂ» Ă  la sĂ©mantique d'Ă©criture sur copie, Ă  l'alignement des blocs de cache et des volumes minces, et au fait que l'Ă©criture alĂ©atoire sur RAID 6 se transforme en lecture alĂ©atoire sur RAID 6, puis Ă©crit dans le cache. Dans notre configuration, la lecture alĂ©atoire de RAID 6 Ă  6 fois (le nombre de SSD SATA dans la baie) est plus rapide que l'Ă©criture. Parce que Étant donnĂ© que les blocs CoW sont allouĂ©s sĂ©quentiellement Ă  partir d'un pool mince, l'enregistrement, pour la plupart, devient Ă©galement sĂ©quentiel.

Ces deux fonctionnalitĂ©s peuvent ĂȘtre avantageusement utilisĂ©es.

Mettre en cache des instantanés «cohérents»


Pour réduire le risque de perte de données en cas d'endommagement / perte de cache, l'auteur suggÚre d'introduire la pratique des instantanés tournants pour garantir leur intégrité dans ce cas.

PremiÚrement, du fait que les métadonnées des volumes minces sont situées sur un périphérique non mis en cache, les métadonnées seront cohérentes et les éventuelles pertes seront isolées à l'intérieur des blocs de données.

Le cycle de rotation des instantanés suivant garantit l'intégrité des données à l'intérieur des instantanés en cas de perte de cache:

  1. Pour chaque volume léger portant le nom <nom>, créez un instantané avec le nom <nom> .cached
  2. Définissez le seuil de migration sur une valeur élevée raisonnable: #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 , .

Un tel schéma de rotation simple pour les instantanés nous permettra non seulement d'avoir constamment un instantané complÚtement synchronisé sur le SSD SATA, mais il nous permettra également d'utiliser l'utilitaire thin_delta pour savoir quels blocs ont été modifiés aprÚs sa création et, ainsi, localiser les dommages sur les volumes principaux, simplifiant grandement la récupération .

TRIM / DISCARD dans libvirt / KVM


Parce que Étant donnĂ© que l'entrepĂŽt de donnĂ©es sera utilisĂ© pour KVM exĂ©cutant libvirt, il serait bon d'apprendre Ă  nos machines virtuelles non seulement Ă  occuper de l'espace libre, mais aussi Ă  libĂ©rer ce qui n'est plus nĂ©cessaire.

Cela se fait en émulant le support TRIM / DISCARD sur les disques virtuels. Pour ce faire, changez le type de contrÎleur en virtio-scsi et modifiez le xml. Les DISCARDs similaires des OS invités sont correctement traités par LVM et les blocs sont correctement libérés à la fois dans le cache et dans le thin pool. Dans notre cas, cela se produit, principalement, reporté, lorsque vous supprimez l'instantané suivant.

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



Sauvegarde BTRFS


Utilisez des scripts prĂȘts Ă  l'emploi avec une extrĂȘme prudence et Ă  vos risques et pĂ©rils . L'auteur a Ă©crit ce code lui-mĂȘme et exclusivement pour lui-mĂȘme. Je suis sĂ»r que de nombreux utilisateurs Linux expĂ©rimentĂ©s ont de telles bĂ©quilles d' expĂ©rience et que d'autres n'en auront pas besoin.

Créer un volume sur le périphérique de sauvegarde: le

#lvcreate -L 256G --name backup backup

formater en BTRFS:

#mkfs.btrfs /dev/backup/backup

créer des points de montage et monter des sous-clés racine du FS: créer des répertoires pour les sauvegardes: créer un répertoire pour les scripts de sauvegarde: copier le script:

#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



Beaucoup de code bash effrayant. À utiliser Ă  vos risques et pĂ©rils. L'auteur n'Ă©crit pas de lettres en colĂšre ...
#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


Que fait-il mĂȘme ..?
BTRFS BTRFS send/recieve.

Le premier lancement peut ĂȘtre relativement long, car au dĂ©but, toutes les donnĂ©es seront copiĂ©es. D'autres lancements seront trĂšs rapides, car seules les modifications seront copiĂ©es.

Un autre script Ă  entasser en cron:

Un peu plus de code bash
#cat >/root/btrfs-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"

BACKUP_SCRIPT="$SCRIPT_DIR/btrfs-backup.sh"
RETENTION="-60 day"
$BACKUP_SCRIPT backup root/@
$BACKUP_SCRIPT removeall root/@ "$RETENTION"
$BACKUP_SCRIPT backup root/@home
$BACKUP_SCRIPT removeall root/@home "$RETENTION"
$BACKUP_SCRIPT backup boot/
$BACKUP_SCRIPT removeall boot/ "$RETENTION"
EOF


Qu'est-ce que ça fait ..?
backup BTRFS-. 60 . /backup/btrfs/back/remote/ .

Donnons au code le droit d'exécuter: Vérifier et entasser les couronnes:

#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

Sauvegarde légÚre LVM


Créez un pool léger sur le périphérique de sauvegarde:

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

installez ddrescue, car les scripts utiliseront cet outil:

#apt-get install gddrescue

Créez un répertoire pour les scripts:

#mkdir /root/lvm-thin-backup

Copiez les scripts:

Beaucoup de coups à l'intérieur ...
#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


Qu'est-ce que ça fait ...?
, thin_delta, ddrescue blkdiscard.

Un autre script que nous allons entasser en couronnes:

Un peu plus 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


Qu'est-ce que ça fait ...?
, . , .

Ce script doit ĂȘtre modifiĂ©, indiquant une liste de volumes lĂ©gers pour lesquels des sauvegardes sont requises. Les noms donnĂ©s sont Ă  titre indicatif seulement. Si vous le souhaitez, vous pouvez Ă©crire un script qui synchronisera tous les volumes.

Donnons des droits: Vérifiez et fourrez dans les couronnes: Le premier lancement sera long, car les volumes minces seront entiÚrement synchronisés en copiant tout l'espace utilisé. Grùce aux métadonnées minces LVM, nous savons quels blocs sont réellement utilisés, donc seuls les blocs réels de volumes minces seront copiés. Les lancements suivants copieront les données de maniÚre incrémentielle en suivant les modifications via les métadonnées fines LVM.

#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





Voyons ce qui se passe:


#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

Et les poupées gigognes?


TrĂšs probablement, bien que les volumes logiques LVM LV puissent ĂȘtre des volumes PV LVM physiques pour d'autres VG. LVM peut ĂȘtre rĂ©cursif, comme les poupĂ©es gigognes. Cela donne Ă  LVM une extrĂȘme flexibilitĂ©.

PS


Dans le prochain article, nous allons essayer d'utiliser plusieurs systÚmes de stockage mobiles / KVM similaires comme base pour créer un cluster de stockage / vm géo-distribué avec redondance sur plusieurs continents via des ordinateurs de bureau à domicile, Internet à domicile et des réseaux P2P.

All Articles