Vad har LVM och en matryoshka gemensamt?

God dag.
Jag vill dela med mig av praktisk erfarenhet av att bygga ett lagringssystem för KVM med hjÀlp av md RAID + LVM.

Programmet kommer att innehÄlla:

  • Montering av md RAID 1 med NVMe SSD.
  • Montering av md RAID 6 med SATA SSD och vanliga diskar.
  • Egenskaper för TRIM/DISCARD i SSD RAID 1/6.
  • Skapande av en startbar md RAID 1/6-array med en uppsĂ€ttning gemensamma diskar.
  • Installation av systemet pĂ„ NVMe RAID 1 i avsaknad av stöd för NVMe i BIOS.
  • AnvĂ€ndning av LVM-cache och LVM-thin.
  • AnvĂ€ndning av BTRFS-snapshots och send/receive för sĂ€kerhetskopiering.
  • AnvĂ€ndning av LVM-thin snapshots och thin_delta för BTRFS-liknande sĂ€kerhetskopiering.

Om det lÄter intressant, var vÀnlig scrolla ner.

Ansvarsfriskrivning

Författaren tar inget ansvar för konsekvenserna av att anvÀnda eller inte anvÀnda material/ exempel/ kod/ rÄd/ data frÄn denna artikel. Genom att lÀsa eller pÄ nÄgot sÀtt anvÀnda detta material tar du ansvar för alla konsekvenser av dessa ÄtgÀrder. Möjliga konsekvenser inkluderar:

  • BrĂ€nda till krispighet NVMe SSD.
  • FullstĂ€ndigt förbrukad skrivresurs och fel pĂ„ SSD-enheter.
  • Total förlust av all data pĂ„ alla lagringsenheter, inklusive sĂ€kerhetskopior.
  • Defekt datorutrustning.
  • Tappad tid, nerver och pengar.
  • Alla andra konsekvenser som inte Ă€r listade ovan.

HÄrdvara

TillgÀngligt var:

Ett moderkort frÄn omkring 2013 baserat pÄ Z87-chipset med Intel Core i7 / Haswell.

  • Processor med 4 kĂ€rnor, 8 trĂ„dar
  • 32 Gigabyte DDR3 RAM
  • 1 x 16 eller 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3-anslutningar

SAS-adapter LSI SAS9211-8I omprogrammerad till IT / HBA-lÀge. Firmware med RAID-stöd har avsiktligt bytts ut mot HBA-firmware för att:

  1. Man enkelt ska kunna slÀnga denna adapter och byta till vilken annan som helst som finns tillgÀnglig.
  2. TRIM/Discard fungerade normalt pÄ diskarna, dÄ dessa kommandon inte alls stöds i RAID-firmware, medan HBA i stort sett inne har nÄgot emot vilka kommandon som skickas via bussen.

HĂ„rddiskar, — 8 stycken HGST Travelstar 7K1000 med 1 TB kapacitet i 2.5" formfaktor, avsedd för bĂ€rbara datorer. Dessa diskar var tidigare i en RAID 6-array. I det nya systemet kommer de ocksĂ„ att anvĂ€ndas. För lagring av lokala sĂ€kerhetskopior.

Dessutom lades till:

6 stycken SATA SSD-modeller Samsung 860 QVO 2TB. FrÄn dessa SSD kunde stor kapacitet, SLC-cache och önskvÀrdhet av tillförlitlighet, samt ett lÄgt pris förvÀntas. Det var obligatoriskt med stöd för discard/zero som verifieras med en rad i dmesg:

kernel: ata1.00: Aktiverar discard_zeroes_data

2 stycken NVMe SSD av modell Samsung SSD 970 EVO 500GB.

För dessa SSD:er Àr hastigheten för slumpmÀssig lÀsning/ skrivning och hÄllbarhet viktig för dina behov. En kylare till dem. Absolut nödvÀndigt. Annars brÀnner du dem till en krispig konsistens vid första RAID-synkroniseringen.

StarTech PEX8M2E2-adapter för 2 x NVMe SSD installerad i PCIe 3.0 8x slot. Detta Àr, Äterigen, bara en HBA, men för NVMe. Den skiljer sig frÄn billigare adaptrar genom att den inte krÀver stöd för PCIe bifurkation frÄn moderkortet tack vare den inbyggda PCIe-switch. Kommer att fungera Àven i de Àldsta systemen som har PCIe, Àven om det Àr en x1 PCIe 1.0 slot. Naturligtvis, med motsvarande hastighet. Det finns inga RAID-funktioner dÀr. Ingen inbyggd BIOS ombord. SÄ, ditt system kommer inte magiskt att lÀra sig att starta frÄn NVMe, Àn mindre att göra NVMe RAID tack vare denna enhet.

Denna komponent valdes uteslutande pÄ grund av att det bara fanns en ledig 8x PCIe 3.0 i systemet, och om det fanns 2 lediga slots, kan den lÀtt bytas ut mot tvÄ billiga PEX4M2E1 eller motsvarande, som kan köpas var som helst för priser frÄn 600 rubel.

AvstÄendet frÄn alla möjliga hÄrdvaru- eller inbyggda chipset/BIO RAID:er gjordes medvetet, för att möjliggöra en fullstÀndig ersÀttning av hela systemet, förutom sjÀlva SSD/HDD, samtidigt som alla data bevaras. Idéellt för att Àven kunna spara det installerade operativsystemet vid flytt till helt ny/annat hÄrdvara. Huvudsakligen att det finns SATA- och PCIe-portar. Det Àr som en live CD eller bootbar USB, bara mycket snabbare och lite mer skrymmande.

HumorFör som ni vet, ibland mÄste man snabbt ta hela arrayen med sig. Och man vill inte förlora data. För detta ÀndamÄl Àr alla nÀmnda lagringsmedia smart placerade i hÄllare i standard 5.25 chassi.

SjÀlvklart för experiment med olika metoder för SSD-cache i Linux.

HÄrdvaru-RAID Àr trÄkigt. SÀtter pÄ det. Det fungerar eller inte. Men med mdadm finns det alltid alternativ.

Programvara

Tidigare var Debian 8 Jessie installerat pÄ hÄrdvaran som Àr nÀra EOL. En RAID 6 byggdes med de ovan nÀmnda HDD:erna i par med LVM. PÄ den kördes virtuella maskiner i kvm/libvirt.

Eftersom författaren har rÀtt erfarenhet av att skapa bÀrbara startbara SATA/NVMe flashenheter och för att inte förstöra den vanliga apt-mallen, valdes Ubuntu 18.04 som mÄlsystem, som redan har stabiliserat sig tillrÀckligt men fortfarande har tre Ärs support kvar.

I det nÀmnda systemet finns alla nödvÀndiga drivrutiner för hÄrdvaran direkt frÄn början. Ingen tredje parts programvara eller drivrutiner kommer att behövas.

Förberedelse för installation

För att installera systemet behöver vi Ubuntu Desktop Image. Den serverversionen har en ganska komplicerad installerare som visar en överdriven och icke-avstÀngd sjÀlvstÀndighet genom att alltid installera UEFI-systempartitionen pÄ en av diskarna, vilket förstör hela estetiken. DÀrför installeras det bara i UEFI-lÀge. Det finns inga andra alternativ.

Det hÀr Àr oacceptabelt för oss.

Varför?TyvÀrr Àr UEFI-booting extremt dÄligt kompatibel med mjukvarubaserad RAID, eftersom ingen erbjuder reservutrymme för UEFI ESP-partitionen. Det finns recept pÄ nÀtet som föreslÄr att placera ESP-partitionen pÄ en flashenhet i USB-porten, men detta Àr en felpunkt. Det finns ocksÄ recept som anvÀnder mjukvarubaserad mdadm RAID 1 med metadata version 0.9 som inte hindrar UEFI BIOS frÄn att se den hÀr partitionen, men detta hÄller bara tills det lyckosamma ögonblicket dÄ BIOS eller ett annat operativsystem pÄ hÄrdvaran skriver nÄgot till ESP utan att synkronisera med de andra speglarna.

Dessutom beror UEFI-booting pÄ NVRAM, som inte flyttas tillsammans med diskarna till det nya systemet, eftersom den Àr en del av moderkortet.

SÄ vi kommer inte att uppfinna den nya cykeln. Vi har redan en fÀrdig, beprövad gammaldags cykel som nu kallas Legacy/BIOS boot, som har det stolta namnet CSM pÄ UEFI-kompatibla system. Vi tar bara ner den frÄn hyllan, smörjer den, pumpar dÀcken och torkar av den med en fuktig trasa.

Desktop-versionen av Ubuntu klarar inte att installeras korrekt med Legacy-bootloadern, men hÀr finns Ätminstone alternativ.

SÄ vi samlar ihop hÄrdvaran och laddar systemet frÄn en startbar flashenhet med Ubuntu Live. Vi kommer att behöva ladda ner paket, sÄ vi stÀller in nÀtverket, vilket som helst fungerar. Om det inte fungerar kan de nödvÀndiga paketen laddas ner i förvÀg till flashenheten.

Vi gÄr in i Desktop-miljön, öppnar terminalemulatorn, och sÄ kör vi:

#sudo bash

Hur
?Raden ovan Ă€r en kanonisk utlösare för debatter om sudo. Med bbĂ€sta resultatet (subjektiv Ă„sikt).Större möjligheter kommer med ettbĂ€sta resultatet (subjektiv Ă„sikt).större ansvar. FrĂ„gan Ă€r om du kan ta det pĂ„ dig. MĂ„nga anser att anvĂ€ndningen av sudo pĂ„ det sĂ€ttet Ă€r, Ă„tminstone oansvarigt. Men:

Spela video

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

Varför inte ZFS
?NĂ€r vi installerar programvara pĂ„ vĂ„r dator, i grund och botten lĂ„nar vi ut vĂ„r hĂ„rdvara till utvecklarna av denna programvara.
NÀr vi litar pÄ denna programvara med att skydda vÄra data, tar vi i skuld en kostnad motsvarande ÄterstÀllningen av dessa data, som vi en dag mÄste betala.

Ur den synvinkeln Àr ZFS en Ferrari, medan mdadm+lvm mer liknar en cykel.

Subjektivt föredrar författaren att lÄna en okÀnd person en kreditcykel istÀllet för en Ferrari. Priset Àr lÄgt. Inga rÀttigheter krÀvs. Enklare vÀgtrafikregler. Parkering Àr gratis. Framkomligheten Àr bÀttre. Man kan alltid fÀsta ben pÄ cykeln, och man kan Àven reparera cykeln sjÀlv.

Varför dĂ„ BTRFS
?För att ladda operativsystemet behöver vi ett filsystem som stöds av Legacy/BIOS GRUB frĂ„n början, och som dessutom stödjer snapshots i realtid. Vi kommer att anvĂ€nda det för ⁄boot-partitionen. Dessutom föredrar författaren att anvĂ€nda detta filsystem för ⁄ (roten) utan att glömma att det för annan programvara kan skapas separata partitioner pĂ„ LVM och monteras i de nödvĂ€ndiga katalogerna.

Varken bilder virtuella maskinereller databaser kommer vi att lagra pÄ detta filsystem.
Detta filsystem kommer endast att anvÀndas för att skapa ögonblicksbilder av systemet utan att stÀnga av det, följt av att dessa ögonblicksbilder överförs till en sÀkerhetsdisk med hjÀlp av send/receive.

Dessutom föredrar författaren oftast att hÄlla sÄ lite programvara som möjligt direkt pÄ hÄrdvaran och köra all annan mjukvara i virtuella maskiner med hjÀlp av hÄllare för GPU och PCI-USB-vÀrdkontrollrar i KVM via IOMMU.

PÄ hÄrdvaran finns endast lagring av data, virtualisering och sÀkerhetskopiering kvar.

Om du litar mer pÄ ZFS, Àr de i princip utbytbara för det angivna anvÀndningsomrÄdet.

Trots detta ignorerar författaren medvetet de inbyggda funktionerna för spegling ⁄ RAID och redundans som finns i ZFS, BTRFS och LVM.

Som ett ytterligare argument har BTRFS egenskapen att omvandla slumpmÀssiga skrivningar till sekventiella, vilket har en mycket positiv inverkan pÄ hastigheten för synkronisering av snapshots / sÀkerhetskopior pÄ HDD.

Vi skannar om alla enheter:

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

Vi ser oss omkring:

#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 Modell Namespace AnvÀndning 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

Partitionering av "diskar"

NVMe SSD

Men vi kommer inte att partitionera dem. VĂ„r BIOS ser Ă€ndĂ„ inte dessa enheter. SĂ„ de gĂ„r helt in i mjukvaru-RAID. Vi kommer inte ens att skapa nĂ„gra partitioner dĂ€r. Om man vill göra det "enligt kanon" eller "principiellt" – skapa en stor partition, precis som för HDD.

SATA HDD

HÀr behöver vi inte uppfinna nÄgot nytt. Vi kommer att skapa en partition för allt. Vi skapar en partition eftersom dessa diskar syns i BIOS och det kan till och med försöka starta frÄn dem. Vi kommer Àven senare att installera GRUB pÄ dessa diskar sÄ att systemet ovÀntat kan starta.

#cat >hdd.part << EOF
etikett: dos
etikett-id: 0x00000000
enhet: /dev/sdg
enhet: sektorer

/dev/sdg1 : start= 2048, size= 1953523120, type=fd, bootable
EOF
#sfdisk /dev/sdg < hdd.part
#sfdisk /dev/sdh < hdd.part
#sfdisk /dev/sdi < hdd.part
#sfdisk /dev/sdj < hdd.part
#sfdisk /dev/sdk < hdd.part
#sfdisk /dev/sdl < hdd.part
#sfdisk /dev/sdm < hdd.part
#sfdisk /dev/sdn < hdd.part

SATA SSD

HÀr Àr det mest intressant.

För det första har vÄra enheter en storlek pÄ 2 TB. Detta ligger inom grÀnserna för MBR, vilket vi kommer att dra nytta av. Om nödvÀndigt kan det bytas ut mot GPT. GPT-diskar har ett kompatibilitetslager som gör att MBR-kompatibla system kan se de första 4 partitionerna om de ligger inom de första 2 terabyterna. Det viktigaste Àr att den startande partitionen och partitionen bios_grub pÄ dessa diskar ligger i början. Detta gör det till och med möjligt att göra Legacy/BIOS-start frÄn GPT-diskar.

Men det Àr inte vÄrt fall.

HÀr kommer vi att skapa tvÄ partitioner. Den första kommer att vara 1 GB stor och anvÀndas för RAID 1 /boot.

Den andra kommer att anvÀndas för RAID 6 och ta upp allt kvarvarande ledigt utrymme förutom ett litet icke-partionerat omrÄde i slutet av lagringsenheten.

Vad Àr det för icke-partionerat omrÄde?Enligt kÀllor pÄ nÀtet har vÄra SATA SSD:er en dynamiskt utökad SLC-cache pÄ mellan 6 och 78 gigabyte. 6 gigabyte fÄr vi "kostnadsfritt" pÄ grund av skillnaden mellan "gigabyte" och "gibibyte" i lagringsenhetens datablad. De andra 72 gigabyten tilldelas pÄ grund av outnyttjat utrymme.

HÀr bör det noteras att cachen Àr SLC och utrymmet anvÀnds i 4 bit MLC-lÀge. Det som effektivt innebÀr för oss Àr att för varje 4 gigabyte ledigt utrymme fÄr vi bara 1 gigabyte SLC-cache.

Vi multiplicerar 72 gigabyte med 4 och fÄr 288 gigabyte. Detta Àr det lediga utrymme som vi inte kommer att partitionera för att lÄta enheterna fullt utnyttja SLC-cachen.

PÄ sÄ sÀtt fÄr vi effektivt upp till 312 gigabyte SLC-cache totalt frÄn sex lagringsenheter. Av alla lagringsenheter kommer 2 att anvÀndas i RAID för redundans.

Denna mĂ€ngd cache kommer att göra att vi sĂ€llan stöter pĂ„ situationer dĂ€r skrivningar inte gĂ„r via cachen. Detta kompenserar extremt bra för den mest nedslĂ„ende nackdelen med QLC-minne – den extremt lĂ„ga skrivhastigheten nĂ€r data skrivs utan att passera cachen. Om dina belastningar inte överensstĂ€mmer med detta rekommenderar jag att du noga övervĂ€ger hur lĂ€nge dina SSD:er kommer att klara en sĂ„dan belastning med hĂ€nsyn till TBW i specifikationen.

#cat >ssd.part << EOF
etikett: dos
etikett-id: 0x00000000
enhet: /dev/sda
enhet: sektorer

/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

Skapande av enheter

Först behöver vi döpa om maskinen. Detta Àr nödvÀndigt eftersom vÀrdnamnet Àr en del av namnet pÄ enheten nÄgonstans i mdadm och pÄverkar nÄgot. Enheter kan sjÀlvklart döpas om senare, men det Àr onödiga ÄtgÀrder.

#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

Varför –assume-clean
?För att inte initiera enheterna. För bĂ„da RAID-nivĂ„erna 1 och 6 Ă€r detta acceptabelt. Allt kan fungera utan initiering om det Ă€r en ny enhet. Dessutom Ă€r initiering av SSD-enheter vid skapandet en slöseri med TBW-resurser. Vi anvĂ€nder TRIM/DISCARD dĂ€r det Ă€r möjligt pĂ„ de sammansatta SSD-enheterna för att "initiera" dem.

För SSD RAID 1 stöds DISCARD ur lÄdan.

För SSD RAID 6 mÄste DISCARD aktiveras i kÀrnmodulens instÀllningar.

Detta bör göras endast om alla SSD-enheter som anvÀnds i nivÄer 4/5/6 i detta system har fungerande stöd för discard_zeroes_data. Ibland dyker det upp konstiga enheter som rapporterar till kÀrnan att de stödjer denna funktion, men i verkligheten gör de det inte, eller funktionen fungerar inte alltid. För nÀrvarande finns det praktiskt taget stöd överallt, men Àldre enheter och felaktiga firmwareversioner förekommer. Av denna anledning Àr DISCARD-stödet som standard inaktiverat för RAID 6.

Observera, nÀsta kommando kommer att förstöra all data pÄ NVMe-enheterna genom att "initiera" enheten med "nollor".

#blkdiscard /dev/md0

Om nÄgot gÄr fel, försök ange steg.

#blkdiscard --step 65536 /dev/md0

SATA SSD

#mdadm --create --verbose --assume-clean /dev/md1 --level=1 --raid-devices=6 /dev/sd[a-f]1
#blkdiscard /dev/md1
#mdadm --create --verbose --assume-clean /dev/md2 --chunk-size=512 --level=6 --raid-devices=6 /dev/sd[a-f]2

Varför sĂ„ stor
?Ökningen av chunk-storleken pĂ„verkar hastigheten för slumpmĂ€ssig lĂ€sning av block upp till och med chunk-storleken. Detta sker eftersom en operation av motsvarande storlek eller mindre kan utföras helt pĂ„ en enhet. DĂ€rför summeras IOPS frĂ„n alla enheter. Enligt statistik överskrider 99% av IO inte 512K.

I RAID 6 Àr IOPS för skrivning alltid mindre eller lika med IOPS för en enda enhet. Vid slumpmÀssig lÀsning kan IOPS vara högre Àn för en enda enhet flera gÄnger, och hÀr Àr blockstorleken avgörande.
Författaren ser ingen mening i att försöka optimera en parameter som Àr dÄlig för RAID 6 enligt design, och istÀllet optimerar vad RAID 6 gör bra.
Den dÄliga slumpmÀssiga skrivningen av RAID 6 kommer vi att kompensera med cache pÄ NVMe och tricks med thin-provisioning.

Vi har Ànnu inte aktiverat DISCARD för RAID 6. SÄ vi kommer inte att "initiera" denna array Ànnu. Vi gör det senare, efter operativsystemets installation.

SATA HDD

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

LVM pÄ NVMe RAID

För hastighet vill vi placera rotfilsystemet pÄ NVMe RAID 1 som /dev/md0.
Denna snabba array kommer vi dock fortfarande behöva för andra behov, sÄsom swap, metdata och LVM-cache samt metdata för LVM-thin, dÀrför kommer vi att skapa en LVM VG pÄ denna array.

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

Vi skapar en partition för rotfilsystemet.

#lvcreate -L 128G --name root root

Vi skapar en partition för swap som Àr i storlek med RAM-minnet.

#lvcreate -L 32G --name swap root

Installation av OS

Sammantaget har vi allt som behövs för att installera systemet.

Vi startar installationsguiden frÄn Ubuntu Live-miljön. Vanlig installation. Endast under valet av diskar för installation mÄste vi ange följande:

  • /dev/md1, — Ń‚ĐŸŃ‡Đșа ĐŒĐŸĐœŃ‚ĐžŃ€ĐŸĐČĐ°ĐœĐžŃ /boot, ЀХ — BTRFS
  • /dev/root/root (a.k.a /dev/mapper/root-root), — Ń‚ĐŸŃ‡Đșа ĐŒĐŸĐœŃ‚ĐžŃ€ĐŸĐČĐ°ĐœĐžŃ / (ĐșĐŸŃ€Đ”ĐœŃŒ), ЀХ — BTRFS
  • /dev/root/swap (a.k.a /dev/mapper/root-swap), — ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČать ĐșаĐș разЎДл ĐżĐŸĐŽĐșачĐșĐž
  • Installera bootloader pĂ„ /dev/sda

NÀr BTRFS vÀljs som rotfilsystem kommer installationsprogrammet automatiskt att skapa tvÄ BTRFS-volymer med namnen "@" för / (rot) och "@home" för /home.

Vi startar installationen


Installationen kommer att avslutas med en modal dialog som meddelar om ett bootloader installationsfel. TyvĂ€rr, blir det inte möjligt att stĂ€nga dialogen pĂ„ vanligt sĂ€tt och fortsĂ€tta installationen. Logga ut frĂ„n systemet och logga in igen, för att hamna pĂ„ skrivbordet för Ubuntu Live. Öppna terminalen, och Ă„terigen:

#sudo bash

Vi skapar en chroot-miljö för att fortsÀtta installationen:

#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

LÄt oss konfigurera nÀtverket och vÀrdnamnet i chroot:

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

Vi gÄr in i chroot-miljön:

#chroot /mnt/chroot

Först installerar vi paketen:

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

Vi kontrollerar och ÄtgÀrdar alla paket som har installerats felaktigt pÄ grund av en ofullstÀndig systeminstallation:

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

Om nÄgot gick snett kan det hÀnda att du först behöver redigera /etc/apt/sources.list

Vi justerar instÀllningarna för RAID 6-modulen för att aktivera TRIM/DISCARD:

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

Vi justerar lite av vÄra arrayer:

#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

Vad var det..?Vi har skapat en uppsÀttning udev-regler som kommer att göra följande:

  • StĂ€ll in en adekvat cachestorlek för RAID 6 för Ă„r 2020. StandardvĂ€rdet verkar inte ha Ă€ndrats sedan Linux skapades och Ă€r sedan lĂ€nge otillrĂ€ckligt.
  • Reservera minst IO under kontroller/synkronisering av arrayerna. Detta Ă€r nödvĂ€ndigt för att förhindra att dina arrayer fastnar i ett tillstĂ„nd av evig synkronisering under belastning.
  • BegrĂ€nsa maximalt IO under kontroller/synkronisering av arrayerna. Detta Ă€r viktigt för att synkronisering/kontroll av SSD RAID inte ska överhetta dina lagringsenheter. SĂ€rskilt viktigt för NVMe. (Kommer du ihĂ„g kylflĂ€nsen? Jag skĂ€mtade inte.)
  • Förhindra att diskarna stoppar spinnandet av spindeln (HDD) via APM och stĂ€ll in en sömntimeout för diskens kontroller pĂ„ 7 timmar. Du kan helt stĂ€nga av APM om dina diskar stödjer det (-B 255). Med standardvĂ€rdet kommer diskarna att stĂ€ngas av efter fem sekunder. DĂ€refter vill operativsystemet Ă„terstĂ€lla diskens cache, diskarna kommer att snurra igen, och processen börjar om. Diskar har ett begrĂ€nsat maximalt antal snurrningar av spindeln. Denna enkla cykel som Ă€r standard kan lĂ€tt döda dina diskar pĂ„ nĂ„gra Ă„r. Detta drabbar inte alla diskar, men vĂ„ra
  • StĂ€ll in readahead pĂ„ snurrande diskar till 1 megabyte - tvĂ„ sekventiella block/chunk RAID 6
  • Förhindra readahead pĂ„ sjĂ€lva arrayerna.

LÄt oss redigera /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

Varför sÄ..?Vi kommer att söka efter partitionen /boot via UUID eftersom namnen pÄ arrayerna teoretiskt kan Àndras.

Vi kommer att söka efter övriga partitioner via LVM-namn i formatet /dev/mapper/vg-lv, eftersom de identifierar partitionerna tillrÀckligt unikt.

Vi anvÀnder inte UUID för LVM eftersom UUID för LVM-volymer och deras snapshotar kan överlappa.Mountar vi /dev/mapper/root-root tvÄ gÄnger..?Ja. Precis sÄ. Detta Àr en egenskap hos BTRFS. Detta filsystem kan monteras flera gÄnger med olika subvol.

Med anledning av denna egenskap rekommenderar jag att aldrig skapa LVM-snapshotar av aktiva BTRFS-volymer. Du kan fÄ en överraskning vid omstart.

Vi regenererar konfigurationen för mdadm:

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

Vi justerar instÀllningarna för 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

Vad var det..?Vi har aktiverat automatisk utvidgning av LVM thin-pooler nÀr 90 % av utrymmet Àr upptaget med 5 % av volymen.

Vi har ökat det maximala antalet cacheblock för LVM-cache.

Vi har förhindrat LVM frÄn att söka efter LVM-volymer (PV) pÄ:

  • enheter som innehĂ„ller LVM-cache (cdata)
  • enheter som Ă€r cachelagrade med LVM-cache förbi cachen (<lv_name>_corig). Den cachelagrade enheten kommer Ă€ndĂ„ att skannas genom cache (bara <lv_name>).
  • enheter som innehĂ„ller metadata för LVM-cache (cmeta)
  • alla enheter i VG med namnet images. HĂ€r kommer vi att ha avbilder av virtuella maskiners diskar, och vi vill inte att LVM pĂ„ vĂ€rden aktiverar volymer som tillhör gĂ€stoperativsystemet.
  • alla enheter i VG med namnet backup. HĂ€r kommer vi att ha sĂ€kerhetskopior av avbilder av virtuella maskiner.
  • alla enheter vars namn slutar med "gpv" (guest physical volume)

Vi har aktiverat DISCARD-stöd nÀr vi frigör ledigt utrymme pÄ LVM VG. Var försiktig. Detta kommer att göra borttagning av LV pÄ SSD ganska lÄngsam. SÀrskilt gÀller detta SSD RAID 6. Men enligt planen kommer vi att anvÀnda thin provisioning, sÄ det hÀr kommer inte att hindra oss.

Vi uppdaterar initramfs-avbilden:

#update-initramfs -u -k all

Vi installerar och konfigurerar grub:

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

Vilka diskar ska vi vÀlja?Alla som sd*. Systemet ska kunna starta frÄn vilken fungerande SATA-disk eller SSD som helst.

Varför har vi dödat os-prober..?För överdriven sjÀlvstÀndighet och nyfikenhet.

Det fungerar inte korrekt om nÄgon av RAID:erna Àr i ett degraderat tillstÄnd. Det försöker söka efter OS pÄ partitioner som anvÀnds i virtuella maskiner som körs pÄ denna hÄrdvara.

Om du behöver det kan du lÄta det vara, men tÀnk pÄ allt ovanstÄende. Jag rekommenderar att du söker efter lösningar för att bli av med nyfikenheten pÄ nÀtet.

HÀrmed avslutar vi den ursprungliga installationen. Det Àr dags att starta om till det nyinstallerade operativsystemet. Glöm inte att ta bort den bootbara Live CD/USB:n.

#exit
#reboot

Som boot-enhet vÀljer vi vilken som helst av SATA SSD.

LVM pÄ SATA SSD

Vid det hÀr laget har vi redan startat upp till det nya operativsystemet, konfigurerat nÀtverket, apt, öppnat terminalemulatorn och kört:

#sudo bash

Vi fortsÀtter.

Vi "initialiserar" matrisen av SATA SSD:

#blkdiscard /dev/md2

Om det inte fungerar, försök:

#blkdiscard --step 65536 /dev/md2
Vi skapar LVM VG pÄ SATA SSD:

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

Varför ytterligare en VG..?Vi har redan en VG med namnet root. Varför inte lÀgga till allt i en VG?

Om det finns flera PV i VG mÄste alla PV vara nÀrvarande (online) för att VG ska aktiveras korrekt. Undantaget Àr LVM RAID, som vi avsiktligt inte anvÀnder.

Vi vill verkligen att nÀr det sker ett fel (lÀs dataloss) i nÄgon av RAID 6-arrayerna, sÄ att operativsystemet laddas som det ska och ger oss möjlighet att lösa problemet.

För detta syfte kommer vi pÄ den första abstraheringsnivÄn att isolera varje typ av fysisk "bÀrare" i en separat VG.

Om vi pratar vetenskapligt, sÄ tillhör olika RAID-arrayer olika "pÄlitlighetsomrÄden". Det Àr inte bra att skapa en ytterligare gemensam felpunkt för dem genom att stoppa dem i en VG.

Att ha LVM pÄ "hÄrdvarunivÄ" kommer att göra det möjligt för oss att dela upp olika RAID-arrayer pÄ olika sÀtt genom att kombinera dem. Till exempel, att köra samtidigt bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, en komplex ZFS-konfiguration med cachar eller vilken annan hemsk kombination som helst, för att prova och jÀmföra allt detta.

PÄ "hÄrdvarunivÄ" kommer vi inte att anvÀnda nÄgot annat Àn de gamla goda "tjocka" LVM-volymerna. Undantaget frÄn denna regel kan möjligen vara partitionen för sÀkerhetskopiering.

Jag tror att mÄnga lÀsare har börjat misstÀnka nÄgot angÄende matryoshkan vid det hÀr laget.

LVM pÄ SATA HDD

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

Ännu en ny VG..?Vi vill verkligen att nĂ€r diskarrayen som vi kommer att anvĂ€nda för att sĂ€kerhetskopiera data gĂ„r ner, sĂ„ ska vĂ„rt operativsystem fortsĂ€tta att fungera som det ska, med fortsatt tillgĂ„ng till icke-sĂ€kerhetskopierade data. DĂ€rför, för att undvika problem med aktiveringen av VG, skapar vi en separat VG.

InstÀllning av LVM-cache

Vi skapar en LV pÄ NVMe RAID 1 för att anvÀnda den som en cachande enhet.

#lvcreate -L 70871154688B --name cache root

Varför sĂ„ lite
?Det handlar om att vĂ„ra NVMe SSD:er ocksĂ„ har SLC-cache. 4 gigabyte "gratis" och 18 gigabyte dynamiskt pĂ„ grund av det lediga utrymmet som upptas i 3-bit MLC. NĂ€r denna cache har uttömts kommer NVMe SSD:er att vara inte mycket snabbare Ă€n vĂ„ra SATA SSD:er med cache. Just dĂ€rför finns det ingen mening med att göra LVM-cachepartitionen mycket större Ă€n dubbla storleken pĂ„ NVMe-lagringens SLC-cache. För de anvĂ€nda NVMe-lagringarna anser författaren att det Ă€r rimligt att göra en cache pĂ„ 32-64 gigabyte.

Den angivna storleken pÄ partitionen Àr nödvÀndig för att organisera 64 gigabyte cache, lagra cache-metadata och en backup av metadata.

Jag vill ocksÄ nÀmna att efter en plötslig avstÀngning av systemet kommer LVM att mÀrka hela cachen som smutsig och synkronisera den pÄ nytt. Dessutom kommer detta att upprepas varje gÄng lvchange anvÀnds pÄ den hÀr enheten fram till nÀsta omstart av systemet. DÀrför rekommenderar jag att genast Äterskapa cachen med hjÀlp av ett lÀmpligt skript.

Vi skapar ett LV pÄ SATA RAID 6 för att anvÀnda det som en cachad enhet.

#lvcreate -L 3298543271936B --name cache data

Varför bara tre terabyte..?SÄ att SATA SSD RAID 6 kan anvÀndas för andra ÀndamÄl vid behov. Den cachade utrymmesstorleken kan ökas dynamiskt, pÄ sprÄng, utan att stÀnga av systemet. För detta behöver cachen tillfÀlligt stoppas och aktiveras igen, men en av de utmÀrkande fördelarna med LVM-cache framför bcache Àr att detta kan göras pÄ sprÄng.

Vi skapar en ny VG för caching.

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

Vi skapar ett LV pÄ den cachade enheten.

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

HÀr har vi genast tagit upp allt ledigt utrymme pÄ /dev/data/cache sÄ att alla andra nödvÀndiga partitioner skapas direkt pÄ /dev/root/cache. Om nÄgot skapades nÄgon annanstans kan det flyttas med hjÀlp av pvmove.

Vi skapar och aktiverar cachen:

#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

Varför en sÄdan chunksize..?Genom praktiska experiment har författaren kommit fram till att bÀsta resultat uppnÄs om storleken pÄ LVM-cachen överensstÀmmer med storleken pÄ LVM thin-blocket. Samtidigt visar sig konfigurationen prestera bÀttre vid mindre blockstorlekar i samband med slumpmÀssiga skrivningar.

64k Àr den minimi blockstorlek som tillÄts för LVM thin.

Var försiktig med writeback..!Ja. Denna typ av cache skjuter upp synkroniseringen av skrivningar till den cachade enheten. Detta innebÀr att vid förlust av cachen kan data gÄ förlorade pÄ den cachade enheten. Senare kommer författaren att berÀtta vilka ÄtgÀrder, förutom NVMe RAID 1, som kan vidtas för att kompensera för denna risk.

Denna typ av cache har valts med avsikt för att kompensera för den lÄga prestandan hos RAID 6 vid slumpmÀssiga skrivningar.

LÄt oss kontrollera vad vi har Ästadkommit:

#lvs -a -o lv_name,lv_size,devices --units B cache
LV LSize Enheter
[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)

PÄ /dev/data/cache ska endast [cachedata_corig] placeras. Om nÄgot Àr fel, anvÀnd pvmove.

Cachen kan stÀngas av vid behov med ett enda kommando:

#lvconvert -y --uncache cache/cachedata

Detta görs online. LVM synkroniserar bara cachen till disken, tar bort den och döper om cachedata_corig tillbaka till cachedata.

InstÀllning av LVM thin

Vi gör en ungefÀrlig uppskattning av hur mycket utrymme vi behöver för metadata för LVM thin:

#thin_metadata_size --block-size=64k --pool-size=6terabytes --max-thins=100000 -u bytes
thin_metadata_size - 3385794560 byte uppskattad metadata omrÄdesstorlek för "--block-size=64kibibytes --pool-size=6terabytes --max-thins=100000"

Vi rundar av till 4 gigabyte: 4294967296B

Vi multiplicerar med tvÄ och lÀgger till 4194304B för LVM PV metadata: 8594128896B
Vi skapar en separat partition pÄ NVMe RAID 1 för att lagra LVM thin-metadata och dess sÀkerhetskopiering:

#lvcreate -L 8594128896B --name images root

Varför..?HÀr kan en frÄga uppstÄ, varför lagra LVM thin-metadata separat, om de ÀndÄ kommer att cachas pÄ NVMe och arbeta snabbt.

Även om hastighet Ă€r viktig, Ă€r det lĂ„ngt ifrĂ„n den huvudsakliga orsaken. Det handlar om att cachen Ă€r en enskild felpunkt. NĂ„got kan hĂ€nda med den, och om LVM thin-metadata Ă€r cachade kan det leda till en total förlust av allt. Utan hela metadata blir det i princip omöjligt att Ă„terstĂ€lla de tunna volymerna.

Genom att flytta metadata till en separat, icke-cachad men snabb volym, garanterar vi att metadata bevaras i hÀndelse av förlust eller skada pÄ cachen. I det hÀr fallet kommer alla skador orsakade av cachförlust att lokaliseras inom de tunna volymerna, vilket avsevÀrt förenklar ÄterstÀllningsproceduren. Med stor sannolikhet kommer dessa skador att kunna ÄterstÀllas med hjÀlp av FS-loggar.

Dessutom, om en ögonblicksbild av den tunna volymen tidigare har tagits, och efter det har cachen en gÄng fullstÀndigt synkroniserats, kommer integriteten av ögonblicksbilden att garanteras vid förlust av cachen, pÄ grund av de interna egenskaperna hos LVM thin.

Vi skapar en ny VG som kommer att ansvara för thin-provisioning:

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

Vi skapar en pool:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Varför -Z yDessutom, för vad detta lĂ€ge faktiskt Ă€r avsett — att förhindra att data frĂ„n en virtuell maskin lĂ€cker till en annan vid omfördelning av utrymme — anvĂ€nds zeroing ocksĂ„ för att öka hastigheten för slumpmĂ€ssiga skrivningar med block mindre Ă€n 64k. Varje skrivning mindre Ă€n 64k i ett tidigare icke-allokerat omrĂ„de av den tunna volymen kommer att omvandlas till 64K som Ă€r anpassade till cachegrĂ€nsen. Detta gör att operationen kan utföras helt via cachen utan att passera den cachade enheten.

Vi flyttar LV till motsvarande PV:

#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

LÄt oss kontrollera:

#lvs -a -o lv_name,lv_size,devices --units B images
LV LSize Enheter
[lvol0_pmspare] 4294967296B /dev/root/images(0)
tunneltank 274877906944B tunneltank_tdata(0)
[tunneltank_tdata] 274877906944B /dev/cache/cachedata(0)
[tunneltank_tmeta] 4294967296B /dev/root/images(1024)

Vi skapar en tunn volym för tester:

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

Vi installerar paket för tester och övervakning:

#apt-get install sysstat fio

SÄ hÀr kan vi övervaka beteendet hos vÄr lagringskonfiguration i realtid:

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

SÄ hÀr kan vi testa vÄr konfiguration:

#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

Varning! Resurs!Den hÀr koden kommer att köra 36 olika tester, var och en av dem kommer att pÄgÄ i 4 sekunder. HÀlften av testerna handlar om skrivning. Under 4 sekunder kan man skriva en hel del pÄ NVMe. Upp till 3 gigabyte per sekund. SÄ varje körning av skrivtesterna kan anvÀnda upp till 216 gigabyte SSD-resurser.

LÀsa och skriva pÄ en gÄng?Ja. Det Àr meningsfullt att köra lÀsa- och skrivtester separat. Dessutom Àr det viktigt att se till att alla cache-minnen Àr synkroniserade, sÄ att tidigare skrivningar inte pÄverkar lÀsningen.

Resultaten kommer att variera kraftigt vid första körningen jÀmfört med efterföljande körningar, beroende pÄ cache-fyllning och tunna volymer, samt om systemet har lyckats synkronisera cachen som fylldes vid den föregÄende körningen.

Förutom detta rekommenderar jag att mÀta hastigheten pÄ en redan fylld tunn volym, som just fÄtt en snapshot. Författaren har haft möjlighet att observera hur slumpmÀssig skrivning plötsligt ökar strax efter att den första snapshoten skapats, sÀrskilt nÀr cachen inte Àr helt fylld. Detta beror pÄ copy-on-write-semantiken, blockutjÀmning av cache och den tunna volymen, och det faktum att slumpmÀssig skrivning pÄ RAID 6 omvandlas till slumpmÀssig lÀsning med RAID 6 följt av skrivning till cache. I vÄr konfiguration Àr slumpmÀssig lÀsning pÄ RAID 6 upp till 6 gÄnger (antalet SATA SSD i arrayen) snabbare Àn skrivning. Eftersom blocken för CoW tilldelas sekventiellt frÄn den tunna poolen, omvandlas skrivningen för det mesta ocksÄ till sekventiell.

BÄda dessa funktioner kan nyttjas fördelaktigt.

Cache-'koherent' snapshots

För att minska risken för dataförlust vid skador/förlust av cache föreslÄr författaren att införa en praktik med rotation av snapshots som garanterar deras integritet i sÄdana fall.

För det första, tack vare att metadata för tunna volymer Àr placerade pÄ ett icke-cacheat enhet, kommer metadata att vara intakt, och eventuella förluster kommer att isoleras inom datablokkarna.

Den följande rotationcykeln av snapshots garanterar dataintegritet inom snapshots i hÀndelse av cacheförlust:

  1. För varje tunn volym med namnet <namn> skapar vi en snapshot med namnet <namn>.cached
  2. LÄt oss sÀtta migrationsgrÀnsen pÄ ett rimligt högt vÀrde: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. I cykeln kontrollerar vi antalet smutsiga block i cachen: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' tills vi fÄr noll. Om nollan dröjer för lÀnge kan den temporÀrt skapas genom att stÀlla om cachen till writethrough-lÀge. Men med tanke pÄ hastighetskarakteristikerna hos vÄra SATA och NVMe SSD:er, samt deras TBW-resurs, kommer du antingen att kunna fÄnga ögonblicket ganska snabbt utan att Àndra cachelÀge, eller sÄ kommer din hÄrdvara att förbruka hela sin resurs pÄ bara nÄgra dagar. PÄ grund av resursbegrÀnsningar Àr systemet i princip oförmöget att vara under 100 % skrivbelastning konstant. VÄra NVMe SSD:er kommer helt att förbruka sin resurs vid 100 % skrivbelastning 3-4 dagar. SATA SSD:er kommer att leva ungefÀr tvÄ gÄnger lÀngre. DÀrför kommer vi att anta att den största delen av belastningen gÄr pÄ lÀsning, och att skrivningen ger relativt kortvariga toppar med extremt hög aktivitet i kombination med lÄg genomsnittlig belastning.
  4. SĂ„ snart vi fĂ„ngar (eller skapar) nollan – byt namn pĂ„ <namn>.cached till <namn>.committed. Den gamla <namn>.committed tas bort.
  5. Valfritt, om cachen Àr fylld till 100 %, kan den Äterskapas med ett skript, vilket pÄ sÄ sÀtt rensar den. Med en halvtom cache fungerar systemet mycket snabbare vid skrivning.
  6. Vi stÀller in migration threshold pÄ noll: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Detta kommer tillfÀlligt att förbjuda synkronisering av cachen till den primÀra enheten.
  7. Vi vÀntar tills det finns tillrÀckligt mÄnga förÀndringar i cachen #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' eller timern gÄr.
  8. Vi upprepar processen.

Varför komplicera med migration threshold
?Saken Ă€r den att i verklig praktik Ă€r "slumptals"-skrivning faktiskt inte helt slumpmĂ€ssig. Om vi har skrivit nĂ„got till en sektor pĂ„ 4 kilobyte, finns det en stor sannolikhet att det kommer att göras en skrivning till denna eller en av de nĂ€rliggande (+- 32K) sektorerna inom nĂ„gra minuter.

Genom att stÀlla in migration threshold pÄ noll skjuter vi upp synkroniseringen av skrivningen till SATA SSD:n och aggregerar flera förÀndringar av en 64K-block i cachen. PÄ sÄ sÀtt sparar vi betydligt pÄ resursen för SATA SSD.

Men var Àr koden..?TyvÀrr anser författaren att han inte Àr tillrÀckligt kompetent inom utvecklingen av bash-skript eftersom han Àr en 100 % sjÀlvlÀrd och praktiserar "google"-driven utveckling, dÀrför anser han att den skrÀmmande koden som kommer under hans hÀnder inte bör anvÀndas av nÄgon annan.

Jag tror att proffsen inom detta omrÄde sjÀlva kommer att kunna avbilda hela den ovan beskrivna logiken vid behov, och kanske till och med snyggt utforma det som en systemd-tjÀnst, som författaren försökte göra.

En enkel rotationsschema för snapshots gör att vi stÀndigt kan ha en fullt synkroniserad snapshot pÄ SATA SSD, och med hjÀlp av verktyget thin_delta kan vi ta reda pÄ vilka block som har Àndrats efter att den skapades, och dÀrmed lokalisera skador pÄ de primÀra volymerna, vilket kraftigt förenklar ÄterstÀllningen.

TRIM/DISCARD i libvirt/KVM

Eftersom datalagret kommer att anvÀndas för KVM under libvirt, vore det bra att lÀra vÄra VM att inte bara ta upp ledigt utrymme utan ocksÄ frigöra onödigt utrymme.

Detta görs genom att emulera stöd för TRIM/DISCARD pÄ virtuella diskar. För att göra detta mÄste vi Àndra kontrollerstypen till virtio-scsi och redigera 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'/>


</disk>

<controller type='scsi' index='0' model='virtio-scsi'>
<alias name='scsi0'/>


</controller>

SÄdana DISCARDs frÄn gÀst-OS hanteras korrekt av LVM, och block frigörs bÄde i cachen och i det tunna lagret. I vÄrt fall sker detta huvudsakligen fördröjt, vid borttagning av nÀsta snapshot.

Backup av BTRFS

AnvÀnd fÀrdiga skript med största försiktighet och pÄ egen risk. Författaren skrev denna kod sjÀlv och uteslutande för sig sjÀlv. Jag Àr sÀker pÄ att mÄnga erfarna Linux-anvÀndare har liknande hacklösningar, och det behövs ingen kopiering av andras.

Vi skapar en volym pÄ sÀkerhetsenheten:

#lvcreate -L 256G --name backup backup

Formatera som BTRFS:

#mkfs.btrfs /dev/backup/backup

Skapa monteringspunkter och montera rotunderkategorier för filsystemet:

#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

Skapa kataloger för sÀkerhetskopior:

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

Skapa en katalog för sÀkerhetskopieringsskript:

#mkdir /root/btrfs-backup

Kopiera skriptet:

Mycket skrĂ€mmande bash-kod. AnvĂ€nd pĂ„ egen risk. Inga arga brev till författaren
#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 "VÀntar pÄ lÄs..."
wait_lock || terminate "Misslyckades med att fÄ lÄs. Avslutar..."
echo "Fick lÄs..."
}

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 hittades"
else
echo "$SOURCE_BASE_PATH Filen hittades inte, skapar snapshot av $SOURCE_PATH till $SOURCE_BASE_PATH"
btrfs subvolymsnapshot -r $SOURCE_PATH $SOURCE_BASE_PATH
sync
if [ -d "$TARGET_BASE_PATH" ]
then
echo "$TARGET_BASE_PATH hittades, Àr ur synk med kÀllan... tar bort..."
btrfs subvolym ta bort -c $TARGET_BASE_PATH
sync
fi
fi
if [ -d "$TARGET_BASE_PATH" ]
then
echo "$TARGET_BASE_PATH hittades"
else
echo "$TARGET_BASE_PATH hittades inte. Synkroniserar till $TARGET_BASE_DIR"
btrfs send $SOURCE_BASE_PATH | btrfs ta emot $TARGET_BASE_DIR
sync
fi
if [ -d "$SOURCE_PEND_PATH" ]
then
echo "$SOURCE_PEND_PATH hittades, tar bort..."
btrfs subvolym ta bort -c $SOURCE_PEND_PATH
sync
fi
btrfs subvolymsnapshot -r $SOURCE_PATH $SOURCE_PEND_PATH
sync
if [ -d "$TARGET_PEND_PATH" ]
then
echo "$TARGET_PEND_PATH hittades, tar bort..."
btrfs subvolym ta bort -c $TARGET_PEND_PATH
sync
fi
echo "Skickar $SOURCE_PEND_PATH till $TARGET_PEND_PATH"
btrfs send -p $SOURCE_BASE_PATH $SOURCE_PEND_PATH | btrfs ta emot $TARGET_BASE_DIR
sync
TARGET_DATE_SUFFIX=$(suffix)
btrfs subvolymsnapshot -r $TARGET_PEND_PATH "$TARGET_PATH$TARGET_DATE_SUFFIX"
sync
btrfs subvolym ta bort -c $SOURCE_BASE_PATH
sync
btrfs subvolym ta bort -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 subvolym ta bort -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 "HjÀlp"
;;
"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 "Ingen.."
;;
esac
) 98>$LOCK_FILE

EOF

Vad gör det..?InnehÄller en uppsÀttning grundlÀggande kommandon för att skapa snapshots av BTRFS och kopiera dem till ett annat filsystem via BTRFS send/receive.

Första körningen kan ta relativt lÄng tid, eftersom alla data kommer att kopieras frÄn början. Efterföljande körningar kommer att vara mycket snabba, eftersom endast Àndringar kommer att kopieras.

Ännu ett skript som vi lĂ€gger i cron:

Lite mer bash-kod#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 dagar"
$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

Vad gör det..?Skapar och synkroniserar inkrementella snapshots av de angivna BTRFS-volymerna pÄ backup-filsystemet. Efter det tar det bort alla snapshots skapade för 60 dagar sedan. Efter körning kommer daterade snapshots av de angivna volymerna att dyka upp i underkatalogerna /backup/btrfs/back/remote/.

LÄt oss ge koden körbehörighet:

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

LÄt oss kontrollera och lÀgga det i 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

LVM thin backup

Skapa en tunn pool pÄ reservdisken:

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

Installera ddrescue, eftersom skripten kommer att anvÀnda detta verktyg:

#apt-get install gddrescue

Skapa en katalog för skripten:

#mkdir /root/lvm-thin-backup

Vi kopierar skript:

Mycket bash inuti...#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 "VÀntar pÄ lÄs..."
wait_lock || terminate "Misslyckades med att fÄ lÄs. Avslutar..."
echo "Fick lÄs..."
}

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 "Ursprung LV Àr inte tunt.")
exit 1
fi

if [ "$DIFF_TARGET_POOL" == "" ]
then
(>&2 echo "MÄl LV Àr inte tunt.")
exit 1
fi

if [ "$DIFF_SOURCE_POOL" != "$DIFF_TARGET_POOL" ]
then
(>&2 echo "KÀlla och mÄl LV tillhör olika tunt pooler.")
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 "Metadata snapshot för tunn pool finns redan. Antar att det Àr gammalt. Kommer att frigöra metadata snapshot om 5 sekunder.")
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 "Misslyckades att skapa metadata snapshot för tunn pool.")
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 hittad"
else
echo "$DISCARD_LV hittades inte i $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 "KĂ€llbas hittades inte, skapar snapshot av $SOURCE_VG/$SOURCE_LV till $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 "Gör av med $SOURCE_BASE_LV_PATH dÄ vi behöver starta om."
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 hittades, inte synkroniserad med kÀllan... tar bort..."
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 hittades"
else
echo "$TARGET_VG/$TARGET_LV hittades inte. Skapar tom volym."
lvcreate --thin-pool "$BACKUPS_POOL" -V "$SOURCE_BASE_SIZE"B --name "$TARGET_BASE_LV" "$TARGET_VG" || exit 1
echo "MÄste starta om. Gör av med kÀllan pÄ $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 "Gör av med mÄlet pÄ $TARGET_BASE_LV_PATH"
discard_volume "$TARGET_VG" "$TARGET_BASE_LV"
sync
fi
if [ "$SOURCE_PEND_LV_PATH" != "" ]
then
echo "$SOURCE_PEND_LV_PATH hittades och tas bort..."
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 hittades och tas bort..."
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 "Synkroniserar $SOURCE_PEND_LV_PATH till $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 hittades inte"
exit 1
fi
if [ "$TARGET_BASE_LV_PATH" != "" ]
then
echo "$TARGET_BASE_LV_PATH hittades"
else
echo "$TARGET_BASE_LV_PATH hittades inte"
exit 1
fi
activate_volume "$TARGET_VG" "$TARGET_BASE_LV"
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
echo JÀmför "$SOURCE_BASE_LV_PATH" med "$TARGET_BASE_LV_PATH"
cmp "$SOURCE_BASE_LV_PATH" "$TARGET_BASE_LV_PATH"
echo FĂ€rdig...
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 hittades inte"
exit 1
fi
if [ "$TARGET_BASE_LV_PATH" != "" ]
then
echo "$TARGET_BASE_LV_PATH hittades"
else
echo "$TARGET_BASE_LV_PATH hittades inte"
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 Synkroniserar "$SOURCE_BASE_LV_PATH" till "$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 "Synkroniserar $SYNC_LENGTH_BYTES byte vid $SYNC_OFFSET_BYTES frÄn $SOURCE_BASE_LV_PATH till $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 FĂ€rdig...
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 "HjÀlp"
;;
"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 "Ingen.."
;;
esac
) 98>$LOCK_FILE

EOF

Vad gör det...?InnehÄller ett set med kommandon för att manipulera tunna snapshots och synkronisera skillnader mellan tvÄ tunna snapshots med hjÀlp av thin_delta till en annan blockenhet med ddrescue och blkdiscard.

Ytterligare ett skript som vi kommer att lÀgga till i cron:

Lite mer bash#cat >/root/lvm-thin-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

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

BACKUP_SCRIPT="$SCRIPT_DIR/lvm-thin-backup.sh"
RETENTION="-60 dagar"

$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

Vad gör det...?AnvÀnder det föregÄende skriptet för att skapa och synkronisera backuper av de angivna tunna volymerna. Skriptet kommer att lÀmna kvar inaktiva snapshots av de angivna volymerna som behövs för att spÄra förÀndringar sedan senaste synkronisering.

Detta skript behöver redigeras för att ange listan över tunna volymer som behöver backas upp. De angivna namnen Àr endast exempel. Om sÄ önskas kan ett skript skrivas som synkroniserar alla volymer.

Ge rÀttigheter:

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

LÄt oss kontrollera och lÀgga det i 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

Första körningen kommer att ta tid, eftersom de tunna volymerna kommer att synkroniseras helt genom att kopiera hela det anvÀnda utrymmet. Tack vare LVM thin metadata vet vi vilka block som faktiskt anvÀnds, sÄ endast de verkligt anvÀnda blocken kommer att kopieras.

Efterföljande körningar kommer att kopiera data inkrementellt tack vare spÄrning av förÀndringar via LVM thin metadata.

vid "laddning" av containern visar att containermiljön starkt beror pÄ den bÀddade montering (Endast början av en lÄng utdata visas).

#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 mar 26 09:11 .
drwxr-xr-x 1 root root 16 mar 6 09:30 ..
drwxr-xr-x 1 root root 322 mar 26 02:00 .@base
drwxr-xr-x 1 root root 516 mar 6 09:39 .@snap.2020-03-06-09-39-37
drwxr-xr-x 1 root root 516 mar 6 09:39 .@snap.2020-03-06-09-39-57
...
/backup/btrfs/back/remote/root:
total 0
drwxr-xr-x 1 root root 2820 mar 26 09:11 .
drwxr-xr-x 1 root root 16 mar 6 09:30 ..
drwxr-xr-x 1 root root 240 mar 26 09:11 @.@base
drwxr-xr-x 1 root root 22 mar 26 09:11 @home.@base
drwxr-xr-x 1 root root 22 mar 6 09:39 @home.@snap.2020-03-06-09-39-35
drwxr-xr-x 1 root root 22 mar 6 09:39 @home.@snap.2020-03-06-09-39-57
...
drwxr-xr-x 1 root root 240 mar 6 09:39 @.@snap.2020-03-06-09-39-26
drwxr-xr-x 1 root root 240 mar 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

Vad har matryoshkor med detta att göra?

Det handlar antagligen om att logiska volymer LVM LV kan vara fysiska volymer LVM PV för andra VG. LVM kan vara rekursivt, som matryoshkor. Detta ger LVM en extraordinÀr flexibilitet.

P.S.

I nÀsta artikel kommer vi att försöka anvÀnda flera sÄdana mobila lagringssystem/KVM som grund för att skapa ett geo-fördelat lagrings-/vm-kluster med redundans pÄ flera kontinenter genom hem-datorer, hem-internet och P2P-nÀtverk.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster