Què tenen en comú LVM i Matryoshka?

Bon dia.
M'agradaria compartir amb la comunitat la meva experiència pràctica en la construcció d'un sistema d'emmagatzematge de dades per a KVM mitjançant md RAID + LVM.

El programa inclourà:

  • Construcció md RAID 1 des de l'SSD NVMe.
  • Muntatge de md RAID 6 des de SSD SATA i unitats normals.
  • Característiques de l'operació TRIM/DISCARD en SSD RAID 1/6.
  • Creació d'una matriu md RAID 1/6 d'arrencada en un conjunt comú de discs.
  • Instal·lació del sistema a NVMe RAID 1 quan no hi ha suport NVMe a la BIOS.
  • Utilitzant la memòria cau LVM i LVM thin.
  • Utilitzant instantànies BTRFS i enviant/reb per a còpia de seguretat.
  • Utilitzant instantànies fines de LVM i thin_delta per a còpies de seguretat d'estil BTRFS.

Si esteu interessats, consulteu cat.

Declaració

L'autor no assumeix cap responsabilitat per les conseqüències de l'ús o no de materials/exemples/codi/consells/dades d'aquest article. En llegir o utilitzar aquest material de qualsevol manera, assumeix la responsabilitat de totes les conseqüències d'aquestes accions. Les possibles conseqüències inclouen:

  • SSD NVMe fregits.
  • Recursos de gravació completament utilitzats i fallades de les unitats SSD.
  • Pèrdua completa de totes les dades de totes les unitats, incloses les còpies de seguretat.
  • Maquinari informàtic defectuós.
  • Perd temps, nervis i diners.
  • Qualsevol altra conseqüència que no estigui enumerada anteriorment.

Ferro

Estaven disponibles:

Placa base de l'any 2013 amb chipset Z87, completa amb Intel Core i7 / Haswell.

  • Processador 4 nuclis, 8 fils
  • 32 GB de RAM DDR3
  • 1 x 16 o 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 connectors SATA 6 de 3 GBps

L'adaptador SAS LSI SAS9211-8I va passar al mode IT/HBA. El microprogramari habilitat per RAID s'ha substituït intencionadament pel microprogramari HBA per:

  1. Podeu llençar aquest adaptador en qualsevol moment i substituir-lo per qualsevol altre que us trobeu.
  2. TRIM/Discard funcionava normalment en discs, perquè... al microprogramari RAID aquestes ordres no són compatibles en absolut, i l'HBA, en general, no li importa quines ordres es transmeten a través del bus.

Discs durs: 8 peces de HGST Travelstar 7K1000 amb una capacitat d'1 TB en un factor de forma 2.5, com per als ordinadors portàtils. Aquestes unitats estaven anteriorment en una matriu RAID 6. També tindran un ús en el nou sistema. Per emmagatzemar còpies de seguretat locals.

Addicionalment afegit:

6 peces SATA SSD model Samsung 860 QVO 2TB. Aquests SSD requerien un gran volum, es desitjava la presència d'una memòria cau SLC, fiabilitat i un preu baix. Es necessitava suport per descartar/zero, que es comprova a la línia de dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 peces de SSD NVMe model Samsung SSD 970 EVO 500GB.

Per a aquests SSD, és important la velocitat de lectura/escriptura aleatòria i la capacitat de recursos per a les vostres necessitats. Radiador per a ells. Necessàriament. Absolutament. En cas contrari, fregiu-los fins que estiguin cruixents durant la primera sincronització RAID.

Adaptador StarTech PEX8M2E2 per a 2 x SSD NVMe instal·lats a la ranura PCIe 3.0 8x. Això, de nou, és només un HBA, però per a NVMe. Es diferencia dels adaptadors barats perquè no requereix suport de bifurcació PCIe de la placa base a causa de la presència d'un commutador PCIe integrat. Funcionarà fins i tot en el sistema més antic amb PCIe, encara que sigui una ranura PCIe 1 x1.0. Naturalment, a la velocitat adequada. No hi ha RAID allà. No hi ha una BIOS integrada a bord. Per tant, el vostre sistema no aprendrà màgicament a arrencar amb NVMe, i molt menys fer-ho NVMe RAID gràcies a aquest dispositiu.

Aquest component es deu únicament a la presència d'un sol PCIe 8 3.0x gratuït al sistema i, si hi ha 2 ranures lliures, es pot substituir fàcilment per dos cèntims PEX4M2E1 o anàlegs, que es poden comprar a qualsevol lloc a un preu de 600 rubles.

El rebuig de tot tipus de maquinari o de chipset/BIOS RAID integrat es va fer deliberadament, per tal de poder substituir completament tot el sistema, amb l'excepció dels propis SSD/HDD, tot conservant totes les dades. L'ideal és que pugueu desar fins i tot el sistema operatiu instal·lat quan passeu a un maquinari completament nou/diferent. El més important és que hi ha ports SATA i PCIe. És com un CD en directe o una unitat flash d'arrencada, només que és molt ràpid i una mica voluminós.

HumorEn cas contrari, ja saps què passa: de vegades necessites portar-te amb urgència tota la matriu per emportar-te. Però no vull perdre dades. Per fer-ho, tots els suports esmentats es troben convenientment situats a les diapositives de les badies 5.25 de la caixa estàndard.

Bé, i, per descomptat, per experimentar amb diferents mètodes de memòria cau SSD a Linux.

Els atacs de maquinari són avorrits. Encendre'l. O funciona o no. I amb mdadm sempre hi ha opcions.

Suau

Anteriorment, Debian 8 Jessie s'ha instal·lat al maquinari, que és proper a EOL. RAID 6 es va muntar a partir dels esmentats HDD emparellats amb LVM. Va executar màquines virtuals en kvm/libvirt.

Perquè L'autor té una experiència adequada en la creació de unitats flaix SATA/NVMe d'arrencada portàtils, i també, per no trencar la plantilla apta habitual, es va triar Ubuntu 18.04 com a sistema de destinació, que ja s'ha estabilitzat prou, però encara té 3 anys de suport en el futur.

El sistema esmentat conté tots els controladors de maquinari que necessitem fora de la caixa. No necessitem cap programari ni controladors de tercers.

Preparació per a la instal·lació

Per instal·lar el sistema necessitem Ubuntu Desktop Image. El sistema del servidor té algun tipus d'instal·lador vigorós, que mostra una independència excessiva que no es pot desactivar introduint la partició del sistema UEFI en un dels discs, fent malbé tota la bellesa. En conseqüència, només s'instal·la en mode UEFI. No ofereix cap opció.

No estem contents amb això.

Per què?Malauradament, l'arrencada UEFI és extremadament mal compatible amb el programari d'arrencada RAID, perquè... Ningú ens ofereix reserves per a la partició UEFI ESP. Hi ha receptes en línia que suggereixen col·locar la partició ESP en una unitat flaix en un port USB, però aquest és un punt de fallada. Hi ha receptes que utilitzen el programari mdadm RAID 1 amb metadades versió 0.9 que no impedeixen que la UEFI BIOS vegi aquesta partició, però aquesta viu fins al moment feliç en què la BIOS o un altre sistema operatiu de maquinari escriu alguna cosa a l'ESP i s'oblida de sincronitzar-la amb altres. miralls.

A més, l'arrencada UEFI depèn de la NVRAM, que no es mourà juntament amb els discs al nou sistema, perquè forma part de la placa base.

Per tant, no reinventarem una nova roda. Ja tenim una bicicleta de l'avi preparada i provada en el temps, ara anomenada arrencada Legacy/BIOS, que porta el nom orgullós de CSM en sistemes compatibles amb UEFI. Només el traiem del prestatge, el lubricarem, bombejarem els pneumàtics i el netejarem amb un drap humit.

La versió d'escriptori d'Ubuntu tampoc es pot instal·lar correctament amb el carregador d'arrencada Legacy, però aquí, com diuen, almenys hi ha opcions.

Així, recollim el maquinari i carreguem el sistema des de la unitat flash d'arrencada d'Ubuntu Live. Haurem de descarregar paquets, així que configurarem la xarxa que us funcioni. Si no funciona, podeu carregar els paquets necessaris a una unitat flaix amb antelació.

Entrem a l'entorn d'escriptori, iniciem l'emulador de terminal i anem:

#sudo bash

Com...?La línia de dalt és el desencadenant canònic de holiwars sobre sudo. C bоarriben més oportunitats iоmajor responsabilitat. La pregunta és si pots assumir-ho tu mateix. Molta gent pensa que utilitzar sudo d'aquesta manera, almenys, no té cura. Malgrat això:

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

Per què no ZFS...?Quan instal·lem programari al nostre ordinador, bàsicament prestem el nostre maquinari als desenvolupadors d'aquest programari perquè els condueixin.
Quan confiem en aquest programari la seguretat de les nostres dades, contractem un préstec igual al cost de la restauració d'aquestes dades, que algun dia haurem de pagar.

Des d'aquest punt de vista, ZFS és un Ferrari, i mdadm+lvm s'assembla més a una bicicleta.

Subjectivament, l'autor prefereix prestar una bicicleta a crèdit a persones desconegudes en comptes d'un Ferrari. Allà, el preu del tema no és alt. No calen drets. Més senzill que les normes de trànsit. L'aparcament és gratuït. La capacitat de travessa és millor. Sempre podeu enganxar les cames a una bicicleta, i podeu reparar una bicicleta amb les vostres pròpies mans.

Per què llavors BTRFS...?Per arrencar el sistema operatiu, necessitem un sistema de fitxers compatible amb Legacy/BIOS GRUB i que, alhora, admeti instantànies en directe. L'utilitzarem per a la partició /boot. A més, l'autor prefereix utilitzar aquest FS per a / (arrel), sense oblidar tenir en compte que per a qualsevol altre programari podeu crear particions separades a LVM i muntar-les als directoris necessaris.

No emmagatzemarem cap imatge de màquines virtuals o bases de dades en aquest FS.
Aquest FS només s'utilitzarà per crear instantànies del sistema sense apagar-lo i després transferir aquestes instantànies a un disc de còpia de seguretat mitjançant enviar/rebre.

A més, l'autor generalment prefereix mantenir un mínim de programari directament al maquinari i executar la resta de programari en màquines virtuals utilitzant coses com reenviar GPU i controladors d'amfitrió PCI-USB a KVM mitjançant IOMMU.

Les úniques coses que queden al maquinari són l'emmagatzematge de dades, la virtualització i la còpia de seguretat.

Si confieu més en ZFS, llavors, en principi, per a l'aplicació especificada són intercanviables.

Tanmateix, l'autor ignora deliberadament les funcions de duplicació/RAID i redundància integrades que tenen ZFS, BRTFS i LVM.

Com a argument addicional, BTRFS té la capacitat de convertir escriptures aleatòries en escriptures seqüencials, la qual cosa té un efecte extremadament positiu en la velocitat de sincronització de les instantànies/còpies de seguretat al disc dur.

Tornem a analitzar tots els dispositius:

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

Fem una ullada al voltant:

#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

Disseny del disc

SSD NVMe

Però no els marcarem de cap manera. Tot i així, la nostra BIOS no veu aquestes unitats. Per tant, aniran completament al programari RAID. Ni tan sols crearem seccions allà. Si voleu seguir el "canon" o "principalment", creeu una partició gran, com un disc dur.

Disc dur SATA

Aquí no cal inventar res especial. Crearem una secció per a tot. Crearem una partició perquè la BIOS veu aquests discs i fins i tot pot intentar arrencar des d'ells. Fins i tot instal·larem GRUB en aquests discs més endavant perquè el sistema pugui fer-ho de sobte.

#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í és on les coses es posen interessants per a nosaltres.

En primer lloc, les nostres unitats tenen una mida de 2 TB. Això es troba dins del rang acceptable per a MBR, que és el que farem servir. Si cal, es pot substituir per GPT. Els discs GPT tenen una capa de compatibilitat que permet als sistemes compatibles amb MBR veure les 4 primeres particions si es troben dins dels primers 2 terabytes. El més important és que la partició d'arrencada i la partició bios_grub d'aquests discs haurien d'estar al principi. Això fins i tot us permet arrencar des de les unitats GPT Legacy/BIOS.

Però aquest no és el nostre cas.

Aquí crearem dues seccions. El primer tindrà una mida d'1 GB i s'utilitzarà per a RAID 1 /boot.

El segon s'utilitzarà per a RAID 6 i ocuparà tot l'espai lliure restant excepte una petita àrea no assignada al final de la unitat.

Quina és aquesta zona no marcada?Segons fonts de la xarxa, els nostres SSD SATA tenen a bord una memòria cau SLC expandible dinàmicament que oscil·la entre 6 i 78 gigabytes. Obtenim 6 gigabytes "gratis" a causa de la diferència entre "gigabytes" i "gibibytes" al full de dades de la unitat. Els 72 gigabytes restants s'assignen des de l'espai no utilitzat.

Aquí cal tenir en compte que tenim una memòria cau SLC i l'espai està ocupat en mode MLC de 4 bits. El que per a nosaltres significa efectivament que per cada 4 gigabytes d'espai lliure només tindrem 1 gigabyte de memòria cau SLC.

Multiplica 72 gigabytes per 4 i aconsegueix 288 gigabytes. Aquest és l'espai lliure que no marcarem per permetre que les unitats facin un ús complet de la memòria cau SLC.

Així, efectivament obtindrem fins a 312 gigabytes de memòria cau SLC d'un total de sis unitats. De totes les unitats, 2 s'utilitzaran en RAID per a la redundància.

Aquesta quantitat de memòria cau ens permetrà trobar-nos molt poques vegades a la vida real amb una situació en què una escriptura no va a la memòria cau. Això compensa molt bé l'inconvenient més trist de la memòria QLC: la velocitat d'escriptura extremadament baixa quan les dades s'escriuen sense passar per la memòria cau. Si les vostres càrregues no corresponen a això, us recomano que penseu bé quant de temps durarà el vostre SSD amb aquesta càrrega, tenint en compte el TBW del full de dades.

#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

Creació de matrius

Primer, hem de canviar el nom de la màquina. Això és necessari perquè el nom d'amfitrió forma part del nom de la matriu en algun lloc dins de mdadm i afecta alguna cosa en algun lloc. Per descomptat, les matrius es poden canviar de nom més tard, però aquest és un pas innecessari.

#mcedit /etc/hostname
#mcedit /etc/hosts
#hostname
vdesk0

SSD NVMe

#mdadm --create --verbose --assume-clean /dev/md0 --level=1 --raid-devices=2 /dev/nvme[0-1]n1

Per què -assum-netejar...?Per evitar la inicialització de matrius. Per als dos nivells de RAID 1 i 6 això és vàlid. Tot pot funcionar sense inicialització si es tracta d'una matriu nova. A més, inicialitzar la matriu SSD després de la creació és un malbaratament de recursos TBW. Utilitzem TRIM/DISCARD sempre que sigui possible en matrius SSD muntades per "inicialitzar-les".

Per a les matrius SSD, s'admet RAID 1 DISCARD des de la caixa.

Per a les matrius SSD RAID 6 DISCARD, l'heu d'activar als paràmetres del mòdul del nucli.

Això només s'ha de fer si tots els SSD que s'utilitzen a les matrius de nivell 4/5/6 d'aquest sistema tenen suport per a discard_zeroes_data. De vegades et trobes amb unitats estranyes que diuen al nucli que aquesta funció és compatible, però de fet no hi és, o la funció no sempre funciona. De moment, el suport està disponible gairebé a tot arreu, però hi ha unitats antigues i firmware amb errors. Per aquest motiu, el suport DISCARD està desactivat per defecte per a RAID 6.

Atenció, l'ordre següent destruirà totes les dades de les unitats NVMe "inicialitzant" la matriu amb "zeros".

#blkdiscard /dev/md0

Si alguna cosa va malament, proveu d'especificar un pas.

#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

Per què tan gran...?Augmentar la mida del tros té un efecte positiu en la velocitat de lectura aleatòria en blocs fins a la mida del tros inclòs. Això passa perquè una operació de la mida adequada o més petita es pot completar completament en un sol dispositiu. Per tant, es resumeixen les IOPS de tots els dispositius. Segons les estadístiques, el 99% de l'IO no supera els 512K.

RAID 6 IOPS per escriptura sempre inferior o igual a les IOPS d'una unitat. Quan, com a lectura aleatòria, les IOPS poden ser diverses vegades més grans que les d'una unitat, i aquí la mida del bloc és de gran importància.
L'autor no veu el sentit d'intentar optimitzar un paràmetre que és dolent en RAID 6 per disseny i, en canvi, optimitza el que RAID 6 és bo.
Compensarem la mala escriptura aleatòria de RAID 6 amb una memòria cau NVMe i trucs d'aprovisionament prim.

Encara no hem habilitat DISCARD per a RAID 6. Per tant, de moment no "inicializarem" aquesta matriu. Ho farem més tard, després d'instal·lar el sistema operatiu.

Disc dur SATA

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

LVM en RAID NVMe

Per a la velocitat, volem col·locar el sistema de fitxers arrel a NVMe RAID 1 que és /dev/md0.
Tanmateix, encara necessitarem aquesta matriu ràpida per a altres necessitats, com ara intercanvi, metadades i metadades de LVM-cache i LVM-thin, de manera que crearem un LVM VG en aquesta matriu.

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

Creem una partició per al sistema de fitxers arrel.

#lvcreate -L 128G --name root root

Creem una partició per intercanviar segons la mida de la memòria RAM.

#lvcreate -L 32G --name swap root

Instal·lació del sistema operatiu

En total, disposem de tot el necessari per instal·lar el sistema.

Inicieu l'assistent d'instal·lació del sistema des de l'entorn Ubuntu Live. Instal·lació normal. Només en l'etapa de selecció de discs per a la instal·lació, heu d'especificar el següent:

  • /dev/md1, - punt de muntatge /boot, FS - BTRFS
  • /dev/root/root (també conegut com /dev/mapper/root-root), - punt de muntatge / (arrel), FS - BTRFS
  • /dev/root/swap (també conegut com /dev/mapper/root-swap), - s'utilitza com a partició d'intercanvi
  • Instal·leu el carregador d'arrencada a /dev/sda

Quan seleccioneu BTRFS com a sistema de fitxers arrel, l'instal·lador crearà automàticament dos volums BTRFS anomenats "@" per a / (arrel) i "@home" per a /home.

Comencem la instal·lació...

La instal·lació finalitzarà amb un quadre de diàleg modal que indica un error en instal·lar el carregador d'arrencada. Malauradament, no podreu sortir d'aquest diàleg amb mitjans estàndard i continuar la instal·lació. Tanquem la sessió del sistema i tornem a iniciar sessió, acabant en un escriptori Ubuntu Live net. Obriu el terminal i de nou:

#sudo bash

Creeu un entorn chroot per continuar la instal·lació:

#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

Configurem la xarxa i el nom d'amfitrió a chroot:

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

Anem a l'entorn chroot:

#chroot /mnt/chroot

En primer lloc, lliurarem els paquets:

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

Comprovem i arreglem tots els paquets que s'han instal·lat malament a causa d'una instal·lació incompleta del sistema:

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

Si alguna cosa no funciona, potser haureu d'editar primer /etc/apt/sources.list

Ajustem els paràmetres del mòdul RAID 6 per habilitar TRIM/DISCARD:

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

Retoquem una mica les nostres matrius:

#cat >/etc/udev/rules.d/60-md.rules << EOF
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/stripe_cache_size", ATTR{md/stripe_cache_size}="32768"
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/sync_speed_min", ATTR{md/sync_speed_min}="48000"
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/sync_speed_max", ATTR{md/sync_speed_max}="300000"
EOF
#cat >/etc/udev/rules.d/62-hdparm.rules << EOF
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", RUN+="/sbin/hdparm -B 254 /dev/%k"
EOF
#cat >/etc/udev/rules.d/63-blockdev.rules << EOF
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", RUN+="/sbin/blockdev --setra 1024 /dev/%k"
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="md*", RUN+="/sbin/blockdev --setra 0 /dev/%k"
EOF

Què era això..?Hem creat un conjunt de regles udev que faran el següent:

  • Estableix la mida de la memòria cau de blocs per a RAID 2020 perquè sigui adequada per al 6. Sembla que el valor per defecte no ha canviat des de la creació de Linux i fa molt de temps que no és adequat.
  • Reserveu un mínim d'IO per a la durada de les comprovacions/sincronitzacions de la matriu. Això és per evitar que les vostres matrius quedin encallades en un estat de sincronització eterna sota càrrega.
  • Limiteu l'IO màxim durant les comprovacions/sincronització de les matrius. Això és necessari perquè la sincronització/comprovació dels RAID SSD no fregui les vostres unitats a un nivell nítid. Això és especialment cert per a NVMe. (Recordes del radiador? No estava fent broma.)
  • Prohibeu que els discs aturin la rotació de l'eix (HDD) mitjançant APM i configureu el temps d'espera de repòs dels controladors de disc a 7 hores. Podeu desactivar completament l'APM si les vostres unitats ho poden fer (-B 255). Amb el valor predeterminat, les unitats s'aturaran al cap de cinc segons. Aleshores, el sistema operatiu vol restablir la memòria cau del disc, els discs tornaran a girar i tot tornarà a començar. Els discos tenen un nombre màxim limitat de girs del cargol. Un cicle predeterminat tan senzill pot matar fàcilment els vostres discs en un parell d'anys. No tots els discs ho pateixen, però els nostres són “portàtils”, amb la configuració predeterminada adequada, que fan que el RAID sembli un mini-MAID.
  • Instal·leu readahead en discs (rotatius) 1 megabyte - dos blocs/fragment RAID 6 consecutius
  • Desactiveu el readahead a les matrius.

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

Per què això..?Cercarem la partició /boot per UUID. La denominació de la matriu podria canviar teòricament.

Cercarem les seccions restants per noms de LVM a la notació /dev/mapper/vg-lv, perquè identifiquen particions de manera força única.

No fem servir UUID per a LVM perquè L'UUID dels volums LVM i les seves instantànies poden ser els mateixos.Muntar /dev/mapper/root-root.. dues vegades?Sí. Exactament. Característica de BTRFS. Aquest sistema de fitxers es pot muntar diverses vegades amb diferents subvols.

A causa d'aquesta mateixa característica, recomano no crear mai instantànies LVM dels volums BTRFS actius. És possible que rebeu una sorpresa quan reinicieu.

Regenerem la configuració de mdadm:

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

Ajustem la configuració de LVM:

#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 això..?Hem habilitat l'expansió automàtica de les piscines primes LVM en arribar al 90% de l'espai ocupat en un 5% del volum.

Hem augmentat el nombre màxim de blocs de memòria cau per a la memòria cau LVM.

Hem impedit que LVM cerqui volums LVM (PV) a:

  • dispositius que contenen memòria cau LVM (cdata)
  • dispositius emmagatzemats a la memòria cau mitjançant la memòria cau LVM, passant per alt la memòria cau ( _corig). En aquest cas, el propi dispositiu de la memòria cau encara s'escanejarà a través de la memòria cau (només ).
  • dispositius que contenen metadades de memòria cau LVM (cmeta)
  • tots els dispositius a VG amb les imatges de nom. Aquí tindrem imatges de disc de màquines virtuals i no volem que LVM a l'amfitrió activi volums que pertanyen al sistema operatiu convidat.
  • tots els dispositius a VG amb el nom de còpia de seguretat. Aquí tindrem còpies de seguretat de les imatges de la màquina virtual.
  • tots els dispositius el nom dels quals acaba amb "gpv" (volum físic convidat)

Hem habilitat el suport DISCARD quan s'allibera espai lliure a LVM VG. Ves amb compte. Això farà que la supressió de LV del SSD requereixi molt de temps. Això s'aplica especialment a SSD RAID 6. No obstant això, segons el pla, utilitzarem un aprovisionament prim, de manera que això no ens impedirà gens.

Actualitzem la imatge initramfs:

#update-initramfs -u -k all

Instal·leu i configureu grub:

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

Quins discs hauríeu de triar?Tots els que són sd*. El sistema ha de poder arrencar des de qualsevol unitat SATA o SSD que funcioni.

Per què van afegir os-prober..?Per una independència excessiva i unes mans juganeres.

No funciona correctament si un dels RAID està en estat degradat. Intenta cercar el sistema operatiu a les particions que s'utilitzen a les màquines virtuals que s'executen amb aquest maquinari.

Si el necessiteu, podeu deixar-lo, però tingueu en compte tot l'anterior. Recomano buscar receptes per desfer-se de les mans entremaliades en línia.

Amb això hem completat la instal·lació inicial. És hora de reiniciar el sistema operatiu recentment instal·lat. No oblideu eliminar el Live CD/USB d'arrencada.

#exit
#reboot

Seleccioneu qualsevol dels SSD SATA com a dispositiu d'arrencada.

LVM en SSD SATA

En aquest punt, ja hem arrencat al nou sistema operatiu, hem configurat la xarxa, hem apt, hem obert l'emulador de terminal i hem llançat:

#sudo bash

Continuem.

"Inicialitzeu" la matriu des del SSD SATA:

#blkdiscard /dev/md2

Si no funciona, prova:

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

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

Per què un altre VG..?De fet, ja tenim un VG anomenat root. Per què no afegir-ho tot en un VG?

Si hi ha diversos PV en un VG, perquè el VG s'activi correctament, tots els PV han d'estar presents (en línia). L'excepció és LVM RAID, que deliberadament no fem servir.

Volem molt que si hi ha una fallada (pèrdua de dades de lectura) en qualsevol de les matrius RAID 6, el sistema operatiu arrenqui amb normalitat i ens doni l'oportunitat de resoldre el problema.

Per fer-ho, en el primer nivell d'abstracció aïllarem cada tipus de "mitjans" físics en un VG separat.

Científicament parlant, diferents matrius RAID pertanyen a diferents "dominis de fiabilitat". No hauríeu de crear un punt de fracàs comú addicional per a ells agrupant-los en un VG.

La presència de LVM a nivell de "maquinari" ens permetrà tallar arbitràriament peces de diferents matrius RAID combinant-les de diferents maneres. Per exemple - córrer a la vegada bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, una configuració complexa de ZFS amb memòria cau o qualsevol altra barreja infernal per provar de comparar-ho tot.

A nivell de "maquinari", no utilitzarem res més que bons volums LVM "gruixuts". L'excepció a aquesta regla pot ser la partició de còpia de seguretat.

Crec que en aquest moment, molts lectors ja havien començat a sospitar alguna cosa sobre la nina nidificant.

LVM al disc dur SATA

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

Nou VG de nou...?Volem realment que si falla la matriu de discs que utilitzarem per a la còpia de seguretat de dades, el nostre sistema operatiu continuï funcionant amb normalitat, mantenint l'accés a les dades que no són de còpia de seguretat com de costum. Per tant, per evitar problemes d'activació de VG, creem un VG independent.

Configuració de la memòria cau LVM

Creem un LV a NVMe RAID 1 per utilitzar-lo com a dispositiu de memòria cau.

#lvcreate -L 70871154688B --name cache root

Per què hi ha tan poc...?El fet és que els nostres SSD NVMe també tenen una memòria cau SLC. 4 gigabytes de "lliure" i 18 gigabytes de dinàmica a causa de l'espai lliure ocupat a l'MLC de 3 bits. Un cop esgotat aquesta memòria cau, els SSD NVMe no seran molt més ràpids que els nostres SSD SATA amb memòria cau. De fet, per aquest motiu, no té sentit fer que la partició de memòria cau LVM sigui molt més gran que el doble de la mida de la memòria cau SLC de la unitat NVMe. Per a les unitats NVMe utilitzades, l'autor considera raonable fer 32-64 gigabytes de memòria cau.

La mida de la partició determinada és necessària per organitzar 64 gigabytes de memòria cau, metadades de la memòria cau i còpia de seguretat de metadades.

A més, observo que després d'un tancament del sistema brut, LVM marcarà tota la memòria cau com bruta i es tornarà a sincronitzar. A més, això es repetirà cada vegada que s'utilitzi lvchange en aquest dispositiu fins que es reiniciï de nou. Per tant, recomano recrear immediatament la memòria cau mitjançant l'script adequat.

Creem un LV a SATA RAID 6 per utilitzar-lo com a dispositiu de memòria cau.

#lvcreate -L 3298543271936B --name cache data

Per què només tres terabytes..?De manera que, si cal, podeu utilitzar SATA SSD RAID 6 per a altres necessitats. La mida de l'espai a la memòria cau es pot augmentar dinàmicament, sobre la marxa, sense aturar el sistema. Per fer-ho, cal aturar i tornar a habilitar la memòria cau temporalment, però l'avantatge distintiu de la memòria cau LVM respecte, per exemple, bcache és que això es pot fer sobre la marxa.

Creem un nou VG per a la memòria cau.

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

Creem un LV al dispositiu de la memòria cau.

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

Aquí vam ocupar immediatament tot l'espai lliure a /dev/data/cache de manera que totes les altres particions necessàries es van crear immediatament a /dev/root/cache. Si heu creat alguna cosa al lloc equivocat, podeu moure'l amb pvmove.

Creem i activem la memòria cau:

#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

Per què tanta mida...?Mitjançant experiments pràctics, l'autor va poder esbrinar que el millor resultat s'aconsegueix si la mida del bloc de memòria cau LVM coincideix amb la mida del bloc prim LVM. A més, com més petita sigui la mida, millor serà la configuració en un enregistrament aleatori.

64k és la mida de bloc mínima permesa per a LVM thin.

Aneu amb compte amb l'escriptura...!Sí. Aquest tipus de memòria cau difereix la sincronització d'escriptura al dispositiu de la memòria cau. Això vol dir que si es perd la memòria cau, podeu perdre les dades del dispositiu guardat a la memòria cau. Més endavant, l'autor us dirà quines mesures, a més de NVMe RAID 1, es poden prendre per compensar aquest risc.

Aquest tipus de memòria cau es va escollir intencionadament per compensar el baix rendiment d'escriptura aleatòria de RAID 6.

Comprovem què tenim:

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

Només [cachedata_corig] s'ha de localitzar a /dev/data/cache. Si alguna cosa no funciona, feu servir pvmove.

Podeu desactivar la memòria cau si cal amb una ordre:

#lvconvert -y --uncache cache/cachedata

Això es fa en línia. LVM simplement sincronitzarà la memòria cau amb el disc, l'eliminarà i canviarà el nom de cachedata_corig a cachedata.

Configuració de LVM thin

Estimem aproximadament quant espai necessitem per a les metadades fines de LVM:

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

Arrodoneix fins a 4 gigabytes: 4294967296B

Multiplica per dos i afegeix 4194304B per a les metadades de LVM PV: 8594128896B
Creem una partició separada a NVMe RAID 1 per col·locar-hi metadades fines de LVM i la seva còpia de seguretat:

#lvcreate -L 8594128896B --name images root

Per a què..?Aquí pot sorgir la pregunta: per què col·locar les metadades fines de LVM per separat si encara es guardaran a la memòria cau a NVMe i funcionaran ràpidament.

Encara que la velocitat és important aquí, està lluny de ser el motiu principal. El cas és que la memòria cau és un punt de fallada. Alguna cosa li podria passar, i si les metadades prims de LVM s'emmagatzemen a la memòria cau, farà que tot es perdi completament. Sense metadades completes, serà gairebé impossible muntar volums prims.

En moure les metadades a un volum independent no emmagatzemat en memòria cau, però ràpid, garantim la seguretat de les metadades en cas de pèrdua o corrupció de la memòria cau. En aquest cas, tots els danys causats per la pèrdua de memòria cau es localitzaran dins de volums prims, la qual cosa simplificarà el procediment de recuperació en ordres de magnitud. Amb una alta probabilitat, aquests danys es restauraran mitjançant els registres FS.

A més, si prèviament es va fer una instantània d'un volum prim, i després d'això, la memòria cau es va sincronitzar completament almenys una vegada, aleshores, a causa del disseny intern de LVM thin, es garantirà la integritat de la instantània en cas de pèrdua de memòria cau. .

Creem un nou VG que serà responsable de l'aprovisionament lleuger:

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

Creem una piscina:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Per què -Z yA més del que realment està pensat aquest mode, per evitar que les dades d'una màquina virtual es filtrin a una altra màquina virtual quan es redistribueix l'espai, també s'utilitza la posada a zero per augmentar la velocitat d'escriptura aleatòria en blocs menors de 64 k. Qualsevol escriptura inferior a 64 k a una àrea prèviament no assignada del volum prim es convertirà en 64 K alineats amb les vores a la memòria cau. Això permetrà que l'operació es realitzi completament a través de la memòria cau, passant per alt el dispositiu de la memòria cau.

Movem els LV als PV corresponents:

#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

Comprovem:

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

Creem un volum prim per a les proves:

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

Instal·larem paquets per a proves i monitoratge:

#apt-get install sysstat fio

Així és com podeu observar el comportament de la nostra configuració d'emmagatzematge en temps real:

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

Així és com podem provar la nostra configuració:

#fio --loops=1 --size=64G --runtime=4 --filename=/dev/images/test --stonewall --ioengine=libaio --direct=1
--name=4kQD32read --bs=4k --iodepth=32 --rw=randread
--name=8kQD32read --bs=8k --iodepth=32 --rw=randread
--name=16kQD32read --bs=16k --iodepth=32 --rw=randread
--name=32KQD32read --bs=32k --iodepth=32 --rw=randread
--name=64KQD32read --bs=64k --iodepth=32 --rw=randread
--name=128KQD32read --bs=128k --iodepth=32 --rw=randread
--name=256KQD32read --bs=256k --iodepth=32 --rw=randread
--name=512KQD32read --bs=512k --iodepth=32 --rw=randread
--name=4Kread --bs=4k --rw=read
--name=8Kread --bs=8k --rw=read
--name=16Kread --bs=16k --rw=read
--name=32Kread --bs=32k --rw=read
--name=64Kread --bs=64k --rw=read
--name=128Kread --bs=128k --rw=read
--name=256Kread --bs=256k --rw=read
--name=512Kread --bs=512k --rw=read
--name=Seqread --bs=1m --rw=read
--name=Longread --bs=8m --rw=read
--name=Longwrite --bs=8m --rw=write
--name=Seqwrite --bs=1m --rw=write
--name=512Kwrite --bs=512k --rw=write
--name=256write --bs=256k --rw=write
--name=128write --bs=128k --rw=write
--name=64write --bs=64k --rw=write
--name=32write --bs=32k --rw=write
--name=16write --bs=16k --rw=write
--name=8write --bs=8k --rw=write
--name=4write --bs=4k --rw=write
--name=512KQD32write --bs=512k --iodepth=32 --rw=randwrite
--name=256KQD32write --bs=256k --iodepth=32 --rw=randwrite
--name=128KQD32write --bs=128k --iodepth=32 --rw=randwrite
--name=64KQD32write --bs=64k --iodepth=32 --rw=randwrite
--name=32KQD32write --bs=32k --iodepth=32 --rw=randwrite
--name=16KQD32write --bs=16k --iodepth=32 --rw=randwrite
--name=8KQD32write --bs=8k --iodepth=32 --rw=randwrite
--name=4kQD32write --bs=4k --iodepth=32 --rw=randwrite
| grep -E 'read|write|test' | grep -v ioengine

Amb compte! Recurs!Aquest codi executarà 36 proves diferents, cadascuna durant 4 segons. La meitat de les proves són per gravar. Podeu gravar molt a NVMe en 4 segons. Fins a 3 gigabytes per segon. Per tant, cada sèrie de proves d'escriptura pot consumir fins a 216 gigabytes de recursos SSD.

Llegir i escriure barrejats?Sí. Té sentit executar les proves de lectura i escriptura per separat. A més, té sentit assegurar-se que totes les memòria cau estan sincronitzades de manera que una escriptura feta prèviament no afecti la lectura.

Els resultats variaran molt durant el primer llançament i els posteriors a mesura que s'omplin la memòria cau i el volum prim, i també en funció de si el sistema ha aconseguit sincronitzar els cachés omplerts durant l'últim llançament.

Entre altres coses, recomano mesurar la velocitat en un volum prim ja ple del qual s'acaba de fer una instantània. L'autor va tenir l'oportunitat d'observar com les escriptures aleatòries s'acceleren bruscament immediatament després de crear la primera instantània, sobretot quan la memòria cau encara no està completament plena. Això passa a causa de la semàntica d'escriptura de còpia en escriptura, l'alineació de la memòria cau i els blocs de volum prim i el fet que una escriptura aleatòria a RAID 6 es converteix en una lectura aleatòria de RAID 6 seguida d'una escriptura a la memòria cau. A la nostra configuració, la lectura aleatòria de RAID 6 és fins a 6 vegades (el nombre de SSD SATA a la matriu) més ràpida que l'escriptura. Perquè els blocs per a CoW s'assignen seqüencialment a partir d'un grup prim, després l'enregistrament, en la seva major part, també es converteix en seqüencial.

Ambdues funcions es poden utilitzar al vostre avantatge.

A la memòria cau les instantànies "coherents".

Per reduir el risc de pèrdua de dades en cas de dany/pèrdua de la memòria cau, l'autor proposa introduir la pràctica de la rotació de les instantànies per garantir-ne la integritat en aquest cas.

En primer lloc, com que les metadades de volum prim resideixen en un dispositiu sense memòria cau, les metadades seran coherents i les possibles pèrdues s'aïllaran dins dels blocs de dades.

El següent cicle de rotació de les instantànies garanteix la integritat de les dades dins de les instantànies en cas de pèrdua de memòria cau:

  1. Per a cada volum prim amb el nom <nom>, creeu una instantània amb el nom <nom>.cached
  2. Establim el llindar de migració en un valor alt raonable: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Al bucle comprovem el nombre de blocs bruts a la memòria cau: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' fins que arribem a zero. Si falta el zero durant massa temps, es pot crear canviant temporalment la memòria cau al mode d'escriptura. Tanmateix, tenint en compte les característiques de velocitat de les nostres matrius SSD SATA i NVMe, així com el seu recurs TBW, podreu capturar ràpidament el moment sense canviar el mode de memòria cau, o el vostre maquinari consumirà completament tot el seu recurs en pocs dies. A causa de les limitacions de recursos, el sistema, en principi, no pot estar per sota del 100% de la càrrega d'escriptura tot el temps. Els nostres SSD NVMe amb una càrrega d'escriptura del 100% esgotaran completament el recurs dies 3-4. Els SSD SATA només duraran el doble. Per tant, assumirem que la major part de la càrrega es destina a la lectura i tenim ràfegues a curt termini d'activitat extremadament alta combinada amb una càrrega baixa de mitjana per escriure.
  4. Tan bon punt hem agafat (o hem fet) un zero, canviem el nom de <name>.cached a <name>.committed. S'elimina l'antic <nom>.committed.
  5. Opcionalment, si la memòria cau està plena al 100%, es pot recrear mitjançant un script, esborrant-la així. Amb una memòria cau mig buida, el sistema funciona molt més ràpid a l'hora d'escriure.
  6. Estableix el llindar de migració a zero: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Això impedirà temporalment que la memòria cau es sincronitzi amb el suport principal.
  7. Esperem fins que s'acumulin molts canvis a la memòria cau #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' o el temporitzador s'apagarà.
  8. Repetim de nou.

Per què dificultats amb el llindar de migració...?El cas és que, a la pràctica real, un enregistrament "atzar" en realitat no és completament aleatori. Si escrivim alguna cosa a un sector de 4 kilobytes de mida, hi ha una alta probabilitat que en els propers dos minuts es faci un registre al mateix sector o a un dels sectors veïns (+- 32 K).

En establir el llindar de migració a zero, posposem la sincronització d'escriptura al SSD SATA i afegim diversos canvis a un bloc de 64K a la memòria cau. Això estalvia significativament els recursos de SATA SSD.

On és el codi..?Malauradament, l'autor es considera insuficientment competent en el desenvolupament de scripts bash perquè és 100% autodidacta i practica el desenvolupament impulsat per "google", per tant creu que ningú no hauria d'utilitzar el terrible codi que surt de les seves mans. altra cosa.

Crec que els professionals d'aquest camp podran representar de manera independent tota la lògica descrita anteriorment, si cal, i, potser, fins i tot dissenyar-la com un servei de sistema, com l'autor va intentar fer.

Un esquema de rotació d'instantànies tan senzill ens permetrà no només tenir una instantània completament sincronitzada constantment al SSD SATA, sinó que també ens permetrà, utilitzant la utilitat thin_delta, esbrinar quins blocs s'han canviat després de la seva creació i, per tant, localitzar els danys en els principals volums, simplificant molt la recuperació.

TRIM/DESCARD a libvirt/KVM

Perquè l'emmagatzematge de dades s'utilitzarà per a KVM amb libvirt, llavors seria una bona idea ensenyar a les nostres VM no només a ocupar espai lliure, sinó també a alliberar allò que ja no es necessita.

Això es fa emulant el suport TRIM/DISCARD als discs virtuals. Per fer-ho, heu de canviar el tipus de controlador a virtio-scsi i editar el xml.

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

Aquests DESCARTATS dels sistemes operatius convidats són processats correctament per LVM i els blocs s'alliberen correctament tant a la memòria cau com al grup prim. En el nostre cas, això passa principalment de manera retardada, en eliminar la següent instantània.

Còpia de seguretat BTRFS

Utilitzeu scripts ja fets amb extrem precaució i sota el propi risc. L'autor va escriure aquest codi ell mateix i exclusivament per a ell mateix. Estic segur que molts usuaris de Linux amb experiència tenen eines similars i no cal copiar les d'una altra persona.

Creem un volum al dispositiu de còpia de seguretat:

#lvcreate -L 256G --name backup backup

Formatem-lo en BTRFS:

#mkfs.btrfs /dev/backup/backup

Creem punts de muntatge i muntem les subseccions arrel del sistema de fitxers:

#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

Creem directoris per a còpies de seguretat:

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

Creem un directori per als scripts de còpia de seguretat:

#mkdir /root/btrfs-backup

Copiem el guió:

Un munt de codi bash espantós. Feu servir sota el vostre propi risc. No escriviu cartes enfadades a l'autor...#cat >/root/btrfs-backup/btrfs-backup.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

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

LOCK_FILE="/dev/shm/$SCRIPT_NAME.lock"
DATE_PREFIX='%Y-%m-%d'
DATE_FORMAT=$DATE_PREFIX'-%H-%M-%S'
DATE_REGEX='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
BASE_SUFFIX=".@base"
PEND_SUFFIX=".@pend"
SNAP_SUFFIX=".@snap"
MOUNTS="/backup/btrfs/"
BACKUPS="/backup/btrfs/back/remote/"

function terminate ()
{
echo "$1" >&2
exit 1
}

function wait_lock()
{
flock 98
}

function wait_lock_or_terminate()
{
echo "Wating for lock..."
wait_lock || terminate "Failed to get lock. Exiting..."
echo "Got lock..."
}

function suffix()
{
FORMATTED_DATE=$(date +"$DATE_FORMAT")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}

function filter()
{
FORMATTED_DATE=$(date --date="$1" +"$DATE_PREFIX")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}

function backup()
{
SOURCE_PATH="$MOUNTS$1"
TARGET_PATH="$BACKUPS$1"
SOURCE_BASE_PATH="$MOUNTS$1$BASE_SUFFIX"
TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
TARGET_BASE_DIR="$(dirname $TARGET_BASE_PATH)"
SOURCE_PEND_PATH="$MOUNTS$1$PEND_SUFFIX"
TARGET_PEND_PATH="$BACKUPS$1$PEND_SUFFIX"
if [ -d "$SOURCE_BASE_PATH" ] then
echo "$SOURCE_BASE_PATH found"
else
echo "$SOURCE_BASE_PATH File not found creating snapshot of $SOURCE_PATH to $SOURCE_BASE_PATH"
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_BASE_PATH
sync
if [ -d "$TARGET_BASE_PATH" ] then
echo "$TARGET_BASE_PATH found out of sync with source... removing..."
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
fi
fi
if [ -d "$TARGET_BASE_PATH" ] then
echo "$TARGET_BASE_PATH found"
else
echo "$TARGET_BASE_PATH not found. Synching to $TARGET_BASE_DIR"
btrfs send $SOURCE_BASE_PATH | btrfs receive $TARGET_BASE_DIR
sync
fi
if [ -d "$SOURCE_PEND_PATH" ] then
echo "$SOURCE_PEND_PATH found removing..."
btrfs subvolume delete -c $SOURCE_PEND_PATH
sync
fi
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_PEND_PATH
sync
if [ -d "$TARGET_PEND_PATH" ] then
echo "$TARGET_PEND_PATH found removing..."
btrfs subvolume delete -c $TARGET_PEND_PATH
sync
fi
echo "Sending $SOURCE_PEND_PATH to $TARGET_PEND_PATH"
btrfs send -p $SOURCE_BASE_PATH $SOURCE_PEND_PATH | btrfs receive $TARGET_BASE_DIR
sync
TARGET_DATE_SUFFIX=$(suffix)
btrfs subvolume snapshot -r $TARGET_PEND_PATH "$TARGET_PATH$TARGET_DATE_SUFFIX"
sync
btrfs subvolume delete -c $SOURCE_BASE_PATH
sync
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
mv $SOURCE_PEND_PATH $SOURCE_BASE_PATH
mv $TARGET_PEND_PATH $TARGET_BASE_PATH
sync
}

function list()
{
LIST_TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
LIST_TARGET_BASE_DIR="$(dirname $LIST_TARGET_BASE_PATH)"
LIST_TARGET_BASE_NAME="$(basename -s .$BASE_SUFFIX $LIST_TARGET_BASE_PATH)"
find "$LIST_TARGET_BASE_DIR" -maxdepth 1 -mindepth 1 -type d -printf "%fn" | grep "${LIST_TARGET_BASE_NAME/$BASE_SUFFIX/$SNAP_SUFFIX}.$DATE_REGEX"
}

function remove()
{
REMOVE_TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
REMOVE_TARGET_BASE_DIR="$(dirname $REMOVE_TARGET_BASE_PATH)"
btrfs subvolume delete -c $REMOVE_TARGET_BASE_DIR/$2
sync
}

function removeall()
{
DATE_OFFSET="$2"
FILTER="$(filter "$DATE_OFFSET")"
while read -r SNAPSHOT ; do
remove "$1" "$SNAPSHOT"
done < <(list "$1" | grep "$FILTER")

}

(
COMMAND="$1"
shift

case "$COMMAND" in
"--help")
echo "Help"
;;
"suffix")
suffix
;;
"filter")
filter "$1"
;;
"backup")
wait_lock_or_terminate
backup "$1"
;;
"list")
list "$1"
;;
"remove")
wait_lock_or_terminate
remove "$1" "$2"
;;
"removeall")
wait_lock_or_terminate
removeall "$1" "$2"
;;
*)
echo "None.."
;;
esac
) 98>$LOCK_FILE

EOF

Què fa fins i tot..?Conté un conjunt d'ordres senzilles per crear instantànies BTRFS i copiar-les a un altre FS mitjançant l'enviament/recepció de BTRFS.

El primer llançament pot ser relativament llarg, perquè... Al principi, es copiaran totes les dades. Els llançaments posteriors seran molt ràpids, perquè... Només es copiaran els canvis.

Un altre script que posarem a cron:

Una mica més de codi 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è fa..?Crea i sincronitza instantànies incrementals dels volums BTRFS enumerats a l'FS de còpia de seguretat. Després d'això, elimina totes les imatges creades fa 60 dies. Després del llançament, apareixeran instantànies amb data dels volums llistats als subdirectoris /backup/btrfs/back/remote/.

Donem els drets d'execució del codi:

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

Comprovem-ho i posem-lo al cron:

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

Còpia de seguretat fina de LVM

Creem un grup prim al dispositiu de còpia de seguretat:

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

Instal·lem ddrescue, perquè... els scripts utilitzaran aquesta eina:

#apt-get install gddrescue

Creem un directori per als scripts:

#mkdir /root/lvm-thin-backup

Copiem els scripts:

Molta xoc a dins...#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è fa...?Conté un conjunt d'ordres per manipular instantànies fines i sincronitzar la diferència entre dues instantànies primes rebudes mitjançant thin_delta a un altre dispositiu de bloc mitjançant ddrescue i blkdiscard.

Un altre script que posarem a cron:

Una mica més de xoc#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è fa...?Utilitza l'script anterior per crear i sincronitzar còpies de seguretat dels volums prims de la llista. L'script deixarà instantànies inactives dels volums llistats, que són necessaris per fer un seguiment dels canvis des de l'última sincronització.

Aquest script s'ha d'editar, especificant la llista de volums prims dels quals s'han de fer còpies de seguretat. Els noms donats només tenen finalitats il·lustratives. Si ho desitgeu, podeu escriure un script que sincronitzi tots els volums.

Donem els drets:

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

Comprovem-ho i posem-lo al cron:

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

El primer llançament serà llarg, perquè... els volums prims es sincronitzaran completament copiant tot l'espai utilitzat. Gràcies a les metadades primes de LVM, sabem quins blocs estan realment en ús, de manera que només es copiaran els blocs de volum prim utilitzats.

Les execucions posteriors copiaran les dades de manera incremental gràcies al seguiment de canvis mitjançant metadades fines de LVM.

A veure què ha passat:

#time /root/btrfs-backup/cron-daily.sh
real 0m2,967s
user 0m0,225s
sys 0m0,353s

#time /root/lvm-thin-backup/cron-daily.sh
real 1m2,710s
user 0m12,721s
sys 0m6,671s

#ls -al /backup/btrfs/back/remote/*
/backup/btrfs/back/remote/boot:
total 0
drwxr-xr-x 1 root root 1260 мар 26 09:11 .
drwxr-xr-x 1 root root 16 мар 6 09:30 ..
drwxr-xr-x 1 root root 322 мар 26 02:00 .@base
drwxr-xr-x 1 root root 516 мар 6 09:39 [email protected]
drwxr-xr-x 1 root root 516 мар 6 09:39 [email protected]
...
/backup/btrfs/back/remote/root:
total 0
drwxr-xr-x 1 root root 2820 мар 26 09:11 .
drwxr-xr-x 1 root root 16 мар 6 09:30 ..
drwxr-xr-x 1 root root 240 мар 26 09:11 @.@base
drwxr-xr-x 1 root root 22 мар 26 09:11 @home.@base
drwxr-xr-x 1 root root 22 мар 6 09:39 @[email protected]
drwxr-xr-x 1 root root 22 мар 6 09:39 @[email protected]
...
drwxr-xr-x 1 root root 240 мар 6 09:39 @[email protected]
drwxr-xr-x 1 root root 240 мар 6 09:39 @[email protected]
...

#lvs -olv_name,lv_size images && lvs -olv_name,lv_size backup
LV LSize
linux-dev 128,00g
linux-dev.base 128,00g
thin-pool 1,38t
win8 128,00g
win8-data 2,00t
win8-data.base 2,00t
win8.base 128,00g
LV LSize
backup 256,00g
images-linux-dev.base 128,00g
images-linux-dev.snap.2020-03-08-10-09-11 128,00g
images-linux-dev.snap.2020-03-08-10-09-25 128,00g
...
images-win8-data.base 2,00t
images-win8-data.snap.2020-03-16-14-11-55 2,00t
images-win8-data.snap.2020-03-16-14-19-50 2,00t
...
images-win8.base 128,00g
images-win8.snap.2020-03-17-04-51-46 128,00g
images-win8.snap.2020-03-18-03-02-49 128,00g
...
thin-pool <2,09t

Què té a veure això amb les nines nidificants?

Molt probablement, atès que els volums lògics LVM LV poden ser volums físics LVM PV per a altres VG. LVM pot ser recursiu, com les nines de nidificació. Això dóna a LVM una flexibilitat extrema.

PS

En el següent article, intentarem utilitzar diversos sistemes d'emmagatzematge mòbil/KVM similars com a base per crear un clúster d'emmagatzematge/vm geodistribuït amb redundància a diversos continents mitjançant escriptoris domèstics, Internet domèstic i xarxes P2P.

Font: www.habr.com

Afegeix comentari