LVM менен Матрешкада эмне жалпылыгы бар?

Жакшы күн.
Мен коомчулук менен md RAID + LVM аркылуу KVM үчүн маалыматтарды сактоо тутумун куруу боюнча практикалык тажрыйбам менен бөлүшкүм келет.

Программа төмөнкүлөрдү камтыйт:

  • NVMe SSDден md RAID 1 куруу.
  • SATA SSD жана кадимки дисктерден md RAID 6 чогултуу.
  • SSD RAID 1/6 боюнча TRIM/DISCARD операциясынын өзгөчөлүктөрү.
  • Жалпы дисктердин топтомунда жүктөлүүчү md RAID 1/6 массивин түзүү.
  • BIOS'та NVMe колдоосу жок болгондо системаны NVMe RAID 1ге орнотуу.
  • LVM кэшин жана LVM жука колдонуу.
  • BTRFS сүрөттөрүн колдонуу жана камдык көчүрмө үчүн жөнөтүү/кабыл алуу.
  • BTRFS стилиндеги камдык көчүрмөлөр үчүн LVM ичке көз ирмемдик сүрөттөрүн жана thin_delta колдонуу.

Эгер сизди кызыктырса, мышыкка кайрылыңыз.

арыз

Бул макаладагы материалдарды/мисалдар/код/кеңештер/маалыматтарды колдонуу же колдонбоо кесепеттери үчүн автор эч кандай жоопкерчилик тартпайт. Бул материалды окуу же кандайдыр бир жол менен колдонуу менен, сиз бул аракеттердин бардык кесепеттери үчүн жоопкерчилик тартасыз. Мүмкүн болгон кесепеттерге төмөнкүлөр кирет:

  • Куурулган NVMe SSDs.
  • Жазуу ресурсу толугу менен сарпталган жана SSD дисктеринин иштебей калышы.
  • Бардык дисктердеги бардык маалыматтардын, анын ичинде резервдик көчүрмөлөрдүн толук жоголушу.
  • Компьютердин жабдыктары бузулган.
  • Убакыт, нерв жана акча текке кетти.
  • Жогоруда саналбаган башка кесепеттер.

темир

Төмөнкүлөр жеткиликтүү болгон:

Intel Core i2013 / Haswell менен толукталган Z87 чипсети менен 7-жылдын тегерегиндеги энелик плата.

  • Процессор 4 ядро, 8 жип
  • 32 ГБ DDR3 RAM
  • 1 x 16 же 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 туташтыргычтары

SAS адаптери LSI SAS9211-8I IT / HBA режимине жарк этти. RAID иштетилген микропрограмма төмөнкү максаттар үчүн HBA микропрограммасы менен атайылап алмаштырылды:

  1. Сиз бул адаптерди каалаган убакта ыргытып жиберип, аны башкасына алмаштырсаңыз болот.
  2. TRIM/Discard дисктерде кадимкидей иштеген, анткени... RAID микропрограммасында бул буйруктар такыр колдоого алынбайт жана HBA, жалпысынан, автобус аркылуу кандай буйруктар берилип жатканына маани бербейт.

Катуу дисктер - 8 даана HGST Travelstar 7K1000 сыйымдуулугу 1 ТБ 2.5 форма факторунда, ноутбуктар үчүн. Бул дисктер мурда RAID 6 массивинде болгон. Алар да жаңы системада колдонууга ээ болот. Жергиликтүү камдык көчүрмөлөрдү сактоо үчүн.

Кошумча кошулду:

6 даана SATA SSD модели Samsung 860 QVO 2TB. Бул SSD'лер чоң көлөмдү, SLC кэшинин болушун, ишенимдүүлүктү жана арзан бааны талап кылган. Discard/нөл үчүн колдоо талап кылынган, ал dmesg ичиндеги сап менен текшерилет:

kernel: ata1.00: Enabling discard_zeroes_data

2 даана NVMe SSD модели Samsung SSD 970 EVO 500GB.

Бул SSD'лер үчүн кокустук окуу/жазуу ылдамдыгы жана сиздин муктаждыктарыңыз үчүн ресурстук сыйымдуулук маанилүү. Алар үчүн радиатор. Сөзсүз. Абсолюттук. Болбосо, биринчи RAID синхрондоштуруу учурунда кытырак чейин аларды кууруу.

PCIe 8 2x уячасына орнотулган 2 x NVMe SSD үчүн StarTech PEX2M3.0E8 адаптери. Бул дагы эле HBA, бирок NVMe үчүн. Ал арзан адаптерлерден айырмаланат, анткени ал орнотулган PCIe которгучу бар болгондуктан, энелик платадан PCIe бифуркациясынын колдоосун талап кылбайт. Ал x1 PCIe 1.0 уячасы болсо да, PCIe менен эң байыркы системада да иштейт. Албетте, тиешелүү ылдамдыкта. Ал жерде эч кандай RAID жок. Бортто орнотулган BIOS жок. Ошентип, сиздин тутумуңуз NVMe менен жүктөөнү сыйкырдуу түрдө үйрөнбөйт, бул аппараттын аркасында NVMe RAID дагы азыраак.

Бул компонент системада бир гана бекер 8x PCIe 3.0 болушу менен шартталган жана 2 бош уяча бар болсо, аны эки пенни PEX4M2E1 же аналогдору менен оңой алмаштырууга болот, аларды каалаган жерден 600 баада сатып алууга болот. рубль.

Бардык маалыматтарды сактоо менен, SSD/HDDди кошпогондо, бүт системаны толугу менен алмаштыруу мүмкүнчүлүгүнө ээ болуу үчүн, бардык түрдөгү аппараттык каражаттарды же орнотулган чипсетти/BIOS RAIDдерди четке кагуу атайылап жасалган. Идеалында, сиз толугу менен жаңы/башка жабдыкка өткөндө орнотулган операциялык системаны да сактап кала аласыз. Эң негизгиси SATA жана PCIe порттору бар. Бул жандуу CD же жүктөлүүчү флэш-диск сыяктуу, болгону абдан тез жана бир аз көлөмдүү.

көңулБолбосо, эмне болорун билесиз - кээде сиз тез арада бүт массивди алып кетишиңиз керек. Бирок мен маалыматтарды жоготкум келбейт. Бул үчүн, бардык аталган медиа стандарттык корпустун 5.25 булуңундагы слайддарда ыңгайлуу жайгашкан.

Ооба, жана, албетте, Linux'та SSD кэштөөнүн ар кандай ыкмалары менен эксперимент жүргүзүү үчүн.

Аппараттык рейддер кызыксыз. Аны күйгүзүңүз. Бул же иштейт, же иштебейт. Жана mdadm менен ар дайым варианттар бар.

жумшак

Буга чейин Debian 8 Jessie EOLга жакын болгон жабдыкка орнотулган. RAID 6 LVM менен жупташкан жогоруда аталган HDDлерден чогултулган. Ал kvm/libvirtте виртуалдык машиналарды иштеткен.

Анткени Автордун портативдик жүктөөчү SATA/NVMe флэш-дисктерин түзүү боюнча ылайыктуу тажрыйбасы бар, ошондой эле кадимки ылайыктуу шаблонду бузбоо үчүн максаттуу система катары Ubuntu 18.04 тандалган, ал буга чейин жетиштүү турукташкан, бирок дагы эле 3 жылдык иштөө мөөнөтү бар. келечекте колдоо.

Белгиленген система кутудан тышкары бизге керек болгон бардык аппараттык драйверлерди камтыйт. Бизге үчүнчү тараптын программалары же драйверлери керек эмес.

Даярдоо үчүн орнотуу

Системаны орнотуу үчүн бизге Ubuntu Desktop Image керек. Сервер тутумунда кандайдыр бир күчтүү орнотуучу бар, ал ашыкча көз карандысыздыкты көрсөтөт, аны UEFI тутумунун бөлүгүн дисктердин бирине түртүп, бардык сулуулукту бузат. Демек, ал UEFI режиминде гана орнотулган. Эч кандай варианттарды сунуштабайт.

Биз буга ыраазы эмеспиз.

Эмне үчүн?Тилекке каршы, UEFI жүктөө RAID жүктөө программасы менен өтө начар шайкеш келет, анткени... Эч ким бизге UEFI ESP бөлүмү үчүн ээлеп коюуну сунуштабайт. Интернетте ESP бөлүмүн USB портундагы флеш-дискке жайгаштырууну сунуш кылган рецепттер бар, бирок бул ийгиликсиздик. 1 метадайындар версиясы бар mdadm RAID 0.9 программасын колдонгон рецепттер бар, алар UEFI BIOS бул бөлүктү көрүүгө тоскоолдук кылбайт, бирок бул BIOS же башка аппараттык OS ESPге бир нерсе жазып, аны башкасына синхрондоштурууну унутуп калган бактылуу учурга чейин жашайт. күзгүлөр.

Мындан тышкары, UEFI жүктөө NVRAMдан көз каранды, ал дисктер менен бирге жаңы системага жылбайт, анткени Motherboard бөлүгү болуп саналат.

Демек, биз жаңы дөңгөлөктү кайра ойлоп таппайбыз. Бизде буга чейин эле UEFI шайкеш системаларда CSM деген сыймыктуу аталышка ээ болгон Legacy/BIOS жүктөө деп аталган даяр, убакыт сынагынан өткөн чоң атанын велосипеди бар. Биз аны текчеден алып чыгып, майлап, дөңгөлөктөрдү насостоп, нымдуу чүпүрөк менен сүртүп алабыз.

Ubuntuнун рабочий версиясын Legacy жүктөөчүсү менен туура орнотуу мүмкүн эмес, бирок бул жерде, алар айткандай, жок дегенде варианттар бар.

Ошентип, биз аппараттык каражаттарды чогултуп, системаны Ubuntu Live жүктөлүүчү флеш-дискинен жүктөйбүз. Биз пакеттерди жүктөп алышыбыз керек, андыктан сиз үчүн иштеген тармакты орнотобуз. Эгер ал иштебесе, керектүү топтомдорду флеш-дискке алдын ала жүктөсөңүз болот.

Биз Desktop чөйрөсүнө кирип, терминалдык эмуляторду ишке киргизебиз жана чыгабыз:

#sudo bash

Кантип…?Жогорудагы сызык судо жөнүндө холиварлар үчүн канондук триггер болуп саналат. C бокөбүрөөк мүмкүнчүлүктөр келет жанаокөбүрөөк жоопкерчилик. Аны өз мойнуңузга ала аласызбы деген суроо туулат. Көптөр мындай жол менен sudo колдонуу, жок эле дегенде, этият эмес деп ойлошот. Бирок:

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

Эмне үчүн ZFS эмес...?Компьютерибизге программалык камсыздоону орноткондо, биз негизинен бул программаны иштеп чыгуучуларга аппараттык жабдыктарды айдоо үчүн карызга беребиз.
Бул программага маалыматтарыбыздын коопсуздугу менен ишенгенибизде, биз бул маалыматтарды калыбына келтирүү наркына барабар насыя алабыз, аны качандыр бир күнү төлөшүбүз керек.

Бул жагынан алып караганда, ZFS Ferrari болуп саналат, ал эми мдам+лвм дагы велосипедге окшош.

Субъективдүү түрдө автор Ferrari эмес, белгисиз адамдарга кредитке велосипед берүүнү туура көрөт. Ал жерде маселенин баасы жогору эмес. Укуктардын кереги жок. Жол эрежесине караганда жөнөкөй. Унаа токтоочу жай бекер. Кросстук жөндөмдүүлүк жакшыраак. Велосипедге дайыма буттарды жабышса болот, ал эми велосипедди өз колуңуз менен оңдосоңуз болот.

Эмне үчүн анда BTRFS ...?Иштөө тутумун жүктөө үчүн бизге Legacy/BIOS GRUB кутучасынан тышкары колдоого алынган жана ошол эле учурда жандуу сүрөттөрдү колдогон файл системасы керек. Биз аны / жүктөө бөлүмү үчүн колдонобуз. Мындан тышкары, автор бул FSди / (root) үчүн колдонууну артык көрөт, башка программалык камсыздоо үчүн LVMде өзүнчө бөлүмдөрдү түзүп, аларды керектүү каталогдорго орното аласыз.

Биз бул ФСте виртуалдык машиналардын же маалымат базаларынын сүрөттөрүн сактабайбыз.
Бул FS системаны өчүрбөстөн эле анын көз ирмемдик сүрөттөрүн түзүү үчүн гана колдонулат жана андан кийин жөнөтүү/кабыл алуу аркылуу бул сүрөттөрдү резервдик дискке өткөрүү үчүн колдонулат.

Кошумчалай кетсек, автор жалпысынан программалык камсыздоонун минималдуу бөлүгүн түз аппараттык жабдыкта сактоону жана GPUларды жана PCI-USB Хост контроллерлорун IOMMU аркылуу KVMге жөнөтүү сыяктуу нерселерди колдонуп, виртуалдык машиналарда башка программаларды иштетүүнү артык көрөт.

Аппараттык жабдыктарда маалыматтарды сактоо, виртуалдаштыруу жана резервдик көчүрүү гана калган.

Эгер сиз ZFSге көбүрөөк ишенсеңиз, анда, негизинен, көрсөтүлгөн колдонмо үчүн алар бири-бирин алмаштыра алышат.

Бирок, автор ZFS, BRTFS жана LVM ээ болгон камтылган чагылдыруу/RAID жана ашыкча мүмкүнчүлүктөрдү атайылап этибарга албайт.

Кошумча аргумент катары, BTRFS кокус жазууларды ырааттуу жазууларга айландыруу мүмкүнчүлүгүнө ээ, бул HDDдеги снапшотторду/камдык көчүрмөлөрдү синхрондоштуруунун ылдамдыгына абдан оң таасирин тийгизет.

Келгиле, бардык түзмөктөрдү кайра карап көрөлү:

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

Келгиле, айланага көз чаптыралы:

#lsscsi && nvme list
[0:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sda
[1:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdb
[2:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdc
[3:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdd
[4:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sde
[5:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdf
[6:0:0:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdg
[6:0:1:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdh
[6:0:2:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdi
[6:0:3:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdj
[6:0:4:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdk
[6:0:5:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdl
[6:0:6:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdm
[6:0:7:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdn
Node SN Model Namespace Usage Format FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1 S466NXXXXXXX15L Samsung SSD 970 EVO 500GB 1 0,00 GB / 500,11 GB 512 B + 0 B 2B2QEXE7
/dev/nvme1n1 S5H7NXXXXXXX48N Samsung SSD 970 EVO 500GB 1 0,00 GB / 500,11 GB 512 B + 0 B 2B2QEXE7

Дисктин жайгашуусу

NVMe SSD

Бирок биз аларды эч кандай белгилебейбиз. Баары бир, биздин BIOS бул дисктерди көрбөйт. Ошентип, алар толугу менен RAID программалык камсыздоосуна өтүшөт. Биз ал жерде бөлүмдөрдү да түзбөйбүз. Эгер сиз "канонду" же "негизинен" кармангыңыз келсе, HDD сыяктуу бир чоң бөлүмдү түзүңүз.

SATA HDD

Бул жерде өзгөчө эч нерсе ойлоп табуунун кереги жок. Биз бардыгы үчүн бир бөлүм түзөбүз. Биз бөлүм түзөбүз, анткени BIOS бул дисктерди көрүп, алардан жүктөөгө аракет кылышы мүмкүн. Система күтүлбөгөн жерден муну жасай алышы үчүн, биз кийинчерээк бул дисктерге GRUB орнотобуз.

#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

Бул жерде биз үчүн нерселер кызыктуу болот.

Биринчиден, биздин дисктердин көлөмү 2 ТБ. Бул MBR үчүн алгылыктуу диапазондо, аны биз колдонобуз. Зарыл болсо, GPT менен алмаштырылышы мүмкүн. GPT дисктеринде MBR шайкеш келген системалар биринчи 4 терабайттын ичинде жайгашкан болсо, биринчи 2 бөлүмдү көрүүгө мүмкүндүк берген шайкештик катмары бар. Эң негизгиси, бул дисктердеги жүктөө бөлүмү жана bios_grub бөлүмү башында болушу керек. Бул атүгүл GPT Legacy/BIOS дисктеринен жүктөөгө мүмкүндүк берет.

Бирок бул бизде эмес.

Бул жерде биз эки бөлүм түзөбүз. Биринчисинин көлөмү 1 ГБ болот жана RAID 1 / жүктөө үчүн колдонулат.

Экинчиси RAID 6 үчүн колдонулат жана дисктин аягындагы кичинекей бөлүштүрүлбөгөн жерден башка бардык бош орундарды ээлейт.

Бул белгиленбеген аймак деген эмне?Тармактагы булактарга ылайык, биздин SATA SSD дисктерибиздин бортунда көлөмү 6дан 78 гигабайтка чейинки динамикалык түрдө кеңейүүчү SLC кэши бар. Дисктин маалымат баракчасындагы "гигабайттар" менен "гибибайттардын" айырмасынан улам 6 гигабайтты "акысыз" алабыз. Калган 72 гигабайт пайдаланылбаган мейкиндиктен бөлүнгөн.

Бул жерде биз SLC кэши бар экенин белгилей кетүү керек, ал эми орун 4 бит MLC режиминде ээлейт. Бул биз үчүн натыйжалуу ар бир 4 гигабайт бош орун үчүн биз SLC кэшинин 1 гигабайтын гана алабыз дегенди билдирет.

72 гигабайтты 4кө көбөйтүңүз жана 288 гигабайт алыңыз. Бул дисктерге SLC кэшин толук колдонууга уруксат берүү үчүн биз белгилебей турган бош мейкиндик.

Ошентип, биз жалпысынан алты дисктен 312 гигабайт SLC кэшин натыйжалуу алабыз. Бардык дисктердин ичинен 2 RAIDде ашыкча болуу үчүн колдонулат.

Кэштин бул көлөмү чыныгы жашоодо жазуу кэшке кирбей калган жагдайга сейрек кездешүүгө мүмкүндүк берет. Бул QLC эс тутумунун эң кейиштүү кемчилигин абдан жакшы компенсациялайт - маалыматтар кэшти айланып жазылганда жазуу ылдамдыгы өтө төмөн. Эгерде сиздин жүктөрүңүз буга дал келбесе, анда мен сизге маалымат баракчасындагы TBWди эске алуу менен SSD мындай жүктүн астында канча убакытка чейин чыдай тургандыгы жөнүндө ойлонуп көрүүнү сунуштайм.

#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

Массивдерди түзүү

Биринчиден, биз машинанын атын өзгөртүү керек. Бул зарыл, анткени хосттун аталышы mdadm ичиндеги бир жерде массивдин аталышынын бир бөлүгү болуп саналат жана кандайдыр бир жерге таасир этет. Албетте, массивдердин атын кийинчерээк өзгөртүүгө болот, бирок бул керексиз кадам.

#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

Эмне үчүн -таза...?Массивдерди инициализациялоодон качуу үчүн. RAID 1 жана 6 деңгээли үчүн бул жарактуу. Эгер ал жаңы массив болсо, баары инициализациясыз иштей алат. Мындан тышкары, SSD массивин түзүү учурунда инициализациялоо TBW ресурсун ысырап кылат. Биз чогултулган SSD массивдеринде мүмкүн болсо TRIM/DISCARD колдонобуз, аларды "инициализациялоо" үчүн.

SSD массивдери үчүн RAID 1 DISCARD кутудан тышкары колдоого алынат.

SSD RAID 6 DISCARD массивдери үчүн сиз аны ядро ​​модулунун параметрлеринде иштетишиңиз керек.

Бул системанын 4/5/6 деңгээлиндеги массивдеринде колдонулган бардык SSD дисктери discard_zeroes_data үчүн жумушчу колдоосуна ээ болгондо гана жасалышы керек. Кээде сиз ядрого бул функция колдоого алынганын билдирген кызыктай дисктерди кезиктиресиз, бирок чындыгында ал жок, же функция дайыма эле иштебейт. Учурда колдоо дээрлик бардык жерде жеткиликтүү, бирок каталары бар эски дисктер жана микропрограммалар бар. Ушул себептен улам, RAID 6 үчүн демейки боюнча DISCARD колдоосу өчүрүлгөн.

Көңүл буруңуз, төмөнкү буйрук NVMe дисктериндеги бардык маалыматтарды "нөлдөр" менен массивди "инициализациялоо" менен жок кылат.

#blkdiscard /dev/md0

Бир нерсе туура эмес болсо, кадамды белгилеп көрүңүз.

#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

Эмнеге мынча чоң...?Бөлүмдүн көлөмүн көбөйтүү блоктордун көлөмүн камтыган блокторду кокус окуунун ылдамдыгына оң таасирин тийгизет. Бул тиешелүү өлчөмдөгү же андан кичирээк бир операцияны бир түзмөктө толугу менен бүтүрсө болот. Ошондуктан, бардык түзмөктөрдөн IOPS жыйынтыкталган. Статистика боюнча, IO 99% 512K ашпайт.

RAID ар бир жазууда 6 IOPS бар дайыма бир дисктин IOPSсынан аз же барабар. Качан, кокус окуу катары, IOPS бир дискке караганда бир нече эсе көп болушу мүмкүн жана бул жерде блоктун өлчөмү негизги мааниге ээ.
Автор RAID 6 дизайнында начар болгон параметрди оптималдаштырууга аракет кылуунун маанисин көрбөйт жана анын ордуна RAID 6 эмнени оптималдаштырат.
Биз RAID 6нын начар кокус жазуусунун ордун NVMe кэши жана жука провизиялоо ыкмалары менен толтурабыз.

Биз RAID 6 үчүн DISCARD функциясын иштете элекпиз. Андыктан биз бул массивди азырынча “башталбайбыз”. Биз муну кийинчерээк, OS орноткондон кийин жасайбыз.

SATA HDD

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

NVMe RAIDдеги LVM

Ылдамдык үчүн, биз тамыр файл тутумун NVMe RAID 1ге жайгаштыргыбыз келет, ал /dev/md0.
Бирок, бизге дагы эле бул тез массив алмашуу, метаберилиштер жана LVM-кэш жана LVM-жука метадайындар сыяктуу башка муктаждыктар үчүн керек болот, ошондуктан биз бул массивде LVM VG түзөбүз.

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

Келгиле, тамыр файл системасы үчүн бөлүм түзөлү.

#lvcreate -L 128G --name root root

Келгиле, оперативдик эстутумдун көлөмүнө жараша алмаштыруу үчүн бөлүм түзөлү.

#lvcreate -L 32G --name swap root

OS орнотуу

Жалпысынан алганда, биз системаны орнотуу үчүн зарыл болгон нерселердин баары бар.

Ubuntu Live чөйрөсүнөн системаны орнотуу устасын ишке киргизиңиз. Кадимки орнотуу. Орнотуу үчүн дисктерди тандоо стадиясында гана төмөнкүлөрдү көрсөтүү керек:

  • /dev/md1, - орнотуу чекити /жүктөө, FS - BTRFS
  • /dev/root/root (a.k.a /dev/mapper/root-root), - орнотуу чекити / (root), FS - BTRFS
  • /dev/root/swap (a.k.a /dev/mapper/root-swap), - алмашуу бөлүмү катары колдонуу
  • /dev/sda боюнча жүктөгүчтү орнотуңуз

BTRFSти тамыр файл системасы катары тандаганыңызда, орнотуучу автоматтык түрдө / (root) үчүн "@" жана /home үчүн "@home" деп аталган эки BTRFS томун түзөт.

Орнотууну баштайлы...

Орнотуу жүктөгүчтү орнотууда катаны көрсөткөн модалдык диалог терезеси менен аяктайт. Тилекке каршы, сиз стандарттуу каражаттар менен бул диалогдон чыгып, орнотууну уланта албайсыз. Биз системадан чыгып, кайра киребиз, таза Ubuntu Live иш тактасында болобуз. Терминалды ачып, кайра:

#sudo bash

Орнотууну улантуу үчүн chroot чөйрөсүн түзүңүз:

#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

Тармакты жана хосттун атын chrootто конфигурациялайлы:

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

Келгиле, chroot чөйрөсүнө баралы:

#chroot /mnt/chroot

Биринчиден, биз пакеттерди жеткиребиз:

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

Келгиле, тутумдун толук орнотулбагандыгынан улам кыйшык орнотулган бардык пакеттерди текшерип, оңдойлу:

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

Эгер бир нерсе болбой калса, алгач /etc/apt/sources.listти түзөтүшүңүз керек болот

TRIM/DISCARD иштетүү үчүн RAID 6 модулунун параметрлерин тууралайлы:

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

Келгиле, массивибизди бир аз чыңдайлы:

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

Бул эмне болчу..?Биз төмөндөгүлөрдү жасай турган udev эрежелеринин топтомун түздүк:

  • RAID 2020 үчүн блок кэшинин өлчөмүн 6-жылга адекваттуу кылып коюңуз. Демейки маани Linux түзүлгөндөн бери өзгөргөн жок жана көптөн бери адекваттуу болгон жок.
  • Массивдерди текшерүү/синхрондоштуруунун узактыгы үчүн минималдуу IO сактаңыз. Бул сиздин массивиңиздин жүк астында түбөлүк синхрондоштуруу абалына тыгылып калышын алдын алуу үчүн.
  • Массивдерди текшерүү/синхрондоштуруу учурунда максималдуу IOну чектөө. Бул SSD RAIDдерди синхрондоштуруу/текшерүү сиздин дисктериңизди катуу кууруу үчүн зарыл. Бул өзгөчө NVMe үчүн чыныгы болуп саналат. (Радиатор жөнүндө эсиңиздеби? Мен тамашалаган жокмун.)
  • APM аркылуу дисктерге шпиндельдин айлануусун (HDD) токтотууга тыюу салыңыз жана диск контроллерлору үчүн 7 саатка уйку күтүү убактысын коюңуз. Эгер дисктериңиз муну жасай алса, сиз APMди толугу менен өчүрө аласыз (-B 255). Демейки мааниде, дисктер беш секунддан кийин токтойт. Андан кийин OS дисктин кэшин баштапкы абалга келтирүүнү каалайт, дисктер кайра айланып, баары кайра башталат. Дисктерде шпиндель айланууларынын чектелген саны бар. Мындай жөнөкөй демейки цикл бир нече жылдын ичинде дисктериңизди оңой эле өлтүрүп коюшу мүмкүн. Бардык дисктер мындан жапа чекпейт, бирок биздики "ноутбуктар" болуп саналат, алар тиешелүү демейки жөндөөлөрү менен RAIDди мини-МАИДге окшош кылат.
  • Дисктерге окууну алдын ала орнотуу (айлануучу) 1 мегабайт - эки ырааттуу блок/бөлүгү RAID 6
  • Массивдердин өзүндө окууну өчүрүү.

/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

Эмнеге андай..?Биз UUID аркылуу / жүктөө бөлүмүн издейбиз. Массивдин аталышы теориялык жактан өзгөрүшү мүмкүн.

Калган бөлүмдөрдү /dev/mapper/vg-lv белгилөөсүндө LVM аттары боюнча издейбиз, анткени алар бөлүктөрүн уникалдуу түрдө аныкташат.

Биз LVM үчүн UUID колдонбойбуз, анткени LVM томдорунун UUIDи жана алардын сүрөттөрү бирдей болушу мүмкүн.Mount /dev/mapper/root-root.. эки жолу?Ооба. Дал ошондой. BTRFS өзгөчөлүгү. Бул файл системасы ар кандай subvols менен бир нече жолу орнотулган болот.

Ушул эле өзгөчөлүктөн улам, мен эч качан активдүү BTRFS томдорунун LVM сүрөтүн түзбөөнү сунуштайм. Кайра жүктөгөнүңүздө сюрприз аласыз.

mdadm конфигурациясын калыбына келтирели:

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

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

Бул эмне болчу..?Биз LVM жука бассейндеринин көлөмүнүн 90% ээлеген мейкиндигинин 5% жеткенде автоматтык түрдө кеңейтүүнү иштеттик.

LVM кэши үчүн кэш блокторунун максималдуу санын көбөйттүк.

Биз LVMге LVM көлөмүн (PV) издөөгө бөгөт койдук:

  • LVM кэши (cdata) камтыган түзмөктөр
  • кэшти айланып өтүп LVM кэши менен кэштелген түзмөктөр (_corig). Бул учурда, кэштелген түзмөктүн өзү дагы эле кэш аркылуу сканерленет (жөн гана ).
  • LVM кэш метадайындарын камтыган түзмөктөр (cmeta)
  • аты сүрөттөрү менен VG бардык түзмөктөр. Бул жерде бизде виртуалдык машиналардын диск сүрөттөрү болот жана биз хосттогу LVM конок ОСке тиешелүү көлөмдөрдү активдештирүүнү каалабайбыз.
  • аты камдык менен VG бардык түзмөктөр. Бул жерде биз виртуалдык машина сүрөттөрүнүн камдык көчүрмөлөрүн алабыз.
  • аты "gpv" менен аяктаган бардык түзмөктөр (коноктун физикалык көлөмү)

LVM VGде бош мейкиндикти бошотуп жатканда, биз ЖАКТЫРУУ колдоосун иштеттик. Абайла. Бул SSDдеги LVлерди жок кылууну бир топ убакытты талап кылат. Бул өзгөчө SSD RAID 6га тиешелүү. Бирок, планга ылайык, биз жука камсыздоону колдонобуз, андыктан бул бизге эч кандай тоскоолдук кылбайт.

initramfs сүрөтүн жаңырталы:

#update-initramfs -u -k all

Grub орнотуу жана конфигурациялоо:

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

Кайсы дисктерди тандоо керек?sd* болгондордун бардыгы. Система каалаган SATA дискинен же SSDден жүктөө мүмкүнчүлүгүнө ээ болушу керек.

Эмнеге ос-проберди кошушту..?Ашыкча көз карандысыздык жана ойноок колдор үчүн.

RAIDдердин бири бузулган абалда болсо, ал туура иштебейт. Бул аппараттык жабдыкта иштеген виртуалдык машиналарда колдонулган бөлүмдөрдөн ОСти издөөгө аракет кылат.

Эгер сизге керек болсо, аны таштап койсоңуз болот, бирок жогоруда айтылгандардын баарын эстен чыгарбаңыз. Мен интернеттен тентек колдордон арылуу үчүн рецепттерди издөөнү сунуштайм.

Муну менен биз алгачкы орнотууну аяктадык. Жаңы орнотулган ОСке кайра жүктөө убактысы келди. Жүктөлүүчү Live CD/USBди алып салууну унутпаңыз.

#exit
#reboot

Жүктөөчү түзүлүш катары SATA SSD дисктеринин каалаганын тандаңыз.

SATA SSDдеги LVM

Бул учурда, биз жаңы ОСке жүктөлүп, тармакты конфигурациялап, терминалдык эмуляторду ачып, ишке киргиздик:

#sudo bash

Келиңиз.

SATA SSDден массивди "инициализациялоо":

#blkdiscard /dev/md2

Эгер ал иштебесе, анда аракет кылыңыз:

#blkdiscard --step 65536 /dev/md2
SATA SSDде LVM VG түзүңүз:

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

Эмне үчүн башка VG..?Чынында, бизде тамыр деп аталган VG бар. Эмне үчүн баарын бир VGге кошпойт?

Эгерде VGде бир нече PV бар болсо, анда VG туура иштетилиши үчүн, бардык PVлор (онлайн) болушу керек. LVM RAID өзгөчөлүгү болуп саналат, биз аны атайылап колдонбойбуз.

Биз чындап эле RAID 6 массивдеринин биринде ката (окуу маалыматтарын жоготуу) болсо, операциялык система кадимкидей жүктөлүп, көйгөйдү чечүүгө мүмкүнчүлүк беришин каалайбыз.

Бул үчүн, абстракциянын биринчи деңгээлинде биз ар бир физикалык “медианы” өзүнчө VGге бөлүп алабыз.

Илимий жактан алганда, ар кандай RAID массивдери ар кандай "ишенимдүүлүк домендерине" таандык. Аларды бир VGге жыйыштырып, алар үчүн кошумча жалпы ийгиликсиз чекитти түзбөшүңүз керек.

LVMдин “аппараттык” деңгээлинде болушу ар кандай жолдор менен айкалыштыруу менен ар кандай RAID массивдеринин бөлүктөрүн өзүм билемдик менен кесип алууга мүмкүндүк берет. Мисалы - чуркап бир эле учурда bcache + LVM thin, bcache + BTRFS, LVM кэш + LVM thin, кэштери бар татаал ZFS конфигурациясы же бардыгын салыштыруу үчүн башка тозок аралашмасы.

"Аппараттык камсыздоо" деңгээлинде биз жакшы эски "калың" LVM көлөмүнөн башка эч нерсени колдонбойбуз. Бул эрежеден өзгөчө резервдик бөлүм болушу мүмкүн.

Менин оюмча, ушул тапта көптөгөн окурмандар уя салган куурчак жөнүндө бир нерседен шектене башташты.

SATA HDDдеги LVM

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

Кайрадан жаңы VG..?Эгерде биз маалыматтардын камдык көчүрмөсүн сактоо үчүн колдоно турган диск массиви иштебей калса, биздин операциялык системабыз кадимкидей иштөөсүн жана камдык көчүрмөсү жок маалыматтарга адаттагыдай эле кирүү мүмкүнчүлүгүн сактап турушун чындап каалайбыз. Ошондуктан, VG активдештирүү көйгөйлөрүн болтурбоо үчүн, биз өзүнчө VG түзөбүз.

LVM кэши орнотулууда

Келгиле, NVMe RAID 1де LV түзөлү, аны кэштөө аппараты катары колдонолу.

#lvcreate -L 70871154688B --name cache root

Эмнеге мынча аз...?Чынында, биздин NVMe SSDтерде SLC кэш бар. 4 гигабайт "акысыз" жана 18 гигабайт динамикалык 3 биттик MLCде бош орун ээлегендиктен. Бул кэш түгөнүп калгандан кийин, NVMe SSD'лери кэш менен SATA SSDге караганда тезирээк болбойт. Чындыгында, ушул себептен LVM кэш бөлүгүн NVMe дискинин SLC кэшинин өлчөмүнөн эки эсе чоңураак кылуунун мааниси жок. Колдонулган NVMe дисктери үчүн автор 32-64 гигабайт кэш жасоону акылга сыярлык деп эсептейт.

Берилген бөлүмдүн өлчөмү 64 гигабайт кэш, кэш метадайындары жана метаберилиштердин камдык көчүрмөсүн уюштуруу үчүн талап кылынат.

Кошумчалай кетчү нерсе, кир система жабылгандан кийин, LVM бүт кэшти кир деп белгилеп, кайра синхрондоштурууну белгилейт. Мындан тышкары, бул аппарат кайра жүктөлмөйүнчө, бул түзмөктө lvchange колдонулган сайын кайталанат. Ошондуктан, мен тиешелүү скрипт менен кэшти дароо кайра түзүүнү сунуштайм.

Аны кэштелген түзмөк катары колдонуу үчүн SATA RAID 6да LV түзөлү.

#lvcreate -L 3298543271936B --name cache data

Эмне үчүн үч гана терабайт..?Ошентип, зарыл болсо, SATA SSD RAID 6 башка муктаждыктар үчүн колдоно аласыз. Кэштелген мейкиндиктин көлөмүн системаны токтотпостон, динамикалык түрдө көбөйтүүгө болот. Бул үчүн, сиз убактылуу токтотуп, кэшти кайра иштетишиңиз керек, бирок LVM-кэштин айырмалоочу артыкчылыгы, мисалы, bcache, муну тез эле жасоого болот.

Кэштөө үчүн жаңы VG түзөлү.

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

Келгиле, кэштелген түзмөктө LV түзөлү.

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

Бул жерде биз дароо /dev/data/cache'деги бардык бош мейкиндикти алдык, андыктан башка бардык керектүү бөлүмдөр дароо /dev/root/cacheте түзүлдү. Эгер сиз туура эмес жерде бир нерсени жараткан болсоңуз, аны pvmove аркылуу жылдырсаңыз болот.

Кэшти түзүп, иштетели:

#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

Эмне үчүн мындай чоңдуктар..?Практикалык эксперименттер аркылуу автор LVM кэш блогунун өлчөмү LVM жука блогунун өлчөмү менен дал келсе, эң жакшы натыйжага жетээрин таба алган. Анын үстүнө, өлчөмү кичине болсо, конфигурация кокус жазууда ошончолук жакшыраак иштейт.

64k LVM ичке үчүн уруксат берилген минималдуу блок өлчөмү болуп саналат.

Абайлагыла кайра жазгыла..!Ооба. Кэштин бул түрү кэштелген түзмөккө жазуу синхрондоштурууну кийинкиге калтырат. Бул кэш жоголсо, кэштелген түзмөктөгү маалыматтарды жоготуп алышыңыз мүмкүн дегенди билдирет. Кийинчерээк, автор NVMe RAID 1ден тышкары, бул тобокелдиктин ордун толтуруу үчүн кандай чаралар көрүлсө болорун айтып берет.

Бул кэш түрү RAID 6нын туш келди жазуу көрсөткүчүнүн ордун толтуруу үчүн атайылап тандалган.

Бизде эмне бар экенин текшерип көрөлү:

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

Бир гана [cachedata_corig] /dev/data/cache'де жайгашышы керек. Эгер бир нерсе туура эмес болсо, анда pvmove колдонуңуз.

Керек болсо, бир буйрук менен кэшти өчүрө аласыз:

#lvconvert -y --uncache cache/cachedata

Бул онлайн жасалат. LVM жөн гана кэшти дискке синхрондотуп, аны алып салып, cachedata_corig атын кайра кэш маалыматтарына өзгөртөт.

LVM жука орнотуу

LVM ичке метадайындары үчүн бизге канча орун керек экенин болжол менен эсептеп көрөлү:

#thin_metadata_size --block-size=64k --pool-size=6terabytes --max-thins=100000 -u bytes
thin_metadata_size - 3385794560 bytes estimated metadata area size for "--block-size=64kibibytes --pool-size=6terabytes --max-thins=100000"

4 гигабайтка чейин тегеректөө: 4294967296B

Экиге көбөйтүңүз жана LVM PV метадайындары үчүн 4194304B кошуңуз: 8594128896B
Келгиле, NVMe RAID 1де LVM ичке метадайындарын жана алардын резервдик көчүрмөсүн жайгаштыруу үчүн өзүнчө бөлүм түзөлү:

#lvcreate -L 8594128896B --name images root

Эмне үчүн..?Бул жерде суроо туулат: эмне үчүн LVM ичке метадайындарын өзүнчө жайгаштыруу керек, эгерде ал дагы эле NVMeде кэштелип, тез иштей турган болсо.

Бул жерде ылдамдык маанилүү болгону менен, бул негизги себептен алыс. Кеп нерсе, кэш ийгиликсиздик чекити болуп саналат. Ага бир нерсе болушу мүмкүн жана LVM ичке метаберилиштери кэштелген болсо, анда бардыгы толугу менен жоголуп кетет. Толук метадайындарсыз жука көлөмдөрдү чогултуу дээрлик мүмкүн эмес.

Метаберилиштерди өзүнчө кэштелбеген, бирок тез көлөмгө жылдыруу менен биз кэш жоголгон же бузулган учурда метадайындардын коопсуздугуна кепилдик беребиз. Бул учурда, кэш жоготуудан келип чыккан бардык зыян жука көлөмдө локализацияланат, бул калыбына келтирүү процедурасын чоңдуктун тартиби менен жөнөкөйлөтөт. Жогорку ыктымалдуулук менен, бул зыяндар FS журналдарын колдонуу менен калыбына келтирилет.

Мындан тышкары, эгерде мурда ичке көлөмдүн сүрөтү тартылып, андан кийин кэш жок дегенде бир жолу толук синхрондолуп калса, анда LVM thinдин ички дизайнына байланыштуу, кэш жоголгон учурда сүрөттүн бүтүндүгү кепилденет. .

Келгиле, жука камсыздоого жооп бере турган жаңы VG түзөлү:

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

Келгиле, бассейн түзөлү:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Эмне үчүн -З жБул режим иш жүзүндө эмне үчүн арналганынан тышкары - мейкиндикти кайра бөлүштүрүү учурунда бир виртуалдык машинадан берилиштердин башка виртуалдык машинага агып кетишине жол бербөө үчүн - нөлдөө кошумча түрдө 64к кичирээк блокторго туш келди жазуу ылдамдыгын жогорулатуу үчүн колдонулат. Жука көлөмдүн мурда бөлүштүрүлбөгөн аймагына 64к азыраак жазуу кэште 64K четине тегизделген болуп калат. Бул операцияны кэштелген аппаратты айланып өтүү менен толугу менен кэш аркылуу аткарууга мүмкүндүк берет.

Келгиле, LVларды тиешелүү 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

текшерип көрөлү:

#lvs -a -o lv_name,lv_size,devices --units B images
LV LSize Devices
[lvol0_pmspare] 4294967296B /dev/root/images(0)
thin-pool 274877906944B thin-pool_tdata(0)
[thin-pool_tdata] 274877906944B /dev/cache/cachedata(0)
[thin-pool_tmeta] 4294967296B /dev/root/images(1024)

Сыноолор үчүн жука көлөм түзөлү:

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

Тесттер жана мониторинг үчүн пакеттерди орнотобуз:

#apt-get install sysstat fio

Реалдуу убакытта сактагыч конфигурациябыздын жүрүм-турумун мына ушундайча байкай аласыз:

#watch 'lvs --rows --reportformat basic --quiet -ocache_dirty_blocks,cache_settings cache/cachedata && (lvdisplay cache/cachedata | grep Cache) && (sar -p -d 2 1 | grep -E "sd|nvme|DEV|md1|md2|md3|md0" | grep -v Average | sort)'

Бул биздин конфигурацияны сынай алабыз:

#fio --loops=1 --size=64G --runtime=4 --filename=/dev/images/test --stonewall --ioengine=libaio --direct=1
--name=4kQD32read --bs=4k --iodepth=32 --rw=randread
--name=8kQD32read --bs=8k --iodepth=32 --rw=randread
--name=16kQD32read --bs=16k --iodepth=32 --rw=randread
--name=32KQD32read --bs=32k --iodepth=32 --rw=randread
--name=64KQD32read --bs=64k --iodepth=32 --rw=randread
--name=128KQD32read --bs=128k --iodepth=32 --rw=randread
--name=256KQD32read --bs=256k --iodepth=32 --rw=randread
--name=512KQD32read --bs=512k --iodepth=32 --rw=randread
--name=4Kread --bs=4k --rw=read
--name=8Kread --bs=8k --rw=read
--name=16Kread --bs=16k --rw=read
--name=32Kread --bs=32k --rw=read
--name=64Kread --bs=64k --rw=read
--name=128Kread --bs=128k --rw=read
--name=256Kread --bs=256k --rw=read
--name=512Kread --bs=512k --rw=read
--name=Seqread --bs=1m --rw=read
--name=Longread --bs=8m --rw=read
--name=Longwrite --bs=8m --rw=write
--name=Seqwrite --bs=1m --rw=write
--name=512Kwrite --bs=512k --rw=write
--name=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

Абайлаңыз! Ресурс!Бул код ар бири 36 секунддан турган 4 түрдүү тестти аткарат. Тесттердин жарымы жаздырууга арналган. NVMeде 4 секунданын ичинде көп нерсени жаза аласыз. секундасына 3 гигабайтка чейин. Ошентип, ар бир жазуу тесттери сизден 216 гигабайтка чейин SSD ресурсун жей алат.

Окуу менен жазуу аралашып жатабы?Ооба. Окуу жана жазуу тесттерин өзүнчө жүргүзүү мааниси бар. Мындан тышкары, мурда жасалган жазуу окууга таасирин тийгизбеши үчүн, бардык кэштер синхрондоштурууну камсыз кылуу мааниси бар.

Натыйжалар биринчи ишке киргизүүдө жана андан кийинкилерде абдан өзгөрүп турат, анткени кэш жана ичке көлөм толгондо, ошондой эле система акыркы ишке киргизүүдө толтурулган кэштерди синхрондоштурууга жетишкен-жетпесине жараша болот.

Башка нерселердин арасында мен ылдамдыкты жаңы эле тартылган толук ичке көлөмдө өлчөөнү сунуштайм. Автор кокус жазуулар биринчи сүрөттү түзгөндөн кийин, өзгөчө кэш али толук толо элек кезде кандайча кескин ылдамдагандыгын байкоого мүмкүнчүлүгүнө ээ болгон. Бул жазууга көчүрүү семантикасына, кэш жана ичке көлөм блокторуна тегиздөө жана RAID 6га туш келди жазуу RAID 6дан туш келди окууга, андан кийин кэшке жазууга айланып кетишинен улам болот. Биздин конфигурацияда RAID 6дан туш келди окуу жазууга караганда 6 эсеге (массивдеги SATA SSDлердин саны) тезирээк. Анткени CoW үчүн блоктор жука бассейнден ырааттуу түрдө бөлүнөт, андан кийин жазуу, көбүнчө, ырааттуу болуп калат.

Бул эки өзгөчөлүк тең сиздин пайдаңыз үчүн колдонулушу мүмкүн.

"Когеренттүү" сүрөттөрдү кэш

Кэш бузулган/жоголгон учурда маалыматтардын жоголуу коркунучун азайтуу үчүн автор бул учурда алардын бүтүндүгүн кепилдөө үчүн снапшотторду айлантуунун практикасын киргизүүнү сунуштайт.

Биринчиден, ичке көлөмдөгү метаберилиштер кэштелбеген түзмөктө жайгашкандыктан, метаберилиштер ырааттуу болот жана мүмкүн болгон жоготуулар маалымат блокторунун ичинде изоляцияланат.

Төмөнкү көз ирмемдик айлануу цикли кэш жоголгон учурда сүрөттөрдүн ичиндеги маалыматтардын бүтүндүгүн кепилдейт:

  1. деген ар бир жука көлөм үчүн .cached деген ат менен сүрөттү түзүңүз
  2. Миграция босогосун акылга сыярлык жогорку мааниге коёлу: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Циклде биз кэштеги кир блоктордун санын текшеребиз: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' биз нөлгө жеткенге чейин. Эгерде нөл өтө көпкө жок болсо, аны кэшти убактылуу жазуу режимине которуу аркылуу түзсө болот. Бирок, биздин SATA жана NVMe SSD массивдерибиздин ылдамдык мүнөздөмөлөрүн, ошондой эле алардын TBW ресурсун эске алуу менен, сиз же кэш режимин өзгөртпөстөн эле учурду тез кармай аласыз, же сиздин аппараттык камсыздооңуз анын бардык ресурсун толугу менен жеп салат. бир нече күн. Ресурстук чектөөлөрдөн улам, система, негизинен, 100% жазуу жүгүн ар дайым аткара албайт. Биздин NVMe SSD'лерибиз 100% жазуу жүгү менен ресурсту толугу менен түгөтөт 3-4 күн. SATA SSDs эки эсе гана узакка созулат. Ошондуктан, биз жүктүн көбү окууга кетет деп ойлойбуз жана бизде салыштырмалуу кыска мөөнөттүү өтө жогорку активдүүлүк жана жазуу үчүн орточо жүктөө аз.
  4. Биз нөлдү кармаарыбыз менен (же түзөөрүбүз менен) .cached атын .committed деп өзгөртөбүз. Жасалган эски жок кылынат.
  5. Каалоо боюнча, кэш 100% толуп калса, аны скрипт аркылуу кайра түзсө болот, ошентип аны тазалайт. Жарым бош кэш менен система жазууда тезирээк иштейт.
  6. Миграция босогосун нөлгө коюңуз: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Бул кэштин негизги медиага синхрондоштуруусуна убактылуу бөгөт коёт.
  7. Кэште бир топ өзгөрүүлөр топтолгуча күтөбүз #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' же таймер өчүп калат.
  8. Дагы кайталайбыз.

Эмне үчүн миграция босогосу менен кыйынчылыктар...?нерсе чыныгы иш жүзүндө, "кокустук" жазуу иш жүзүндө толугу менен кокустук эмес. Эгерде биз 4 килобайт көлөмүндөгү секторго бир нерсе жазган болсок, жакынкы эки мүнөттүн ичинде ошол эле же коңшу (+- 32К) секторлордун бирине рекорд коюлуп калышы ыктымал.

Миграция босогосун нөлгө коюу менен, биз SATA SSDдеги жазуу синхрондоштурууну кийинкиге калтырабыз жана кэштеги бир 64K блокко бир нече өзгөртүүлөрдү бириктиребиз. Бул SATA SSD ресурсун олуттуу үнөмдөйт.

Код кайда..?Тилекке каршы, автор өзүн 100% өз алдынча үйрөнгөн жана "google" аркылуу иштеп чыгууну практикалагандыктан, баш сценарийлерин иштеп чыгууда өзүн жетишсиз деп эсептейт, ошондуктан анын колунан чыккан коркунучтуу кодду эч ким колдонбошу керек деп эсептейт. башка.

Менимче, бул тармактын адистери, керек болсо, жогоруда сүрөттөлгөн бардык логиканы өз алдынча элестете алышат жана, балким, автор аракет кылгандай, аны системалуу кызмат катары кооздой алышат.

Мындай жөнөкөй көз ирмемдик айлануу схемасы бизге дайыма SATA SSDде толук синхрондоштурулган бир сүрөттү гана эмес, ошондой эле thin_delta утилитасын колдонуу менен, ал түзүлгөндөн кийин кайсы блоктор өзгөртүлгөнүн билип, зыянды локалдаштырууга мүмкүндүк берет. калыбына келтирүү абдан жөнөкөйлөштүрүүчү негизги көлөмү .

libvirt/KVMде ТҮШҮРҮҮ/ЖОК

Анткени маалымат сактагычы libvirt иштеткен KVM үчүн колдонулат, анда биздин VMлерди бош мейкиндикти гана ээлеп тим болбостон, керексиз нерселерди бошотууну да үйрөтсөк жакшы болмок.

Бул виртуалдык дисктерде TRIM/DISCARD колдоосун эмуляциялоо аркылуу жасалат. Бул үчүн сиз контроллердин түрүн virtio-scsiге өзгөртүп, 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>

Конок OS'лериндеги мындай ЖОКТООЛОР LVM тарабынан туура иштетилет жана блоктор кэште да, жука бассейнде да туура бошотулат. Биздин учурда, бул кийинки сүрөттү жок кылууда, негизинен, кечиктирилген түрдө болот.

BTRFS камдык көчүрмөсү

менен даяр скрипттерди колдонуңуз экстремалдуу сак жана өз тобокелине. Автор бул кодду өзү жана өзү үчүн гана жазган. Мен көптөгөн тажрыйбалуу Linux колдонуучуларынын окшош куралдары бар экенине ишенем жана башка бирөөнүн куралдарын көчүрүүнүн кереги жок.

Камдык түзмөктө көлөм түзөлү:

#lvcreate -L 256G --name backup backup

Келгиле, аны BTRFSде форматтайлы:

#mkfs.btrfs /dev/backup/backup

Келгиле, монтаждоо чекиттерин түзөлү жана файл тутумунун түпкү бөлүмдөрүн монтаждайлы:

#mkdir /backup
#mkdir /backup/btrfs
#mkdir /backup/btrfs/root
#mkdir /backup/btrfs/back
#ln -s /boot /backup/btrfs
# cat >>/etc/fstab << EOF

/dev/mapper/root-root /backup/btrfs/root btrfs defaults,space_cache,noatime,nodiratime 0 2
/dev/mapper/backup-backup /backup/btrfs/back btrfs defaults,space_cache,noatime,nodiratime 0 2
EOF
#mount -a
#update-initramfs -u
#update-grub

Камдык көчүрмөлөр үчүн каталогдорду түзөлү:

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

Келгиле, резервдик скрипттер үчүн каталог түзөлү:

#mkdir /root/btrfs-backup

Сценарийди көчүрөлү:

Көптөгөн коркунучтуу баш коду. Өзүңүздүн тобокелиңиз менен колдонуңуз. Авторго ачууланып кат жазбаңыз...#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

Ал эмне кылат..?BTRFS сүрөтүн түзүү жана BTRFS жөнөтүү/кабыл алуу аркылуу башка FSге көчүрүү үчүн жөнөкөй буйруктардын топтомун камтыйт.

Биринчи учуруу салыштырмалуу узак болушу мүмкүн, анткени... Башында, бардык маалыматтар көчүрүлөт. Андан ары ишке киргизүү абдан тез болот, анткени... Өзгөртүүлөр гана көчүрүлөт.

Биз cron киргизе турган дагы бир скрипт:

Дагы бир нече bash коду#cat >/root/btrfs-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

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

BACKUP_SCRIPT="$SCRIPT_DIR/btrfs-backup.sh"
RETENTION="-60 day"
$BACKUP_SCRIPT backup root/@
$BACKUP_SCRIPT removeall root/@ "$RETENTION"
$BACKUP_SCRIPT backup root/@home
$BACKUP_SCRIPT removeall root/@home "$RETENTION"
$BACKUP_SCRIPT backup boot/
$BACKUP_SCRIPT removeall boot/ "$RETENTION"
EOF

Эмне кылат..?Камдык FS боюнча тизмеленген BTRFS томдорунун кошумча сүрөттөрүн түзөт жана синхрондошот. Андан кийин, ал 60 күн мурун түзүлгөн бардык сүрөттөрдү жок кылат. Ишке киргизгенден кийин, /backup/btrfs/back/remote/ подкаталогдорунда тизмеленген томдордун даталуу сүрөттөрү пайда болот.

Келгиле, кодду аткаруу укуктарын берели:

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

Келгиле, аны текшерип, кронго салалы:

#/usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/btrfs-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t btrfs-backup
#cat /var/log/syslog | grep btrfs-backup
#crontab -e
0 2 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/btrfs-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t btrfs-backup

LVM ичке камдык көчүрмөсү

Камдык түзмөктө жука бассейн түзөлү:

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

ddrescue орнотобуз, анткени... скрипттер бул куралды колдонот:

#apt-get install gddrescue

Скрипттер үчүн каталог түзөлү:

#mkdir /root/lvm-thin-backup

Скрипттерди көчүрөлү:

Ичинде көп балээ...#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

Ал эмне кылат...?Жука көз ирмемдерди манипуляциялоо жана thin_delta аркылуу алынган эки ичке сүрөттүн ортосундагы айырманы ddrescue жана blkdiscard аркылуу башка блок түзмөгүнө синхрондоштуруу үчүн буйруктардын топтомун камтыйт.

Биз cron киргизе турган дагы бир скрипт:

Дагы бир аз баш#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

Ал эмне кылат...?Сандалган жука томдордун камдык көчүрмөлөрүн түзүү жана синхрондоштуруу үчүн мурунку сценарийди колдонот. Скрипт акыркы синхрондоштуруудан кийинки өзгөрүүлөргө көз салуу үчүн зарыл болгон тизмеленген томдордун жигердүү эмес сүрөттөрүн калтырат.

Бул скрипт камдык көчүрмөлөрү жасалышы керек болгон жука томдордун тизмесин көрсөтүү менен редакцияланышы керек. Берилген ысымдар иллюстрация үчүн гана. Кааласаңыз, бардык томдорду синхрондоштуруучу сценарий жаза аласыз.

Укуктарды берели:

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

Келгиле, аны текшерип, кронго салалы:

#/usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/lvm-thin-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t lvm-thin-backup
#cat /var/log/syslog | grep lvm-thin-backup
#crontab -e
0 3 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/lvm-thin-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t lvm-thin-backup

Биринчи учуруу узакка созулат, анткени... ичке томдор бардык колдонулган мейкиндикти көчүрүү менен толугу менен синхрондолот. LVM ичке метаберилиштеринин аркасында биз кайсы блоктор иш жүзүндө колдонулуп жатканын билебиз, андыктан иш жүзүндө колдонулган ичке көлөмдүү блоктор гана көчүрүлөт.

Кийинки иштетүүлөр LVM ичке метадайындары аркылуу көз салууну өзгөртүүнүн аркасында маалыматтарды акырындык менен көчүрөт.

Келгиле, эмне болгонун карап көрөлү:

#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

Мунун куурчактарга эмне тиешеси бар?

Кыязы, LVM LV логикалык томдору башка VG үчүн LVM PV физикалык томдору болушу мүмкүн экенин эске алганда. LVM куурчактары сыяктуу рекурсивдүү болушу мүмкүн. Бул LVMге өтө ийкемдүүлүктү берет.

PS

Кийинки макалада биз үй столдорун, үй Интернетин жана P2P тармактарын колдонуу менен бир нече континенттерде ашыкча гео-бөлүштүрүлгөн сактагыч/VM кластерин түзүү үчүн негиз катары бир нече окшош мобилдик сактоо тутумдарын/KVM колдонууга аракет кылабыз.

Source: www.habr.com

Комментарий кошуу