¿Qué es común entre LVM y matryoshka?

Buen día.
Quiero compartir con la comunidad la experiencia práctica en la construcción de un sistema de almacenamiento para KVM usando md RAID + LVM.

El programa:

  • Construya md RAID 1 desde NVMe SSD.
  • Construya md RAID 6 desde SSD SATA y unidades regulares.
  • Características de TRIM / DISCARD en SSD RAID 1/6.
  • Creación de una matriz de arranque RAID md 1/6 en un conjunto común de discos.
  • Instalación del sistema en NVMe RAID 1 si no hay compatibilidad con NVMe en el BIOS.
  • Usando caché LVM y LVM delgado.
  • Uso de instantáneas BTRFS y envío / recepción para copia de seguridad.
  • Uso de instantáneas delgadas LVM y thin_delta para copia de seguridad de estilo BTRFS.

Si está interesado, por favor, debajo del gato.

Declaración


El autor no tiene ninguna responsabilidad por las consecuencias de usar o no usar los materiales / ejemplos / código / consejos / datos de este artículo. Al leer o utilizar este material de cualquier manera, usted asume la responsabilidad de todas las consecuencias de estas acciones. Las posibles consecuencias incluyen:

  • Crispy Fried NVMe SSD.
  • Completamente agotado el recurso de grabación y la falla de las unidades SSD.
  • Pérdida completa de todos los datos en todas las unidades, incluidas las copias de seguridad.
  • Hardware de la computadora defectuoso.
  • Pasó tiempo, nervios y dinero.
  • Cualquier otro efecto no mencionado anteriormente.

Hierro


En stock fue:


La placa base es alrededor de 2013 en el chipset Z87 completo con Intel Core i7 / Haswell.

  • CPU 4 núcleos, 8 hilos
  • 32 Gigabytes de RAM DDR3
  • 1 x 16 o 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • Conectores SATA 3 de 6 x 6 GBps

Adaptador SAS LSI SAS9211-8I parpadeó en modo IT / HBA. El firmware habilitado para RAID se ha reemplazado intencionalmente con el firmware HBA para:

  1. En cualquier momento fue posible lanzar este adaptador y reemplazarlo por cualquier otro primero.
  2. TRIM / Discard funcionó normalmente en discos, como en el firmware RAID, estos comandos no son compatibles en absoluto, y a HBA, en general, no le importa qué comandos enviar en el bus.

Discos duros: 8 piezas de HGST Travelstar 7K1000 con un volumen de 1 TB en el factor de forma 2.5, como para las computadoras portátiles. Estas unidades estaban previamente en una matriz RAID 6. En el nuevo sistema, también encontrarán aplicación. Para almacenar copias de seguridad locales.

Además se agregó:


6 piezas de SSD SATA modelo Samsung 860 QVO 2TB. Estos SSD requieren una gran cantidad, la presencia de un caché SLC, la fiabilidad es deseable y un precio bajo. Obligatorio fue el soporte para descarte / cero, que se verifica mediante una línea en dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 piezas de NVMe SSD modelo Samsung SSD 970 EVO 500GB.

Para estos SSD, la velocidad de lectura / escritura aleatoria y un recurso para sus necesidades son importantes. Radiador para ellos. Obligatorio. Absolutamente necesario. De lo contrario, fríalos hasta que estén crujientes durante la primera sincronización RAIDa.

Adaptador StarTech PEX8M2E2 para 2 x NVMe SSD con ranura PCIe 3.0 8x. Esto, nuevamente, es solo HBA, pero para NVMe. Se diferencia de los adaptadores baratos en ausencia del requisito de soporte de bifurcación PCIe de la placa base debido a la presencia de un conmutador PCIe integrado. Funcionará incluso en el sistema más antiguo donde hay PCIe, incluso si es una ranura x1 PCIe 1.0. Naturalmente, con la velocidad adecuada. No hay RAID allí. No hay BIOS integrado a bordo. Por lo tanto, su sistema no aprenderá mágicamente a arrancar desde NVMe, y mucho menos NVMe RAID gracias a este dispositivo.

Este componente fue causado únicamente por la presencia de un solo PCIe 3.0 8x libre en el sistema y, en presencia de 2 ranuras libres, se reemplaza fácilmente por dos PEX4M2E1 o análogos baratos, que se pueden comprar en cualquier lugar a un precio de 600 rublos.

El rechazo de todo tipo de hardware o conjuntos de chips RAID / BIOS integrados se hizo deliberadamente, para poder reemplazar por completo todo el sistema, con la excepción de la propia SSD / HDD, guardando todos los datos. Idealmente, sería posible mantener incluso el sistema operativo instalado al pasar a un hardware completamente nuevo / diferente. Lo principal es que hay puertos SATA y PCIe. Es como un CD en vivo o una unidad flash de arranque, solo que muy rápido y un poco sobredimensionado.

Humor
, , — . . 5.25 .

Bueno, y, por supuesto, para experimentar con diferentes métodos de almacenamiento en caché SSD en Linux.
Incursiones de hardware, es aburrido. Encender. Funciona o no. Y con mdadm siempre hay opciones.

Suave


Anteriormente, Debian 8 Jessie se instaló en el hardware, que está cerca de EOL. RAID 6 de los discos duros mencionados anteriormente se emparejó con LVM. Estaba ejecutando máquinas virtuales en kvm / libvirt.

Porque El autor tiene la experiencia adecuada en la creación de unidades flash portátiles SATA / NVMe de arranque, y también, para no romper la plantilla de apt habitual, se eligió Ubuntu 18.04 como el sistema de destino, que ya se ha estabilizado lo suficiente, pero todavía tiene 3 años de soporte en el futuro.

En el sistema mencionado hay todos los controladores de hardware que necesitamos listos para usar. No necesitamos ningún software y controladores de terceros.

Preparación para la instalación


Para instalar el sistema, necesitamos Ubuntu Desktop Image. El sistema del servidor tiene algún tipo de instalador vigoroso que exhibe una independencia excesiva, no desconectable, siempre empujando la partición del sistema UEFI en uno de los discos que estropea toda la belleza. En consecuencia, se instala solo en modo UEFI. No ofrece opciones.

Esto no nos conviene.

¿Por qué?
, UEFI RAID, .. UEFI ESP . , ESP USB , , . mdadm RAID 1 0.9 UEFI BIOS , , BIOS - ESP .

, UEFI NVRAM, , .. .

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

La versión de escritorio de Ubuntu tampoco sabe cómo instalar normalmente con el gestor de arranque Legacy, pero aquí, como dicen, al menos hay opciones.

Y así, recoja el hardware y cargue el sistema desde la unidad flash Ubuntu Live de arranque. Tendremos que descargar paquetes, por lo que configuramos la red, lo que le valió la pena. Si no funciona, puede descargar los paquetes necesarios a la unidad flash USB de antemano.

Entramos en el entorno de escritorio, ejecutamos el emulador de terminal y vamos:

#sudo bash

Cómo...?
sudo. . , . sudo , . :


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

¿Por qué no ZFS ...?
, — , .
, — , - .

ZFS — , mdadm+lvm .

. . . . . . , .

¿Por qué entonces BTRFS ...?
Legacy/BIOS GRUB , , , -. /boot . , / () , LVM .

, .
send/recieve.

, GPU PCI-USB Host- KVM IOMMU.

— , .

ZFS, , , .

, / RAID ZFS, BRTFS LVM.

, BTRFS , / HDD.

Vuelva a escanear todos los dispositivos: echemos un vistazo

#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

Particionar "unidades"


NVMe SSD


Pero de ninguna manera no los marcaremos. De todos modos, nuestro BIOS no ve estas unidades. Entonces, irán completamente a RAID de software. Ni siquiera crearemos particiones allí. Si desea de acuerdo con el "canon" o el "principio", cree una partición grande, como un HDD.

HDD SATA


No hay nada especial para inventar. Crearemos una sección para todo. Crearemos la sección porque el BIOS ve estos discos e incluso puede intentar arrancar desde ellos. Incluso instalaremos GRUB más adelante en estos discos para que el sistema tenga éxito de repente.

#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


Aquí tenemos lo más interesante.

En primer lugar, tenemos unidades de 2 TB. Esto está dentro de los límites permitidos para MBR, que utilizaremos. Si es necesario, puede ser reemplazado por GPT. Los discos GPT tienen una capa de compatibilidad que permite a los sistemas compatibles con MBR ver las primeras 4 particiones si están ubicadas dentro de los primeros 2 terabytes. Lo principal es que la partición de arranque y la partición bios_grub en estos discos deben estar al principio. Esto le permite incluso arrancar desde la unidad GPT Legacy / BIOS.

Pero este no es nuestro caso.

Aquí crearemos dos secciones. El primero tendrá un tamaño de 1 GB y se usará para RAID 1 / arranque.

El segundo se usará para RAID 6 y ocupará todo el espacio libre restante con la excepción de un área pequeña no asignada al final de la unidad.

¿Cuál es el área no asignada?
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

Crear matrices


Primero tenemos que cambiar el nombre del auto. Esto es necesario porque el nombre de host es parte del nombre de la matriz en algún lugar dentro de mdadm y afecta algo en algún lugar. Las matrices, por supuesto, se pueden renombrar más tarde, pero estas son acciones innecesarias.

#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

¿Por qué ... supongo que limpio ...?
. 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.

Atención, el siguiente comando destruirá todos los datos en las unidades NVMe al "inicializar" la matriz con "ceros".

#blkdiscard /dev/md0

Si algo salió mal, intente especificar un paso.

#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

¿Por qué tan grande ...?
chunk-size chunk-size . , . , IOPS . 99% IO 512K.

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

Todavía no hemos habilitado DISCARD para RAID 6. Por lo tanto, todavía no "inicializaremos" esta matriz. Lo haremos más tarde, después de instalar el sistema operativo.

HDD SATA


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

LVM en NVMe RAID


Para mayor velocidad, queremos colocar el FS raíz en NVMe RAID 1, que es / dev / md0.
Sin embargo, todavía necesitamos esta matriz rápida para otras necesidades, como intercambio, metadatos y LVM-cache y metadatos delgados LVM, por lo tanto, en esta matriz crearemos LVM VG. Cree una partición para el FS raíz. Crea una sección para intercambiar el tamaño de RAM.

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




#lvcreate -L 128G --name root root



#lvcreate -L 32G --name swap root

Instalación del sistema operativo


En total, tenemos todo lo necesario para instalar el sistema.

Inicie el asistente de instalación desde el entorno Ubuntu Live. Instalación normal Solo en la etapa de selección de unidades para la instalación, debe especificar lo siguiente:

  • / dev / md1, - punto de montaje / arranque, FS - BTRFS
  • / dev / root / root (también conocido como / dev / mapper / root-root), - punto de montaje / (root), FS - BTRFS
  • / dev / root / swap (también conocido como / dev / mapper / root-swap), se usa como partición de intercambio
  • Instalación del cargador de arranque en / dev / sda

Si selecciona BTRFS como FS raíz, el instalador creará automáticamente dos volúmenes BTRFS con los nombres "@" para / (root) y "@home" para / home.

Comenzamos la instalación ... La

instalación finalizará con un cuadro de diálogo modal que informa sobre el error de instalación del cargador de arranque. Desafortunadamente, salir de este diálogo por medios regulares y continuar con la instalación fallará. Salimos del sistema e iniciamos sesión nuevamente, entrando en el limpio escritorio de Ubuntu Live. Abra el terminal y nuevamente:

#sudo bash

cree un entorno chroot para continuar la instalación: configure la red y el nombre de host en chroot: vaya al entorno chroot: primero entregamos los paquetes: verifique y repare todos los paquetes que se torcieron debido a la instalación incompleta del sistema:

#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 algo no crece juntos, es posible que necesite

editar /etc/apt/sources.list antes de eso. Cambiemos los parámetros para el módulo RAID 6 para habilitar TRIM / DISCARD: Ajustaremos ligeramente nuestros arreglos:

#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é era..?
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 .


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

Porqué es eso..?
/boot UUID .. .

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

UUID LVM .. UUID LVM .
¿Dos veces montamos / dev / mapper / root-root ..?
. . BTRFS. subvol.

- LVM BTRFS . .

Regeneramos la configuración de mdadm: corrija la configuración de 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é era..?
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, , .

Actualice la imagen initramfs:

#update-initramfs -u -k all

instale y configure grub:

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


¿Qué impulsa a elegir?
sd*. SATA SSD.

¿Por qué clavado os-prober ..?
.

RAID- . , .

, , , . .

Con esto, completamos la instalación inicial. Es hora de reiniciar en el sistema operativo recién instalado. Recuerde quitar el Live CD / USB de arranque. Como dispositivo para iniciar, seleccione cualquiera de los SSD SATA.

#exit
#reboot




SSD LVM a SATA


En este punto, ya hemos arrancado en el nuevo sistema operativo, configuramos la red, apt, abrimos el emulador de terminal y comenzamos:

#sudo bash

Continuar.

"Inicialice" una matriz de SSD SATA:

#blkdiscard /dev/md2

si no lo hace, intente:

#blkdiscard --step 65536 /dev/md2
Crear LVM VG en un SSD SATA:

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


¿Por qué otra 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-, . , , .

, , - .

HDD LVM a SATA


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


De nuevo el nuevo VG ..?
, , , , - . , - VG, — VG.

Configurar caché LVM


Cree LV en NVMe RAID 1 para usarlo como dispositivo de almacenamiento en caché.

#lvcreate -L 70871154688B --name cache root

¿Por qué tan poco ...?
, NVMe SSD SLC . 4 «» 18 3-bit MLC. - NVMe SSD SATA SSD . , LVM cache SLC NVMe . NVMe 32-64 .

64 , .

, LVM . , lvchange . , .

Creemos LV en SATA RAID 6 para usarlo como un dispositivo en caché.

#lvcreate -L 3298543271936B --name cache data

¿Por qué solo tres terabytes ...?
, , SATA SSD RAID 6 - . , , . , , LVM-cache , , bcache, , .

Crea un nuevo VG para el almacenamiento en caché. Crear LV en el dispositivo en caché. Aquí tomamos inmediatamente todo el espacio libre en / dev / data / cache para que todas las demás particiones necesarias se hayan creado inmediatamente en / dev / root / cache. Si tiene algo no creado allí, puede moverlo usando pvmove. Crea y habilita el caché:

#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

¿Por qué tan chunksize ..?
, LVM cache LVM thin. , , .

64 — LVM thin.

Precaución reescritura ..!
. . , , , . , , NVMe RAID 1 , .

, RAID 6 .

Verifiquemos que hayamos tenido éxito: solo [cachedata_corig] debe ubicarse en / dev / data / cache. Si algo está mal, entonces use pvmove. Si es necesario, puede deshabilitar el caché con un comando: esto se hace en línea. LVM simplemente sincroniza el caché al disco, lo elimina y cambia el nombre de cachedata_corig a 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



Configuración delgada de LVM


Calcularemos aproximadamente cuánto espacio necesitaremos para los metadatos delgados LVM : redondee hasta 4 gigabytes: 4294967296B Multiplique por dos y agregue 4194304B para los metadatos LVM PV: 8594128896B Cree una partición separada en NVMe RAID 1 para marcar metadatos delgados LVM en él y hacer una copia de seguridad:

#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

Para qué..?
, LVM thin , NVMe .

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

- -, , , . , . .

, , , , , , LVM thin, .

Cree un nuevo VG que se encargará del aprovisionamiento delgado: cree un grupo:

#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
Por qué -Z y
, , — , — zeroing 64k. 64k 64K . .

Muevamos LV a los PV correspondientes: Verificar: Crear un volumen delgado para pruebas: Poner paquetes para pruebas y observaciones: Así es como puedes observar el comportamiento de nuestra configuración de almacenamiento en tiempo real: Así es como puedes probar nuestra configuración:

#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

¡Precaución! ¡Recurso!
36 , 4 . . 4 NVMe . 3 . , 216 SSD.

Lectura y escritura aleatoria?
. . , , , .

Los resultados variarán enormemente en el primer inicio y los posteriores a medida que se llenen el caché y el volumen delgado, y también, dependiendo de si el sistema logró sincronizar los cachés llenados en el último inicio.

Entre otras cosas, recomiendo medir la velocidad en el volumen delgado ya lleno desde el que se acaba de hacer la instantánea. El autor tuvo la oportunidad de observar cómo una grabación aleatoria acelera bruscamente inmediatamente después de crear la primera instantánea, especialmente cuando el caché aún no está lleno. Esto se debe a la semántica de escritura de copia en escritura, la alineación de los bloques de caché y los volúmenes delgados, y el hecho de que la escritura aleatoria en RAID 6 se convierte en lectura aleatoria desde RAID 6 y luego escribe en la caché. En nuestra configuración, la lectura aleatoria de RAID 6 hasta 6 veces (la cantidad de SSD SATA en la matriz) es más rápida que la escritura. Porque Dado que los bloques CoW se asignan secuencialmente desde un grupo delgado, el registro, en su mayor parte, también se convierte en secuencial.

Ambas características se pueden usar ventajosamente.

Caché de instantáneas "coherentes"


Para reducir el riesgo de pérdida de datos en caso de daño / pérdida de caché, el autor sugiere introducir la práctica de instantáneas rotativas para garantizar su integridad en este caso.

En primer lugar, debido al hecho de que los metadatos de los volúmenes delgados se encuentran en un dispositivo sin caché, los metadatos serán consistentes y las posibles pérdidas se aislarán dentro de los bloques de datos.

El siguiente ciclo de rotación de instantáneas garantiza la integridad de los datos dentro de las instantáneas en caso de pérdida de caché:

  1. Para cada volumen delgado con el nombre <nombre>, cree una instantánea con el nombre <nombre> .cached
  2. Establezca el umbral de migración en un valor alto razonable: #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 esquema de rotación tan simple para las instantáneas nos permitirá no solo tener una instantánea sincronizada completamente en el SSD SATA, sino también con la ayuda de la utilidad thin_delta para descubrir qué bloques se modificaron después de su creación, y así localizar el daño en los volúmenes principales, lo que hace que sea mucho más fácil restaurar .

RECORTAR / DESCARGAR en libvirt / KVM


Porque Dado que el almacén de datos se usará para KVM ejecutando libvirt, sería bueno enseñar a nuestras máquinas virtuales no solo a ocupar espacio libre, sino también a liberar lo que ya no es necesario.

Esto se realiza emulando el soporte TRIM / DISCARD en discos virtuales. Para hacer esto, cambie el tipo de controlador a virtio-scsi y edite el xml. DESECHOS similares de los SO invitados son procesados ​​correctamente por LVM, y los bloques se liberan correctamente tanto en el caché como en el grupo delgado. En nuestro caso, esto sucede, principalmente, pospuesto, cuando elimina la siguiente instantánea.

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


Utilice guiones preparados con extrema precaución y bajo su propio riesgo y riesgo . El autor escribió este código él mismo y exclusivamente para sí mismo. Estoy seguro de que muchos usuarios experimentados de Linux tienen esas muletas de experiencia, y copiar otros no será necesario.

Cree un volumen en el dispositivo de respaldo:

#lvcreate -L 256G --name backup backup

Formatee en BTRFS:

#mkfs.btrfs /dev/backup/backup

Cree puntos de montaje y monte subclaves raíz del FS: Cree directorios para respaldos: Cree un directorio para scripts de respaldo: Copie el 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



Un montón de código bash aterrador. Úselo bajo su propio riesgo. El autor no escribe cartas enojadas ...
#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


¿Qué hace incluso?
BTRFS BTRFS send/recieve.

El primer lanzamiento puede ser relativamente largo, porque Al principio se copiarán todos los datos. Otros lanzamientos serán muy rápidos, porque solo se copiarán los cambios.

Otro script para meter en cron:

Un poco más de código 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á haciendo ..?
backup BTRFS-. 60 . /backup/btrfs/back/remote/ .

Démosle al código el derecho de ejecución: verifica y mete las coronas:

#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

Copia de seguridad delgada LVM


Cree un grupo delgado en el dispositivo de respaldo:

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

instale ddrescue, porque los scripts usarán esta herramienta:

#apt-get install gddrescue

Cree un directorio para los scripts:

#mkdir /root/lvm-thin-backup

copie los scripts:

Mucha fiesta dentro ...
#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á haciendo ...?
, thin_delta, ddrescue blkdiscard.

Otro guión que vamos a meter en coronas:

Un poco más 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á haciendo ...?
, . , .

Este script debe editarse, lo que indica una lista de volúmenes delgados para los que se requieren copias de seguridad. Los nombres dados son solo para fines ilustrativos. Si lo desea, puede escribir un script que sincronice todos los volúmenes.

Demos derechos: revisa y mete las coronas: el primer lanzamiento será largo, porque los volúmenes delgados se sincronizarán completamente copiando todo el espacio utilizado. Gracias a los metadatos delgados de LVM, sabemos qué bloques se usan realmente, por lo que solo se copiarán los bloques reales de volúmenes delgados. Los lanzamientos posteriores copiarán datos de forma incremental mediante el seguimiento de los cambios a través de metadatos delgados 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





Vamos a ver que pasó:


#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

¿Y las muñecas que anidan?


Lo más probable, aunque los volúmenes lógicos LVM LV pueden ser volúmenes FV LVM físicos para otros VG. LVM puede ser recursivo, como las muñecas de anidación. Esto le da a LVM una flexibilidad extrema.

PD


En el próximo artículo, intentaremos utilizar varios sistemas de almacenamiento móvil / KVM similares como base para crear un clúster de almacenamiento distribuido / vm geo-distribuido con redundancia en varios continentes a través de escritorios domésticos, Internet doméstica y redes P2P.

All Articles