O que é comum entre LVM e matryoshka?

Dia bom.
Quero compartilhar com a experiência prática da comunidade na construção de um sistema de armazenamento para KVM usando md RAID + LVM.

O programa irá:

  • Crie o md RAID 1 a partir do NVMe SSD.
  • Crie o md RAID 6 a partir do SATA SSD e unidades regulares.
  • Recursos do TRIM / DISCARD no SSD RAID 1/6.
  • Criando uma matriz md RAID 1/6 inicializável em um conjunto comum de discos.
  • Instalando o sistema no NVMe RAID 1 se não houver suporte ao NVMe no BIOS.
  • Usando cache LVM e LVM thin.
  • Usando instantâneos BTRFS e enviar / receber para backup.
  • Usando instantâneos finos do LVM e thin_delta para backup no estilo BTRFS.

Se estiver interessado, por favor, em cat.

Declaração


O autor não se responsabiliza pelas consequências do uso ou não dos materiais / exemplos / códigos / dicas / dados deste artigo. Ao ler ou usar este material de qualquer forma, você assume a responsabilidade por todas as consequências dessas ações. As possíveis consequências incluem:

  • SSD NVMe frito e crocante.
  • Recurso de gravação completamente usado e falha de unidades SSD.
  • Perda completa de todos os dados em todas as unidades, incluindo backups.
  • Hardware de computador com defeito.
  • Passou tempo, nervos e dinheiro.
  • Quaisquer outros efeitos não listados acima.

Ferro


Em estoque foi:


A placa-mãe está por volta de 2013 no chipset Z87 completo com Intel Core i7 / Haswell.

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

O adaptador SAS LSI SAS9211-8I piscou no modo IT / HBA. O firmware ativado para RAID foi intencionalmente substituído pelo firmware HBA para:

  1. Era possível a qualquer momento jogar este adaptador e substituí-lo por qualquer outro primeiro.
  2. TRIM / Descartar funcionou normalmente em discos, como no firmware RAID, esses comandos não são suportados e o HBA, em geral, não se importa com os comandos a serem enviados no barramento.

Discos rígidos - 8 peças do HGST Travelstar 7K1000 com um volume de 1 TB no fator de forma 2,5, como para laptops. Essas unidades estavam anteriormente em uma matriz RAID 6. No novo sistema, eles também encontrarão aplicativos. Para armazenar backups locais.

Além disso, foi adicionado:


6 peças de modelo SSD SATA Samsung 860 QVO 2TB. Esses SSDs exigiam uma grande quantidade, a presença de um cache SLC, a confiabilidade é desejável e um preço baixo. Obrigatório era o suporte para descarte / zero, verificado por uma linha no dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 peças do modelo NVMe SSD modelo Samsung SSD 970 EVO 500GB.

Para esses SSDs, a velocidade aleatória de leitura / gravação e um recurso para suas necessidades são importantes. Radiador para eles. Obrigatório. Absolutamente necessário. Caso contrário, frite-os até ficarem crocantes durante a primeira sincronização do RAIDa.

Adaptador StarTech PEX8M2E2 para 2 SSDs NVMe com slot PCIe 3.0 8x. Novamente, isso é apenas HBA, mas para o NVMe. Difere dos adaptadores baratos na ausência do requisito de suporte à bifurcação PCIe da placa-mãe devido à presença de um comutador PCIe integrado. Ele funcionará mesmo no sistema mais antigo em que houver PCIe, mesmo que seja um slot PCIe 1.0 x1. Naturalmente, com a velocidade adequada. Não há RAIDs lá. Não há BIOS integrado a bordo. Portanto, seu sistema não aprenderá magicamente a inicialização a partir do NVMe, muito menos o NVMe RAID graças a este dispositivo.

Esse componente foi causado exclusivamente pela presença de apenas um 8x PCIe 3.0 gratuito no sistema e, com 2 slots livres, é facilmente substituído por dois PEX4M2E1 ou análogos baratos, que podem ser comprados em qualquer lugar a um preço de 600 rublos.

A rejeição de todos os tipos de hardware ou chipsets / BIOS RAID integrados foi feita deliberadamente, para poder substituir completamente o sistema inteiro, com exceção do próprio SSD / HDD, salvando todos os dados. Idealmente, seria possível manter o sistema operacional instalado ao mudar para um hardware completamente novo / diferente. O principal é que existem portas SATA e PCIe. É como um CD ao vivo ou uma unidade flash inicializável, apenas muito rápida e um pouco grande demais.

Humor
, , — . . 5.25 .

Bem, e, é claro, para experimentar diferentes métodos de armazenamento em cache SSD no Linux.
Invasões de hardware, é chato. Ligar. Funciona ou não. E com o mdadm sempre há opções.

Suave


Anteriormente, o Debian 8 Jessie era instalado no hardware, próximo ao EOL. O RAID 6 dos HDDs mencionados acima foi emparelhado com o LVM. Ele estava executando máquinas virtuais no kvm / libvirt.

Porque O autor tem a experiência apropriada na criação de unidades flash SATA / NVMe inicializáveis ​​portáteis e também, para não rasgar o modelo apt usual, o Ubuntu 18.04 foi escolhido como o sistema de destino, que já se estabilizou o suficiente, mas ainda tem 3 anos de suporte no futuro.

No sistema mencionado, existem todos os drivers de hardware necessários imediatamente. Não precisamos de software e drivers de terceiros.

Preparação para instalação


Para instalar o sistema, precisamos do Ubuntu Desktop Image. O sistema do servidor possui algum tipo de instalador vigoroso que exibe independência excessiva e não desconectável, sempre empurrando a partição do sistema UEFI para um dos discos que estraga toda a beleza. Portanto, ele é instalado apenas no modo UEFI. Não oferece opções.

Isso não nos convém.

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

, UEFI NVRAM, , .. .

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

A versão desktop do Ubuntu também não sabe como instalar normalmente com o carregador de inicialização Legacy, mas aqui, como se costuma dizer, pelo menos existem opções.

E assim, colete o hardware e carregue o sistema a partir da unidade flash inicializável do Ubuntu Live. Nós precisaremos fazer o download dos pacotes, por isso, configuramos a rede que ganhou você. Se não funcionar, você pode baixar os pacotes necessários para a unidade flash USB com antecedência.

Entramos no ambiente Desktop, executamos o emulador de terminal e vamos:

#sudo bash

Quão...?
sudo. . , . sudo , . :


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

Por que não o ZFS ...?
, — , .
, — , - .

ZFS — , mdadm+lvm .

. . . . . . , .

Por que então o BTRFS ...?
Legacy/BIOS GRUB , , , -. /boot . , / () , LVM .

, .
send/recieve.

, GPU PCI-USB Host- KVM IOMMU.

— , .

ZFS, , , .

, / RAID ZFS, BRTFS LVM.

, BTRFS , / HDD.

Verifique novamente todos os dispositivos: vamos dar uma olhada

#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

Particionando "unidades"


NVMe SSD


Mas, de qualquer forma, não os marcaremos. Mesmo assim, nosso BIOS não vê essas unidades. Então, eles irão inteiramente para o software RAID. Nem criaremos partições lá. Se você quiser, de acordo com o "cânone" ou o "princípio" - crie uma partição grande, como um disco rígido.

HDD SATA


Não há nada de especial para inventar. Vamos criar uma seção para tudo. Criaremos a seção porque o BIOS vê esses discos e pode até tentar inicializá-los. Até instalaremos o GRUB posteriormente nesses discos, para que o sistema tenha êxito repentino.

#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


Aqui temos o mais interessante.

Em primeiro lugar, temos 2 unidades de TB. Isso está dentro dos limites permitidos para o MBR, que usaremos. Se necessário, pode ser substituído pelo GPT. Os discos GPT têm uma camada de compatibilidade que permite que sistemas compatíveis com MBR vejam as 4 primeiras partições se estiverem localizados nos 2 primeiros terabytes. O principal é que a partição de inicialização e a partição bios_grub nesses discos devem estar no início. Isso permite que você inicialize a partir da unidade GPT Legacy / BIOS.

Mas, este não é o nosso caso.

Aqui vamos criar duas seções. O primeiro terá 1 GB de tamanho e será usado para RAID 1 / boot.

O segundo será usado para o RAID 6 e ocupará todo o espaço livre restante, com exceção de uma pequena área não alocada no final da unidade.

Qual é a área não alocada?
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

Criando matrizes


Primeiro precisamos renomear o carro. Isso é necessário porque o nome do host faz parte do nome da matriz em algum lugar dentro do mdadm e afeta algo em algum lugar. Matrizes, é claro, podem ser renomeadas mais tarde, mas essas são ações desnecessárias.

#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 que - assumir limpo ...?
. 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.

Atenção, o comando a seguir destruirá todos os dados nas unidades NVMe “inicializando” a matriz com “zeros”.

#blkdiscard /dev/md0

Se algo der errado, tente especificar uma etapa.

#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 que tão 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.

Ainda não ativamos o DISCARD for RAID 6. Portanto, ainda não iremos "inicializar" esse array. Faremos isso mais tarde, depois de instalar o sistema operacional.

HDD SATA


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

LVM no NVMe RAID


Para velocidade, queremos colocar o FS raiz no NVMe RAID 1, que é / dev / md0.
No entanto, ainda precisamos desse array rápido para outras necessidades, como swap, metadados e cache LVM e metadados thin-LVM; portanto, nesse array, criaremos o LVM VG. Crie uma partição para o FS raiz. Crie uma seção para trocar o tamanho da RAM.

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




#lvcreate -L 128G --name root root



#lvcreate -L 32G --name swap root

Instalação do SO


No total, temos todo o necessário para instalar o sistema.

Inicie o assistente de instalação no ambiente Ubuntu Live. Instalação normal. Somente no estágio de seleção de unidades para instalação, você precisa especificar o seguinte:

  • / dev / md1, - ponto de montagem / inicialização, FS - BTRFS
  • / dev / root / root (também conhecido como / dev / mapper / root-root), - ponto de montagem / (root), FS - BTRFS
  • / dev / root / swap (também conhecido como / dev / mapper / root-swap), - use como partição swap
  • Instalação do carregador de inicialização em / dev / sda

Se você selecionar BTRFS como o FS raiz, o instalador criará automaticamente dois volumes BTRFS com os nomes "@" para / (root) e "@home" para / home.

Iniciamos a instalação ... A

instalação terminará com uma caixa de diálogo modal informando sobre o erro de instalação do carregador de inicialização. Infelizmente, sair desse diálogo por meios regulares e continuar a instalação falhará. Nós saímos do sistema e entramos novamente, entrando na área de trabalho limpa do Ubuntu Live. Abra o terminal e novamente:

#sudo bash

Crie um ambiente chroot para continuar a instalação: Configure a rede e o nome do host no chroot: Vá para o ambiente chroot: Primeiro, entregamos os pacotes: Verifique e corrija todos os pacotes que estavam torcidos devido à instalação incompleta do 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

Se algo não crescer junto, talvez seja necessário

editar o arquivo /etc/apt/sources.list antes disso. Vamos alterar os parâmetros do módulo RAID 6 para ativar TRIM / DISCARD: Vamos ajustar um pouco as matrizes:

#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

O que foi isso..?
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 .


Edite o / 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

Por que é que..?
/boot UUID .. .

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

UUID LVM .. UUID LVM .
Duas vezes montamos / dev / mapper / root-root ..?
. . BTRFS. subvol.

- LVM BTRFS . .

Regeneramos a configuração do mdadm: Corrija as configurações do 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

O que foi isso..?
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, , .

Atualize a imagem initramfs:

#update-initramfs -u -k all

Instale e configure o grub:

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


Quais unidades escolher?
sd*. SATA SSD.

Por que pregado os-prober ..?
.

RAID- . , .

, , , . .

Com isso, concluímos a instalação inicial. É hora de reiniciar no sistema operacional recém-instalado. Lembre-se de remover o Live CD / USB inicializável. Como um dispositivo para inicializar, selecione qualquer um dos SSDs SATA.

#exit
#reboot




SSD de LVM para SATA


Neste ponto, já iniciamos o novo sistema operacional, configuramos a rede, apt, abrimos o emulador de terminal e começamos:

#sudo bash

Continue.

"Inicialize" uma matriz do SATA SSD:

#blkdiscard /dev/md2

se não estiver, tente:

#blkdiscard --step 65536 /dev/md2
Criar LVM VG em um SATA SSD:

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


Por que outra vg ..?
, VG root. VG?

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

, ( ) RAID 6 .

, «» VG.

-, RAID « ». , VG.

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

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

, , - .

LVM para SATA HDD


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


Mais uma vez o novo VG ..?
, , , , - . , - VG, — VG.

Configurar cache LVM


Crie o LV no NVMe RAID 1 para usá-lo como um dispositivo de armazenamento em cache.

#lvcreate -L 70871154688B --name cache root

Por que tão pouco ...?
, NVMe SSD SLC . 4 «» 18 3-bit MLC. - NVMe SSD SATA SSD . , LVM cache SLC NVMe . NVMe 32-64 .

64 , .

, LVM . , lvchange . , .

Vamos criar LV no SATA RAID 6 para usá-lo como um dispositivo em cache.

#lvcreate -L 3298543271936B --name cache data

Por que apenas três terabytes ..?
, , SATA SSD RAID 6 - . , , . , , LVM-cache , , bcache, , .

Crie um novo VG para armazenamento em cache. Crie LV no dispositivo em cache. Aqui, ocupamos imediatamente todo o espaço livre em / dev / data / cache, para que todas as outras partições necessárias fossem criadas imediatamente em / dev / root / cache. Se você tiver algo que não foi criado lá, poderá movê-lo usando pvmove. Crie e ative o 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

Por que tão chunksize ..?
, LVM cache LVM thin. , , .

64 — LVM thin.

Cuidado writeback ..!
. . , , , . , , NVMe RAID 1 , .

, RAID 6 .

Vamos verificar se conseguimos: Apenas [cachedata_corig] deve estar localizado em / dev / data / cache. Se algo estiver errado, use pvmove. Se necessário, você pode desativar o cache com um comando: Isso é feito on-line. O LVM simplesmente sincroniza o cache no disco, o exclui e renomeia cachedata_corig de volta para 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



Configuração fina do LVM


Estimaremos aproximadamente o espaço necessário para os metadados finos do LVM: Arredonde até 4 gigabytes: 4294967296B Multiplique por dois e adicione 4194304B para os metadados do LVM PV: 8594128896B Crie uma partição separada no NVMe RAID 1 para marcar os metadados finos do LVM nele e faça o backup:

#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

Pelo que..?
, LVM thin , NVMe .

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

- -, , , . , . .

, , , , , , LVM thin, .

Crie um novo VG que será responsável pelo thin provisioning: Crie um 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
Por que -Z y
, , — , — zeroing 64k. 64k 64K . .

Mova o LV para os PVs correspondentes: Verifique: Crie um pequeno volume para testes: Coloque pacotes para testes e monitoramento: É assim que você pode observar o comportamento de nossa configuração de armazenamento em tempo real: É assim que você pode testar nossa configuração:

#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

Cuidado! Recurso!
36 , 4 . . 4 NVMe . 3 . , 216 SSD.

Leitura e escrita aleatória?
. . , , , .

Os resultados variarão bastante na primeira inicialização e nos subsequentes conforme o cache e o volume fino forem preenchidos e também, dependendo se o sistema conseguiu sincronizar os caches preenchidos na última inicialização.

Entre outras coisas, recomendo medir a velocidade no volume fino já preenchido a partir do qual o instantâneo acabou de ser feito. O autor teve a oportunidade de observar como uma gravação aleatória acelera acentuadamente imediatamente após a criação do primeiro instantâneo, especialmente quando o cache ainda não está cheio. Isso ocorre devido à semântica da gravação na cópia, alinhamento de blocos de cache e volumes finos, e o fato de a gravação aleatória no RAID 6 se transformar em leitura aleatória do RAID 6 e depois gravar no cache. Em nossa configuração, a leitura aleatória do RAID 6 até 6 vezes (o número de SSDs SATA na matriz) é mais rápida que a gravação. Porque Como os blocos CoW são alocados seqüencialmente a partir de um thin pool, o registro, na maioria das vezes, também se transforma em sequencial.

Ambos os recursos podem ser utilizados com vantagem.

Instantâneos "coerentes" do cache


Para reduzir o risco de perda de dados em caso de dano / perda de cache, o autor sugere a introdução da prática de girar instantâneos para garantir sua integridade neste caso.

Em primeiro lugar, devido ao fato de os metadados de volumes finos estarem localizados em um dispositivo não armazenado em cache, os metadados serão consistentes e as possíveis perdas serão isoladas dentro dos blocos de dados.

O seguinte ciclo de rotação de snapshot garante a integridade dos dados dentro dos snapshots em caso de perda de cache:

  1. Para cada volume fino com o nome <name>, crie uma captura instantânea com o nome <name> .cached
  2. Defina o limite de migração para um valor alto razoável: #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 , .

Um esquema de rotação tão simples para instantâneos nos permitirá não apenas ter constantemente um instantâneo totalmente sincronizado no SSD SATA, mas também com a ajuda do utilitário thin_delta para descobrir quais blocos foram alterados após sua criação e, assim, localizar o dano nos volumes principais, facilitando muito a restauração .

TRIM / DISCARD em libvirt / KVM


Porque Como o data warehouse será usado para o KVM executando a libvirt, seria bom ensinar nossas VMs não apenas a ocupar espaço livre, mas também a liberar o que não é mais necessário.

Isso é feito emulando o suporte TRIM / DISCARD em discos virtuais. Para fazer isso, altere o tipo de controlador para virtio-scsi e edite o xml. DISCARDs semelhantes de sistemas operacionais convidados são processados ​​corretamente pelo LVM e os blocos são liberados corretamente no cache e no thin pool. No nosso caso, isso acontece, principalmente, adiado quando você exclui o próximo instantâneo.

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



Backup de BTRFS


Use scripts prontos com extrema cautela e por seu próprio risco e risco . O autor escreveu esse código ele mesmo e exclusivamente para si mesmo. Estou certo de que muitos usuários experientes do Linux têm essas muletas de experiência e outras pessoas de cópia não precisarão.

Crie um volume no dispositivo de backup:

#lvcreate -L 256G --name backup backup

Formate-o em BTRFS:

#mkfs.btrfs /dev/backup/backup

Crie pontos de montagem e subchaves raiz do FS: Crie diretórios para backups: Crie um diretório para scripts de backup: Copie o 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



Um monte de código bash assustador. Use por sua conta e risco. O autor não escreve cartas raivosas ...
#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


O que isso faz ..?
BTRFS BTRFS send/recieve.

O primeiro lançamento pode ser relativamente longo, porque no início todos os dados serão copiados. Novos lançamentos serão muito rápidos, porque somente as alterações serão copiadas.

Outro script para inserir no cron:

Um pouco mais 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


O que isso está fazendo ..?
backup BTRFS-. 60 . /backup/btrfs/back/remote/ .

Vamos dar ao código o direito de executar: Verifique e empurre as coroas:

#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

Backup thin do LVM


Crie um pool fino no dispositivo de backup:

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

instale o ddrescue, porque Os scripts usarão esta ferramenta:

#apt-get install gddrescue

Crie um diretório para scripts:

#mkdir /root/lvm-thin-backup

Copie os scripts:

Muita festa por 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


O que isso está fazendo ...?
, thin_delta, ddrescue blkdiscard.

Outro script que vamos colocar em coroas:

Um pouco mais de festa
#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


O que isso está fazendo ...?
, . , .

Esse script precisa ser editado, indicando uma lista de volumes thin para os quais os backups são necessários. Os nomes dados são apenas para fins ilustrativos. Se desejar, você pode escrever um script que sincronize todos os volumes.

Vamos dar direitos: Verifique e enfie as coroas: o primeiro lançamento será longo, porque volumes finos serão totalmente sincronizados, copiando todo o espaço usado. Graças aos metadados finos do LVM, sabemos quais blocos são realmente usados, portanto, apenas os blocos reais de volumes finos serão copiados. Os lançamentos subsequentes copiarão os dados de forma incremental, rastreando as alterações através dos metadados finos do 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 ver o que aconteceu:


#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

E quanto a aninhar bonecas?


Muito provavelmente, embora os volumes lógicos do LVM LV possam ser volumes físicos do LVM PV para outros VGs. O LVM pode ser recursivo, como bonecas aninhadas. Isso fornece ao LVM extrema flexibilidade.

PS


No próximo artigo, tentaremos usar vários sistemas de armazenamento móvel / KVMs semelhantes como base para criar um cluster de armazenamento / vm distribuído geograficamente com backup em vários continentes através de desktops domésticos, Internet doméstica e redes P2P.

All Articles