Mitä yhteistä on LVM:llä ja Matryoshkalla?

Hyvää päivää.
Haluaisin jakaa yhteisön kanssa käytännön kokemukseni KVM:n tiedontallennusjärjestelmän rakentamisesta md RAID + LVM:n avulla.

Ohjelma sisältää:

  • md RAID 1:n rakentaminen NVMe SSD:ltä.
  • Md RAID 6:n kokoaminen SATA SSD:ltä ja tavallisilta asemista.
  • TRIM/DISCARD-toiminnan ominaisuudet SSD RAID 1/6:ssa.
  • Käynnistettävän md RAID 1/6 -ryhmän luominen yhteiselle levyjoukolle.
  • Järjestelmän asentaminen NVMe RAID 1:een, kun BIOS ei tue NVMe-tukea.
  • Käytä LVM-välimuistia ja LVM thin.
  • BTRFS-snapshot-kuvien käyttäminen ja lähetys/vastaanotto varmuuskopiointia varten.
  • LVM ohuiden tilannekuvien ja thin_deltan käyttäminen BTRFS-tyylisiin varmuuskopioihin.

Jos olet kiinnostunut, katso kissa.

Заявление

Kirjoittaja ei ole vastuussa tämän artikkelin materiaalien/esimerkkien/koodin/vinkkien/tietojen käytön tai käyttämättä jättämisen seurauksista. Lukemalla tai käyttämällä tätä materiaalia millään tavalla otat vastuun kaikista näiden toimien seurauksista. Mahdollisia seurauksia ovat:

  • Rapeaksi paistetut NVMe SSD -levyt.
  • Täysin käytetty tallennusresurssi ja SSD-asemien vika.
  • Kaikkien asemien tietojen täydellinen menetys, mukaan lukien varmuuskopiot.
  • Viallinen tietokonelaitteisto.
  • Hukkaa aikaa, hermoja ja rahaa.
  • Kaikki muut seuraukset, joita ei ole lueteltu yllä.

rauta

Saatavilla olivat:

Emolevy noin vuodelta 2013 Z87-piirisarjalla, jossa on Intel Core i7 / Haswell.

  • Prosessori 4 ydintä, 8 säiettä
  • 32GB DDR3 RAM
  • 1 x 16 tai 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 -liittimet

SAS-sovitin LSI SAS9211-8I välähti IT/HBA-tilaan. RAID-yhteensopiva laiteohjelmisto on tarkoituksella korvattu HBA-laiteohjelmistolla, jotta:

  1. Voit heittää tämän sovittimen pois milloin tahansa ja korvata sen millä tahansa muulla vastaantulemalla.
  2. TRIM/Discard toimi normaalisti levyillä, koska... RAID-laiteohjelmistossa näitä komentoja ei tueta ollenkaan, eikä HBA yleensä välitä siitä, mitkä komennot lähetetään väylän kautta.

Kiintolevyt - 8 kpl HGST Travelstar 7K1000, joiden kapasiteetti on 1 TB, 2.5-kokoinen, kuten kannettavissa tietokoneissa. Nämä asemat olivat aiemmin RAID 6 -ryhmässä. Niille on myös käyttöä uudessa järjestelmässä. Paikallisten varmuuskopioiden tallentamiseen.

Lisäksi lisätty:

6 kpl SATA SSD malli Samsung 860 QVO 2TB. Nämä SSD-levyt vaativat suurta määrää, SLC-välimuistin läsnäoloa, luotettavuutta ja alhaista hintaa. Discard/zero-tuki vaadittiin, mikä tarkistetaan rivillä dmesg:ssä:

kernel: ata1.00: Enabling discard_zeroes_data

2 kpl NVMe SSD mallia Samsung SSD 970 EVO 500GB.

Näille SSD-levyille satunnainen luku-/kirjoitusnopeus ja tarpeisiisi sopiva resurssikapasiteetti ovat tärkeitä. Jäähdytin heille. Välttämättä. Ehdottomasti. Muussa tapauksessa paista ne rapeiksi ensimmäisen RAID-synkronoinnin aikana.

StarTech PEX8M2E2 -sovitin 2 x NVMe SSD:lle asennettuna PCIe 3.0 8x -paikkaan. Tämä taas on vain HBA, mutta NVMe:lle. Se eroaa halvoista sovittimista siinä, että se ei vaadi PCIe-haaroitustukea emolevyltä sisäänrakennetun PCIe-kytkimen vuoksi. Se toimii jopa vanhimmassa PCIe-järjestelmässä, vaikka se olisi x1 PCIe 1.0 -paikka. Luonnollisesti sopivalla nopeudella. Siellä ei ole RAIDeja. Laitteessa ei ole sisäänrakennettua BIOSia. Joten järjestelmäsi ei maagisesti opi käynnistymään NVMe:n avulla, saati NVMe RAIDin tämän laitteen ansiosta.

Tämä komponentti johtui yksinomaan siitä, että järjestelmässä oli vain yksi ilmainen 8x PCIe 3.0, ja jos on 2 vapaata paikkaa, se voidaan helposti korvata kahdella penniäisellä PEX4M2E1:llä tai analogeilla, joita voi ostaa mistä tahansa hintaan 600 ruplaa.

Kaikenlaisten laitteistojen tai sisäänrakennettujen piirisarjan/BIOS RAID:ien hylkääminen tehtiin tarkoituksella, jotta koko järjestelmä voitaisiin korvata kokonaan, paitsi itse SSD/HDD, säilyttäen samalla kaikki tiedot. Ihannetapauksessa, jotta voit tallentaa jopa asennetun käyttöjärjestelmän, kun siirryt täysin uuteen/erilaiseen laitteistoon. Tärkeintä on, että siellä on SATA- ja PCIe-portit. Se on kuin live-CD tai käynnistettävä flash-asema, vain erittäin nopea ja hieman tilaa vievä.

ЮморMuuten tiedät mitä tapahtuu - joskus sinun on kiireellisesti otettava koko joukko mukaasi vietäväksi. Mutta en halua menettää tietoja. Tätä varten kaikki mainitut mediat sijaitsevat kätevästi vakiokotelon 5.25-paikkojen dioissa.

No, ja tietysti kokeilla erilaisia ​​SSD-välimuistimenetelmiä Linuxissa.

Laitteistot ovat tylsiä. Käynnistä se. Se joko toimii tai ei. Ja mdadmin kanssa on aina vaihtoehtoja.

Ohjelmisto

Aiemmin Debian 8 Jessie asennettiin laitteistoon, joka on lähellä EOL:a. RAID 6 koottiin edellä mainituista kiintolevyistä, jotka on yhdistetty LVM:n kanssa. Se suoritti virtuaalikoneita kvm/libvirtissä.

Koska Tekijällä on sopiva kokemus kannettavien käynnistettäväksi käytettävien SATA/NVMe-flash-asemien luomisesta, ja myös, jotta tavallista osuvaa mallia ei rikota, kohdejärjestelmäksi valittiin Ubuntu 18.04, joka on jo riittävästi vakiintunut, mutta jolla on vielä 3 vuotta käyttöaikaa. tukea tulevaisuudessa.

Mainittu järjestelmä sisältää kaikki tarvitsemamme laitteisto-ohjaimet. Emme tarvitse kolmannen osapuolen ohjelmistoja tai ohjaimia.

Valmistautuminen asennukseen

Järjestelmän asentamiseen tarvitaan Ubuntu Desktop Image. Palvelinjärjestelmässä on jonkinlainen voimakas asennusohjelma, joka osoittaa liiallista riippumattomuutta, jota ei voida poistaa käytöstä työntämällä UEFI-järjestelmäosio yhdelle levystä, mikä pilaa kaiken kauneuden. Näin ollen se asennetaan vain UEFI-tilassa. Ei tarjoa vaihtoehtoja.

Emme ole tyytyväisiä tähän.

Miksi?Valitettavasti UEFI-käynnistys on erittäin huonosti yhteensopiva käynnistysohjelmiston RAIDin kanssa, koska... Kukaan ei tarjoa meille varauksia UEFI ESP -osiolle. Verkossa on reseptejä, jotka ehdottavat ESP-osion sijoittamista USB-portissa olevaan flash-asemaan, mutta tämä on epäonnistumisen kohta. On olemassa reseptejä, jotka käyttävät ohjelmistoa mdadm RAID 1 metatietoversiolla 0.9, jotka eivät estä UEFI BIOSia näkemästä tätä osiota, mutta tämä kestää siihen onnelliseen hetkeen asti, jolloin BIOS tai muu laitteisto-käyttöjärjestelmä kirjoittaa jotain ESP:hen ja unohtaa synkronoida sen muihin peilit.

Lisäksi UEFI-käynnistys riippuu NVRAM-muistista, joka ei siirry levyjen mukana uuteen järjestelmään, koska on osa emolevyä.

Emme siis keksi uutta pyörää uudelleen. Meillä on jo valmiina, aika-testattu isoisän pyörä, nyt nimeltään Legacy/BIOS boot ja joka kantaa UEFI-yhteensopivissa järjestelmissä ylpeänä nimeä CSM. Otamme sen vain hyllyltä, voitelemme, pumppaamme renkaat ja pyyhimme sen kostealla liinalla.

Ubuntun työpöytäversiota ei myöskään voi asentaa kunnolla Legacy-käynnistyslataimella, mutta täällä, kuten sanotaan, ainakin vaihtoehtoja on.

Niinpä keräämme laitteistot ja lataamme järjestelmän Ubuntu Live -käynnistettävältä flash-asemalta. Meidän on ladattava paketteja, joten määritämme sinulle sopivan verkon. Jos se ei toimi, voit ladata tarvittavat paketit flash-asemalle etukäteen.

Siirrymme työpöytäympäristöön, käynnistämme pääteemulaattorin ja aloitamme:

#sudo bash

Miten…?Yllä oleva rivi on kanoninen laukaisu holiwarsille sudoa varten. C bоsuurempia mahdollisuuksia tulee jaоsuurempaa vastuuta. Kysymys kuuluu, voitko ottaa sen itse. Monet ihmiset ajattelevat, että sudon käyttäminen tällä tavalla ei ainakaan ole varovaista. Kuitenkin:

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

Miksei ZFS...?Kun asennamme ohjelmistoja tietokoneellemme, lainaamme laitteistomme pääasiassa tämän ohjelmiston kehittäjille.
Kun luotamme tähän ohjelmistoon tietojemme turvallisuuteen, otamme lainan, joka vastaa näiden tietojen palauttamisen kustannuksia, ja joudumme joskus maksamaan sen pois.

Tästä näkökulmasta katsottuna ZFS on Ferrari, ja mdadm+lvm on enemmän kuin polkupyörä.

Subjektiivisesti kirjoittaja lainaa mieluummin pyörää luotolla tuntemattomille henkilöille Ferrarin sijaan. Siellä numeron hinta ei ole korkea. Oikeuksia ei tarvita. Yksinkertaisempi kuin liikennesäännöt. Pysäköinti on ilmaista. Maastohiihtokyky on parempi. Pyörään voi aina kiinnittää jalat ja pyörän voi korjata omin käsin.

Miksi sitten BTRFS...?Käyttöjärjestelmän käynnistämiseksi tarvitsemme tiedostojärjestelmän, jota tuetaan Legacy/BIOS GRUB:ssa heti valmiina ja joka tukee samalla reaaliaikaisia ​​tilannekuvia. Käytämme sitä /boot-osiolle. Lisäksi kirjoittaja käyttää mieluummin tätä FS:ää / (root) -sovellukselle, unohtamatta huomata, että kaikille muille ohjelmistoille voit luoda erilliset osiot LVM:ään ja liittää ne tarvittaviin hakemistoihin.

Emme tallenna virtuaalikoneiden tai tietokantojen kuvia tähän FS:ään.
Tätä FS:ää käytetään vain tilannekuvien luomiseen järjestelmästä sammuttamatta sitä ja sitten siirtämään nämä tilannevedokset varmuuskopiolevylle lähettämällä/vastaanottamalla.

Lisäksi kirjoittaja haluaa yleensä pitää mahdollisimman vähän ohjelmistoja suoraan laitteistossa ja käyttää kaikkia muita ohjelmistoja virtuaalikoneissa käyttämällä esimerkiksi GPU:iden ja PCI-USB-isäntäohjaimien välittämistä KVM:lle IOMMU:n kautta.

Laitteistoon jää vain tietojen tallennus, virtualisointi ja varmuuskopiointi.

Jos luotat ZFS:ään enemmän, ne ovat periaatteessa vaihdettavissa määritetylle sovellukselle.

Kirjoittaja jättää kuitenkin tietoisesti huomioimatta ZFS:n, BRTFS:n ja LVM:n sisäänrakennetut peilaus/RAID- ja redundanssiominaisuudet.

Lisäargumenttina BTRFS:llä on kyky muuttaa satunnaiset kirjoitukset peräkkäisiksi, millä on erittäin positiivinen vaikutus kiintolevyn tilannekuvien/varmuuskopioiden synkronoinnin nopeuteen.

Skannaa kaikki laitteet uudelleen:

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

Katsotaanpa ympärillesi:

#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

Levyn asettelu

NVMe SSD

Mutta emme merkitse niitä millään tavalla. BIOS ei kuitenkaan näe näitä asemia. Joten ne menevät kokonaan ohjelmisto-RAIDiin. Emme edes luo osioita sinne. Jos haluat noudattaa "kanonia" tai "periaatteessa", luo yksi suuri osio, kuten kiintolevy.

SATA-kiintolevy

Ei tässä tarvitse keksiä mitään erikoista. Luomme yhden osion kaikelle. Luomme osion, koska BIOS näkee nämä levyt ja saattaa jopa yrittää käynnistää niiltä. Asennamme jopa GRUB:n näille levyille myöhemmin, jotta järjestelmä voi yhtäkkiä tehdä tämän.

#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

SATA SSD

Täällä asiat kiinnostavat meitä.

Ensinnäkin asemamme ovat kooltaan 2 TB. Tämä on hyväksyttävällä alueella MBR:lle, jota käytämme. Tarvittaessa voidaan korvata GPT:llä. GPT-levyillä on yhteensopivuuskerros, jonka avulla MBR-yhteensopivat järjestelmät voivat nähdä ensimmäiset 4 osiota, jos ne sijaitsevat kahden ensimmäisen teratavun sisällä. Tärkeintä on, että näiden levyjen käynnistysosio ja bios_grub-osio ovat alussa. Tämä mahdollistaa jopa käynnistämisen GPT Legacy/BIOS -asemista.

Mutta tämä ei ole meidän tapaus.

Tässä luomme kaksi osiota. Ensimmäinen on kooltaan 1 Gt ja sitä käytetään RAID 1:lle / käynnistys.

Toista käytetään RAID 6:lle ja se vie kaiken jäljellä olevan vapaan tilan lukuun ottamatta pientä jakamatonta aluetta aseman lopussa.

Mikä tämä merkitsemätön alue on?Verkossa olevien lähteiden mukaan SATA SSD -levyillämme on dynaamisesti laajennettava SLC-välimuisti, jonka koko vaihtelee 6 - 78 gigatavua. Saamme 6 gigatavua "ilmaiseksi" aseman tietosivun "gigatavujen" ja "gibitavujen" välisen eron vuoksi. Loput 72 gigatavua on varattu käyttämättömästä tilasta.

Tässä on huomattava, että meillä on SLC-välimuisti, ja tila on varattu 4-bittisessä MLC-tilassa. Mikä tarkoittaa meille käytännössä sitä, että jokaista 4 gigatavua vapaata tilaa kohden saamme vain 1 gigatavua SLC-välimuistia.

Kerro 72 gigatavua neljällä ja saat 4 gigatavua. Tämä on vapaa tila, jota emme merkitse, jotta asemat voivat hyödyntää täysimääräisesti SLC-välimuistia.

Siten saamme tehokkaasti jopa 312 gigatavua SLC-välimuistia yhteensä kuudesta asemasta. Kaikista asemista 2 käytetään RAIDissa redundanssiin.

Tämä välimuistin määrä antaa meille mahdollisuuden äärimmäisen harvoin kohdata tosielämässä tilannetta, jossa kirjoitus ei mene välimuistiin. Tämä kompensoi erittäin hyvin QLC-muistin surullisinta haittaa - erittäin alhaista kirjoitusnopeutta, kun dataa kirjoitetaan ohittamalla välimuisti. Jos kuormasi eivät vastaa tätä, suosittelen harkitsemaan tarkasti, kuinka kauan SSD-levysi kestää tällaisella kuormituksella, ottaen huomioon tietolomakkeen TBW.

#cat >ssd.part << EOF
label: dos
label-id: 0x00000000
device: /dev/sda
unit: sectors

/dev/sda1 : start= 2048, size= 2097152, type=fd, bootable
/dev/sda2 : start= 2099200, size= 3300950016, type=fd
EOF
#sfdisk /dev/sda < ssd.part
#sfdisk /dev/sdb < ssd.part
#sfdisk /dev/sdc < ssd.part
#sfdisk /dev/sdd < ssd.part
#sfdisk /dev/sde < ssd.part
#sfdisk /dev/sdf < ssd.part

Arrayiden luominen

Ensin meidän on nimettävä kone uudelleen. Tämä on välttämätöntä, koska isäntänimi on osa taulukon nimeä jossain mdadm:n sisällä ja vaikuttaa johonkin jossain. Tietenkin taulukot voidaan nimetä uudelleen myöhemmin, mutta tämä on tarpeeton vaihe.

#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

Miksi -oleta-puhdas...?Välttääksesi taulukoiden alustamisen. Tämä koskee sekä RAID-tasoja 1 että 6. Kaikki voi toimia ilman alustusta, jos se on uusi matriisi. Lisäksi SSD-ryhmän alustaminen luomisen yhteydessä on TBW-resurssien tuhlausta. Käytämme TRIM/DISCARDia mahdollisuuksien mukaan kootuissa SSD-ryhmissä niiden "alustamiseen".

SSD-ryhmissä RAID 1 DISCARD on tuettu heti.

SSD RAID 6 DISCARD -taulukoissa sinun on otettava se käyttöön ydinmoduulin parametreissa.

Tämä tulisi tehdä vain, jos kaikilla tämän järjestelmän tason 4/5/6 taulukoissa käytetyillä SSD-levyillä on toimiva discard_zeroes_data-tuki. Joskus törmäät outoihin asemiin, jotka kertovat ytimelle, että tätä toimintoa tuetaan, mutta todellisuudessa sitä ei ole tai toiminto ei aina toimi. Tällä hetkellä tuki on saatavilla melkein kaikkialla, mutta siellä on vanhoja asemia ja laiteohjelmistoja, joissa on virheitä. Tästä syystä DISCARD-tuki on oletuksena poistettu käytöstä RAID 6:ssa.

Huomio, seuraava komento tuhoaa kaikki NVMe-asemien tiedot "alustaa" taulukon "nollailla".

#blkdiscard /dev/md0

Jos jokin menee pieleen, yritä määrittää vaihe.

#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

Miksi niin iso...?Kappaleen koon lisäämisellä on positiivinen vaikutus satunnaislukemisen nopeuteen lohkoissa kappalekokoon asti. Tämä johtuu siitä, että yksi sopivan kokoinen tai pienempi toiminto voidaan suorittaa kokonaan yhdellä laitteella. Siksi kaikkien laitteiden IOPS lasketaan yhteen. Tilastojen mukaan 99% IO:sta ei ylitä 512K.

RAID 6 IOPS kirjoitusta kohti aina pienempi tai yhtä suuri kuin yhden aseman IOPS. Kun satunnaislukuna IOPS voi olla useita kertoja suurempi kuin yhden aseman, ja tässä lohkon koolla on keskeinen merkitys.
Kirjoittaja ei näe järkeä yrittää optimoida parametria, joka on huono RAID 6:n suunnittelussa, vaan optimoi sen, missä RAID 6 on hyvä.
Kompensoimme RAID 6:n huonon satunnaisen kirjoituksen NVMe-välimuistilla ja ohuilla hallintatempuilla.

Emme ole vielä ottaneet käyttöön DISCARDia RAID 6:lle. Emme siis "alusta" tätä ryhmää toistaiseksi. Teemme tämän myöhemmin käyttöjärjestelmän asennuksen jälkeen.

SATA-kiintolevy

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

LVM NVMe RAIDissa

Nopeuden vuoksi haluamme sijoittaa juuritiedostojärjestelmän NVMe RAID 1:een, joka on /dev/md0.
Tarvitsemme kuitenkin edelleen tätä nopeaa taulukkoa muihin tarpeisiin, kuten swap-, metatieto- ja LVM-välimuistiin sekä LVM-ohut metatietoihin, joten luomme LVM VG:n tälle joukolle.

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

Luodaan osio juuritiedostojärjestelmälle.

#lvcreate -L 128G --name root root

Luodaan osio vaihtamista varten RAM-muistin koon mukaan.

#lvcreate -L 32G --name swap root

OS asennus

Kaiken kaikkiaan meillä on kaikki tarvittava järjestelmän asentamiseen.

Käynnistä ohjattu järjestelmän asennustoiminto Ubuntu Live -ympäristöstä. Normaali asennus. Vain asennuslevyjen valintavaiheessa sinun on määritettävä seuraavat:

  • /dev/md1, - liitoskohta /boot, FS - BTRFS
  • /dev/root/root (alias /dev/mapper/root-root), - liitoskohta / (juuri), FS - BTRFS
  • /dev/root/swap (alias /dev/mapper/root-swap), - käytä swap-osiona
  • Asenna käynnistyslatain hakemistoon /dev/sda

Kun valitset päätiedostojärjestelmäksi BTRFS:n, asennusohjelma luo automaattisesti kaksi BTRFS-taltiota, joiden nimi on "@" / (root) ja "@home" /home.

Aloitetaan asennus...

Asennus päättyy modaaliseen valintaikkunaan, joka ilmaisee käynnistyslataimen asennuksessa tapahtuneen virheen. Valitettavasti et voi poistua tästä valintaikkunasta tavallisilla tavoilla ja jatkaa asennusta. Kirjaudumme ulos järjestelmästä ja kirjaudumme uudelleen sisään, jolloin päädymme puhtaaseen Ubuntu Live -työpöytään. Avaa pääte ja uudelleen:

#sudo bash

Luo chroot-ympäristö jatkaaksesi asennusta:

#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

Määritetään verkko ja isäntänimi chrootissa:

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

Siirrytään chroot-ympäristöön:

#chroot /mnt/chroot

Ensin toimitamme paketit:

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

Tarkastetaan ja korjataan kaikki paketit, jotka asennettiin väärin järjestelmän epätäydellisen asennuksen vuoksi:

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

Jos jokin ei toimi, saatat joutua muokkaamaan tiedostoa /etc/apt/sources.list ensin

Säädetään RAID 6 -moduulin parametreja ottaaksesi käyttöön TRIM/DISCARD:

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

Muokataan hieman taulukkojamme:

#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

Mitä se oli..?Olemme luoneet joukon udev-sääntöjä, jotka tekevät seuraavat:

  • Aseta RAID 2020:lle lohkovälimuistin koko riittäväksi vuodelle 6. Oletusarvo ei näytä olevan muuttunut Linuxin luomisen jälkeen, eikä se ole ollut riittävä pitkään aikaan.
  • Varaa vähintään IO taulukon tarkistusten/synkronointien ajaksi. Tämä estää taulukoitasi juuttumasta ikuisen synkronoinnin tilaan kuormituksen alaisena.
  • Rajoita suurinta IO:ta taulukoiden tarkistusten/synkronoinnin aikana. Tämä on välttämätöntä, jotta SSD RAID -levyjen synkronointi/tarkistus ei paista levyjäsi rapeaksi. Tämä koskee erityisesti NVMe:tä. (Muistatko jäähdyttimen? En vitsaillut.)
  • Estä levyjä pysäyttämästä karan pyörimistä (HDD) APM:n kautta ja aseta levyohjainten lepotilan aikakatkaisu 7 tuntiin. Voit poistaa APM:n kokonaan käytöstä, jos asemasi voivat tehdä sen (-B 255). Oletusarvolla taajuusmuuttajat pysähtyvät viiden sekunnin kuluttua. Sitten käyttöjärjestelmä haluaa nollata levyvälimuistin, levyt pyörivät uudelleen ja kaikki alkaa alusta. Levyillä on rajoitettu enimmäismäärä karan kierroksia. Tällainen yksinkertainen oletussykli voi helposti tappaa levysi muutamassa vuodessa. Kaikki levyt eivät kärsi tästä, mutta meidän levymme ovat "kannettavia", joissa on asianmukaiset oletusasetukset, jotka tekevät RAIDista näyttämään mini-MAIDilta.
  • Asenna Readahead levyille (pyörivä) 1 megatavu – kaksi peräkkäistä lohkoa/pala RAID 6
  • Poista Readahead käytöstä itse taulukoissa.

Muokataan tiedostoa /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

Miksi niin..?Etsimme /boot-osion UUID:n avulla. Taulukon nimeäminen voi teoriassa muuttua.

Etsimme loput osat LVM-nimien mukaan /dev/mapper/vg-lv-merkinnästä, koska ne tunnistavat osiot melko yksilöllisesti.

Emme käytä UUID:tä LVM:lle, koska LVM-taltioiden UUID ja niiden tilannekuvat voivat olla samat.Liitä /dev/mapper/root-root.. kahdesti?Joo. Tarkalleen. BTRFS:n ominaisuus. Tämä tiedostojärjestelmä voidaan asentaa useita kertoja eri alivolyymeillä.

Tämän saman ominaisuuden vuoksi en suosittele koskaan luomaan LVM-vedoksia aktiivisista BTRFS-taltioista. Saatat saada yllätyksen, kun käynnistät uudelleen.

Luodaan uudelleen mdadm-asetus:

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

Säädetään LVM-asetuksia:

#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

Mitä se oli..?Olemme sallineet LVM ohuiden altaiden automaattisen laajennuksen, kun 90 % käytössä olevasta tilasta on saavutettu 5 % tilavuudesta.

Olemme lisänneet LVM-välimuistin välimuistilohkojen enimmäismäärää.

Olemme estäneet LVM:ää etsimästä LVM-määriä (PV):

  • laitteet, jotka sisältävät LVM-välimuistin (cdata)
  • laitteet välimuistiin LVM-välimuistin avulla ohittaen välimuistin ( _corig). Tässä tapauksessa itse välimuistissa oleva laite tarkistetaan edelleen välimuistin kautta (vain ).
  • laitteet, jotka sisältävät LVM-välimuistin metatietoja (cmeta)
  • kaikki VG-laitteet nimikuvilla. Täällä meillä on virtuaalikoneiden levykuvia, emmekä halua isäntäkoneen LVM:n aktivoivan vieraskäyttöjärjestelmään kuuluvia asemia.
  • kaikki VG:n laitteet, joiden nimi on varmuuskopio. Täällä meillä on varmuuskopiot virtuaalikoneen kuvista.
  • kaikki laitteet, joiden nimi päättyy "gpv" (vieraan fyysinen äänenvoimakkuus)

Olemme ottaneet käyttöön DISCARD-tuen vapauttaessamme vapaata tilaa LVM VG:ssä. Ole varovainen. Tämä tekee LV:iden poistamisesta SSD-levyltä melko aikaa vievää. Tämä koskee erityisesti SSD RAID 6:ta. Suunnitelman mukaan käytämme kuitenkin ohutta provisiointia, joten tämä ei estä meitä ollenkaan.

Päivitetään initramfs-kuva:

#update-initramfs -u -k all

Asenna ja määritä grub:

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

Mitkä levyt valita?Kaikki, jotka ovat sd*. Järjestelmän on voitava käynnistyä mistä tahansa toimivasta SATA-asemasta tai SSD-levystä.

Miksi he lisäsivät os-proberin..?Liialliseen itsenäisyyteen ja leikkisään käsiin.

Se ei toimi oikein, jos jokin RAID-levyistä on heikentyneessä tilassa. Se yrittää etsiä käyttöjärjestelmää osioista, joita käytetään tällä laitteistolla toimivissa virtuaalikoneen.

Jos tarvitset sitä, voit jättää sen, mutta muista kaikki edellä mainitut asiat. Suosittelen etsimään netistä reseptejä, joilla pääset eroon tuhmista käsistä.

Tällä olemme saaneet alkuasennuksen valmiiksi. On aika käynnistää uudelleen äskettäin asennettuun käyttöjärjestelmään. Älä unohda irrottaa käynnistettävä Live CD/USB.

#exit
#reboot

Valitse käynnistyslaitteeksi mikä tahansa SATA SSD -levy.

LVM SATA SSD:llä

Tässä vaiheessa olemme jo käynnistäneet uuteen käyttöjärjestelmään, määrittäneet verkon, apt, avanneet pääteemulaattorin ja suorittaneet:

#sudo bash

Jatkataan.

"Alusta" joukko SATA SSD:ltä:

#blkdiscard /dev/md2

Jos se ei toimi, kokeile:

#blkdiscard --step 65536 /dev/md2
Luo LVM VG SATA SSD:lle:

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

Miksi toinen VG..?Itse asiassa meillä on jo VG nimeltä root. Miksi ei lisätä kaikkea yhdeksi VG:ksi?

Jos VG:ssä on useita PV:itä, kaikkien PV:iden on oltava läsnä (online), jotta VG aktivoituu oikein. Poikkeuksena on LVM RAID, jota emme tarkoituksella käytä.

Haluamme todella, että jos jossakin RAID 6 -ryhmässä tapahtuu vika (lukutietojen menetys), käyttöjärjestelmä käynnistyy normaalisti ja antaa meille mahdollisuuden ratkaista ongelma.

Tätä varten eristämme abstraktion ensimmäisellä tasolla jokaisen fyysisen "median" tyypin erilliseksi VG:ksi.

Tieteellisesti ottaen eri RAID-ryhmät kuuluvat eri "luotettavuusalueisiin". Sinun ei pitäisi luoda heille ylimääräistä yhteistä vikakohtaa ahmimalla niitä yhteen VG:hen.

LVM:n läsnäolo "laitteistotasolla" antaa meille mahdollisuuden leikata mielivaltaisesti osia eri RAID-ryhmistä yhdistämällä niitä eri tavoilla. Esimerkiksi - juokse samanaikaisesti bcache + LVM thin, bcache + BTRFS, LVM välimuisti + LVM thin, monimutkainen ZFS-kokoonpano välimuistilla tai mikä tahansa muu helvetin sekoitus vertailla sitä kaikkea.

"Laitteistotasolla" emme käytä mitään muuta kuin vanhoja hyviä "paksuja" LVM-taltioita. Poikkeuksena tähän sääntöön voi olla varmuuskopiointiosio.

Luulen, että tähän hetkeen mennessä monet lukijat olivat jo alkaneet epäillä jotain pesänukkesta.

LVM SATA HDD:llä

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

Taas uusi VG..?Haluamme todella, että jos tietojen varmuuskopiointiin käyttämämme levyryhmä epäonnistuu, käyttöjärjestelmämme jatkaa toimintaansa normaalisti, mutta säilyttää pääsyn muihin kuin varmuuskopioituihin tietoihin tavalliseen tapaan. Siksi VG-aktivointiongelmien välttämiseksi luomme erillisen VG:n.

LVM-välimuistin asetukset

Luodaan LV NVMe RAID 1:lle käyttääksesi sitä välimuistilaitteena.

#lvcreate -L 70871154688B --name cache root

Miksi on niin vähän...?Tosiasia on, että NVMe SSD -levyillämme on myös SLC-välimuisti. 4 gigatavua "ilmaista" ja 18 gigatavua dynaamista 3-bittisen MLC:n varatun vapaan tilan ansiosta. Kun tämä välimuisti on käytetty loppuun, NVMe SSD -levyt eivät ole paljon nopeampia kuin SATA SSD -levymme välimuistilla. Itse asiassa tästä syystä meidän ei ole järkevää tehdä LVM-välimuistiosiosta paljon suurempi kuin kaksi kertaa NVMe-aseman SLC-välimuistin koko. Käytettyjen NVMe-asemien osalta kirjoittaja pitää järkevänä tehdä 32-64 gigatavua välimuistia.

Annettu osion koko tarvitaan 64 gigatavun välimuistin, välimuistin metatietojen ja metatietojen varmuuskopion järjestämiseen.

Lisäksi huomaan, että likaisen järjestelmän sammutuksen jälkeen LVM merkitsee koko välimuistin likaiseksi ja synkronoi uudelleen. Lisäksi tämä toistetaan aina, kun lvchangea käytetään tässä laitteessa, kunnes järjestelmä käynnistetään uudelleen. Siksi suosittelen välimuistin luomista välittömästi uudelleen käyttämällä sopivaa komentosarjaa.

Luodaan LV SATA RAID 6:een käyttääksesi sitä välimuistilaitteena.

#lvcreate -L 3298543271936B --name cache data

Miksi vain kolme teratavua..?Jotta voit tarvittaessa käyttää SATA SSD RAID 6:ta muihin tarpeisiin. Välimuistitilan kokoa voidaan kasvattaa dynaamisesti, lennossa, järjestelmää pysäyttämättä. Tätä varten välimuisti on väliaikaisesti pysäytettävä ja otettava uudelleen käyttöön, mutta LVM-välimuistin erottuva etu esimerkiksi bcacheen verrattuna on, että tämä voidaan tehdä lennossa.

Luodaan uusi VG välimuistia varten.

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

Luodaan LV välimuistilaitteeseen.

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

Täällä otimme heti kaiken vapaan tilan /dev/data/cache, joten kaikki muut tarvittavat osiot luotiin välittömästi /dev/root/cache. Jos loit jotain väärään paikkaan, voit siirtää sen pvmovella.

Luodaan ja otetaan käyttöön välimuisti:

#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

Miksi noin kokoisia..?Käytännön kokeiden avulla kirjoittaja sai selville, että paras tulos saavutetaan, jos LVM-välimuistilohkon koko on sama kuin LVM-ohutlohkon koko. Lisäksi mitä pienempi koko, sitä paremmin konfiguraatio toimii satunnaisessa tallennuksessa.

64k on LVM ohuille sallittu pienin lohkokoko.

Varo kirjoittamista..!Joo. Tämän tyyppinen välimuisti lykkää kirjoitussynkronointia välimuistissa olevaan laitteeseen. Tämä tarkoittaa, että jos välimuisti katoaa, voit menettää välimuistissa olevan laitteen tietoja. Myöhemmin kirjoittaja kertoo, mihin toimenpiteisiin NVMe RAID 1:n lisäksi voidaan ryhtyä tämän riskin kompensoimiseksi.

Tämä välimuistityyppi valittiin tarkoituksella kompensoimaan RAID 6:n huonoa satunnaista kirjoitussuoritusta.

Katsotaan mitä meillä on:

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

Vain [cachedata_corig] tulee sijaita kansiossa /dev/data/cache. Jos jokin on vialla, käytä pvmovea.

Voit tarvittaessa poistaa välimuistin käytöstä yhdellä komennolla:

#lvconvert -y --uncache cache/cachedata

Tämä tehdään verkossa. LVM yksinkertaisesti synkronoi välimuistin levylle, poistaa sen ja nimeää cachedata_corig uudelleen välimuistiin.

LVM thin asetukset

Arvioidaan karkeasti, kuinka paljon tilaa tarvitsemme LVM:n ohuille metatiedoille:

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

Pyöristä 4 gigatavuun: 4294967296B

Kerro kahdella ja lisää 4194304B LVM PV -metatiedoille: 8594128896B
Luodaan NVMe RAID 1:lle erillinen osio LVM-metatietojen ja niiden varmuuskopion sijoittamiseksi siihen:

#lvcreate -L 8594128896B --name images root

Minkä vuoksi..?Tässä saattaa herää kysymys: miksi LVM:n ohuita metatietoja sijoitetaan erikseen, jos ne säilyvät edelleen NVMe:n välimuistissa ja toimivat nopeasti.

Vaikka nopeus on tässä tärkeä asia, se on kaukana tärkeimmistä syistä. Asia on, että välimuisti on epäonnistumispiste. Sille voi tapahtua jotain, ja jos LVM:n ohut metatiedot tallennetaan välimuistiin, kaikki menetetään kokonaan. Ilman täydellisiä metatietoja on lähes mahdotonta koota ohuita volyymeja.

Siirtämällä metatiedot erilliseen välimuistiin tallentamattomaan, mutta nopeaan taltioon takaamme metatietojen turvallisuuden välimuistin katoamisen tai vioittumisen varalta. Tässä tapauksessa kaikki välimuistin katoamisen aiheuttamat vahingot lokalisoidaan ohuiden levyjen sisään, mikä yksinkertaistaa palautusmenettelyä suuruusluokkaa. Suurella todennäköisyydellä nämä vauriot korjataan käyttämällä FS-lokeja.

Lisäksi, jos tilannekuva ohuesta tilavuudesta otettiin aiemmin ja sen jälkeen välimuisti on synkronoitu kokonaan vähintään kerran, LVM thin sisäisen suunnittelun ansiosta tilannevedoksen eheys taataan välimuistin katoamisen yhteydessä. .

Luodaan uusi VG, joka vastaa suppeasta provisiosta:

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

Luodaan allas:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Miksi -Z ySen lisäksi, mihin tämä tila on todellisuudessa tarkoitettu - jotta yhdestä virtuaalikoneen dataa ei vuotaisi toiseen virtuaalikoneeseen tilaa uudelleen jaettaessa - nollausta käytetään lisäksi lisäämään satunnaisen kirjoittamisen nopeutta alle 64k:n lohkoissa. Kaikki alle 64 kt:n kirjoitukset ohuen tilavuuden aiemmin varaamattomalle alueelle muuttuvat välimuistissa 64 kt:n reunatasaiseksi. Tämä mahdollistaa toiminnon suorittamisen kokonaan välimuistin kautta välimuistissa olevan laitteen ohittaen.

Siirretään LV:t vastaaviin PV:ihin:

#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

Tarkista:

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

Luodaan ohut tilavuus testejä varten:

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

Asennamme paketteja testejä ja valvontaa varten:

#apt-get install sysstat fio

Näin voit tarkkailla tallennuskokoonpanomme toimintaa reaaliajassa:

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

Näin voimme testata kokoonpanomme:

#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

Huolellisesti! Resurssi!Tämä koodi suorittaa 36 erilaista testiä, joista jokainen kestää 4 sekuntia. Puolet testeistä on tallennettavia. Voit tallentaa paljon NVMe:llä 4 sekunnissa. Jopa 3 gigatavua sekunnissa. Jokainen kirjoitustesti voi siis syödä sinulta jopa 216 gigatavua SSD-resurssia.

Lukeminen ja kirjoittaminen sekoitettuna?Joo. On järkevää suorittaa luku- ja kirjoitustestit erikseen. Lisäksi on järkevää varmistaa, että kaikki välimuistit synkronoidaan, jotta aiemmin tehty kirjoitus ei vaikuta lukemiseen.

Tulokset vaihtelevat suuresti ensimmäisen käynnistyksen ja sitä seuraavien käyntien aikana, kun välimuisti ja ohut volyymi täyttyvät, ja myös riippuen siitä, onnistuiko järjestelmä synkronoimaan viimeisimmän käynnistyksen aikana täytetyt välimuistit.

Suosittelen muun muassa nopeuden mittaamista jo valmiiksi ohuelta tilavuudelta, josta tilannekuva on juuri otettu. Tekijällä oli mahdollisuus tarkkailla kuinka satunnaiset kirjoitukset kiihtyvät jyrkästi heti ensimmäisen tilannevedoksen luomisen jälkeen, varsinkin kun välimuisti ei ole vielä täysin täynnä. Tämä johtuu kopioinnin kirjoitussemantiikasta, välimuistin kohdistamisesta ja ohuista tilavuuslohkoista sekä siitä, että satunnainen kirjoitus RAID 6:een muuttuu satunnaiseksi lukemiseksi RAID 6:sta, jota seuraa kirjoitus välimuistiin. Kokoonpanossamme satunnainen lukeminen RAID 6:sta on jopa 6 kertaa nopeampi kuin kirjoittaminen (jossa on SATA SSD -levyjen määrä). Koska CoW:n lohkot allokoidaan peräkkäin ohuesta poolista, jolloin tallennus muuttuu myös suurimmaksi osaksi peräkkäiseksi.

Molempia ominaisuuksia voidaan käyttää eduksesi.

Tallenna "yhtenäiset" tilannekuvat välimuistiin

Tietojen katoamisen riskin vähentämiseksi välimuistin vaurioituessa/menetyksessä kirjoittaja ehdottaa, että otetaan käyttöön tilannekuvien kiertäminen niiden eheyden takaamiseksi tässä tapauksessa.

Ensinnäkin, koska ohut metatiedot sijaitsevat välimuistissa olevissa laitteissa, metatiedot ovat johdonmukaisia ​​ja mahdolliset häviöt eristetään tietolohkojen sisällä.

Seuraava tilannekuvan kiertojakso takaa tilannekuvien sisällä olevien tietojen eheyden välimuistin katoamisen varalta:

  1. Luo kullekin ohuelle taltiolle, jonka nimi on <nimi>, tilannevedos, jonka nimi on <nimi>.cached
  2. Asetetaan siirtokynnys kohtuullisen korkeaksi arvoksi: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Silmukassa tarkistamme välimuistissa olevien likaisten lohkojen määrän: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' kunnes saamme nollan. Jos nolla puuttuu liian kauan, se voidaan luoda vaihtamalla välimuisti väliaikaisesti kirjoitustilaan. Kun kuitenkin huomioidaan SATA- ja NVMe SSD-levyjemme nopeusominaisuudet sekä niiden TBW-resurssit, voit joko saada hetken nopeasti kiinni vaihtamatta välimuistitilaa tai laitteistosi syö kokonaan koko resurssinsa. Muutama päivä. Resurssirajoituksista johtuen järjestelmä ei periaatteessa voi olla koko ajan alle 100 %:n kirjoituskuorman. NVMe SSD -levyjemme alle 100 % kirjoituskuormituksen kuluttavat resurssit kokonaan 3-4 päivää. SATA SSD -levyt kestävät vain kaksi kertaa niin kauan. Siksi oletetaan, että suurin osa kuormituksesta menee lukemiseen, ja meillä on suhteellisen lyhytaikaisia ​​erittäin korkean aktiivisuuden purskeita yhdistettynä keskimäärin alhaiseen kuormitukseen kirjoittamiseen.
  4. Heti kun saimme (tai teimme) nollan, nimemme <nimi>.cached uudelleen muotoon <nimi>.committed. Vanha <nimi>.sitoutunut poistetaan.
  5. Valinnaisesti, jos välimuisti on 100 % täynnä, se voidaan luoda uudelleen skriptillä, jolloin se tyhjennetään. Puolityhjällä välimuistilla järjestelmä toimii paljon nopeammin kirjoitettaessa.
  6. Aseta siirtymäkynnys nollaan: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Tämä estää väliaikaisesti välimuistia synkronoimasta päämediaan.
  7. Odotamme, kunnes välimuistiin kertyy melko paljon muutoksia #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' tai ajastin sammuu.
  8. Toistamme uudestaan.

Miksi vaikeudet maahanmuuttokynnyksen kanssa...?Asia on siinä, että käytännössä "satunnainen" tallennus ei itse asiassa ole täysin satunnaista. Jos kirjoitimme jotain 4 kilotavun sektoriin, on suuri todennäköisyys, että seuraavan parin minuutin aikana samaan tai johonkin naapurisektoriin (+- 32K) tehdään tietue.

Asettamalla siirtokynnyksen nollaan lykkäämme kirjoitussynkronointia SATA SSD:lle ja yhdistämme useita muutoksia yhteen 64K-lohkoon välimuistissa. Tämä säästää merkittävästi SATA SSD:n resursseja.

Missä koodi on..?Valitettavasti kirjoittaja ei pidä itseään riittävän pätevänä bash-skriptien kehittämisessä, koska hän on 100% itseoppinut ja harjoittaa "google"-pohjaista kehitystä, joten hän uskoo, että hänen käsistään tulevaa kauheaa koodia ei pitäisi käyttää kenenkään. muu.

Uskon, että alan ammattilaiset pystyvät tarvittaessa kuvaamaan itsenäisesti kaiken yllä kuvatun logiikan ja ehkä jopa suunnittelemaan sen kauniisti järjestelmäpalveluksi, kuten kirjoittaja yritti tehdä.

Tällainen yksinkertainen tilannekuvan kiertomalli antaa meille mahdollisuuden paitsi jatkuvasti synkronoida yksi tilannekuva täysin SATA SSD:lle, myös sen avulla voimme Thin_delta-apuohjelman avulla selvittää, mitkä lohkot on muutettu sen luomisen jälkeen, ja siten paikallistaa vauriot tärkeimmät volyymit, mikä yksinkertaistaa palautumista huomattavasti.

TRIM/DISCARD libvirt/KVM:ssä

Koska Tietotallennustilaa käytetään libvirt-ajoa käyttävään KVM:ään, silloin olisi hyvä idea opettaa virtuaalikoneemme paitsi viemään vapaata tilaa, myös vapauttamaan tarpeettomat.

Tämä tehdään emuloimalla TRIM/DISCARD-tukea virtuaalilevyillä. Tätä varten sinun on vaihdettava ohjaimen tyypiksi virtio-scsi ja muokattava 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>

LVM käsittelee tällaiset vieraskäyttöjärjestelmien hylkäämiset oikein, ja lohkot vapautetaan oikein sekä välimuistissa että ohuessa poolissa. Meidän tapauksessamme tämä tapahtuu pääasiassa viiveellä, kun seuraavaa tilannekuvaa poistetaan.

BTRFS varmuuskopio

Käytä valmiita skriptejä äärimmäinen varovaisuutta ja omalla vastuulla. Kirjoittaja kirjoitti tämän koodin itse ja yksinomaan itselleen. Olen varma, että monilla kokeneilla Linux-käyttäjillä on samanlaisia ​​työkaluja, eikä kenenkään muun tarvitse kopioida.

Luodaan taltio varmuuskopiolaitteeseen:

#lvcreate -L 256G --name backup backup

Muotoillaan se BTRFS:llä:

#mkfs.btrfs /dev/backup/backup

Luodaan liitospisteitä ja liitetään tiedostojärjestelmän juurialaosat:

#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

Luodaan hakemistoja varmuuskopioille:

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

Luodaan hakemisto varmuuskopioskripteille:

#mkdir /root/btrfs-backup

Kopioidaan skripti:

Paljon pelottavaa bash-koodia. Käytä omalla vastuullasi. Älä kirjoita vihaisia ​​kirjeitä kirjoittajalle...#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

Mitä se edes tekee..?Sisältää joukon yksinkertaisia ​​komentoja BTRFS-snapshot-kuvien luomiseen ja niiden kopioimiseen toiseen FS:ään käyttämällä BTRFS-lähetys/vastaanotto-toimintoa.

Ensimmäinen laukaisu voi olla suhteellisen pitkä, koska... Alussa kaikki tiedot kopioidaan. Jatkojulkaisut ovat erittäin nopeita, koska... Vain muutokset kopioidaan.

Toinen käsikirjoitus, jonka laitamme croniin:

Lisää bash-koodia#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

Mitä se tekee..?Luo ja synkronoi varmuuskopion BTRFS-taltioiden lisävedoksia. Tämän jälkeen se poistaa kaikki 60 päivää sitten luodut kuvat. Käynnistyksen jälkeen luetteloitujen taltioiden päivätyt tilannekuvat näkyvät /backup/btrfs/back/remote/-alihakemistoissa.

Annetaan koodin suoritusoikeudet:

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

Tarkastetaan ja laitetaan se croniin:

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

Luodaan ohut pooli varmuuskopiolaitteeseen:

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

Asennataan ddrescue, koska... komentosarjat käyttävät tätä työkalua:

#apt-get install gddrescue

Luodaan hakemisto skripteille:

#mkdir /root/lvm-thin-backup

Kopioidaan skriptit:

Paljon röyhkeyttä sisällä...#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

Mitä se tekee...?Sisältää joukon komentoja ohuiden tilannekuvien manipuloimiseksi ja kahden ohuen tilannevedoksen välisen eron synkronoimiseksi thin_delta:n kautta toiseen lohkolaitteeseen käyttämällä ddrescue- ja blkdiscard-tiedostoja.

Toinen skripti, jonka laitamme croniin:

Hieman lisää röyhkeyttä#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

Mitä se tekee...?Käyttää edellistä komentosarjaa luetteloitujen ohuiden taltioiden varmuuskopioiden luomiseen ja synkronoimiseen. Skripti jättää luetteloituista taltioista passiivisia tilannekuvia, joita tarvitaan edellisen synkronoinnin jälkeen tehtyjen muutosten seuraamiseen.

Tätä komentosarjaa on muokattava ja määritettävä luettelo ohuista levyistä, joista varmuuskopiot tulee tehdä. Annetut nimet ovat vain havainnollistavia. Halutessasi voit kirjoittaa skriptin, joka synkronoi kaikki taltiot.

Annetaan oikeudet:

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

Tarkastetaan ja laitetaan se croniin:

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

Ensimmäinen laukaisu tulee olemaan pitkä, koska... ohuet taltiot synkronoidaan täysin kopioimalla kaikki käytetty tila. LVM ohuen metatietojen ansiosta tiedämme, mitkä lohkot ovat todella käytössä, joten vain todellisuudessa käytetyt ohuet volyymilohkot kopioidaan.

Myöhemmät ajot kopioivat tiedot asteittain LVM-metatietojen muutosseurannan ansiosta.

Katsotaan, mitä tapahtui:

#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

Mitä tekemistä tällä on pesivien nukkejen kanssa?

Todennäköisimmin, koska LVM LV:n loogiset volyymit voivat olla LVM PV fyysisiä volyymeja muille VG:ille. LVM voi olla rekursiivinen, kuten sisäkkäiset nuket. Tämä antaa LVM:lle äärimmäisen joustavuuden.

PS.

Seuraavassa artikkelissa yritämme käyttää useita samankaltaisia ​​mobiilitallennusjärjestelmiä/KVM:ää perustana maantieteellisesti hajautetun tallennus-/vm-klusterin luomiselle, jossa on redundanssi useilla mantereilla käyttämällä kotitietokoneita, koti Internet- ja P2P-verkkoja.

Lähde: will.com

Lisää kommentti