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 SSD дискілері.
  • Жазу ресурсы толығымен қолданылды және SSD дискілерінің істен шығуы.
  • Барлық дискілердегі барлық деректердің, соның ішінде сақтық көшірмелердің толық жоғалуы.
  • Ақаулы компьютерлік жабдық.
  • Уақыт, жүйке және ақша босқа кетті.
  • Жоғарыда аталмаған кез келген басқа салдар.

темір

Қол жетімді болды:

Intel Core i2013 / Haswell жиынтығымен толықтырылған Z87 чипсетімен шамамен 7 жылғы аналық плата.

  • Процессор 4 ядро, 8 ағын
  • 32 ГБ DDR3 жедел жады
  • 1 x 16 немесе 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 ГБ/с SATA 3 қосқыштары

SAS адаптері LSI SAS9211-8I IT / HBA режиміне жыпылықтайды. RAID қосылған микробағдарлама келесі мақсатта HBA микробағдарламасымен әдейі ауыстырылды:

  1. Бұл адаптерді кез келген уақытта лақтырып, оны кез келген басқасымен ауыстыруға болады.
  2. TRIM/Discard дискілерде қалыпты жұмыс істеді, себебі... RAID микробағдарламасында бұл пәрмендерге мүлде қолдау көрсетілмейді және HBA, жалпы алғанда, шина арқылы қандай пәрмендер жіберілетініне мән бермейді.

Қатты дискілер - ноутбуктер сияқты 8 форма факторында сыйымдылығы 7 ТБ HGST Travelstar 1000K1 2.5 дана. Бұл дискілер бұрын RAID 6 массивінде болған. Олардың да жаңа жүйеде қолданылуы болады. Жергілікті сақтық көшірмелерді сақтау үшін.

Қосымша қосылды:

6 дана SATA SSD моделі Samsung 860 QVO 2TB. Бұл SSD дискілері үлкен көлемді қажет етті, SLC кэшінің болуы, сенімділігі және төмен бағасы қажет болды. Жою/нөлге қолдау қажет болды, ол dmesg жолында тексеріледі:

kernel: ata1.00: Enabling discard_zeroes_data

NVMe SSD үлгісінің 2 дана 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 порттары бар. Бұл тірі ықшам дискі немесе жүктелетін флэш-диск сияқты, тек өте жылдам және сәл көлемді.

ӘзілӘйтпесе, сіз не болатынын білесіз - кейде алып кету үшін бүкіл массивді шұғыл түрде өзіңізбен бірге алып кетуіңіз керек. Бірақ мен деректерді жоғалтқым келмейді. Ол үшін барлық аталған тасымалдағыштар стандартты корпустың 5.25 ұяшықтарындағы слайдтарда ыңғайлы орналасқан.

Әрине, Linux жүйесінде SSD кэштеуінің әртүрлі әдістерімен тәжірибе жасау үшін.

Аппараттық рейдтер қызықсыз. Бұны қосыңызшы. Ол жұмыс істейді немесе жоқ. Және mdadm-мен әрқашан опциялар бар.

Бағдарламалық жасақтама

Бұрын Debian 8 Jessie EOL-ге жақын аппараттық құралға орнатылған болатын. RAID 6 жоғарыда аталған LVM-мен жұптастырылған HDD дискілерінен жиналған. Ол kvm/libvirt ішінде виртуалды машиналарды басқарды.

Өйткені Автордың портативті жүктелетін SATA/NVMe флэш-дискілерін жасауда лайықты тәжірибесі бар, сонымен қатар әдеттегі apt үлгісін бұзбау үшін мақсатты жүйе ретінде Ubuntu 18.04 таңдалды, ол жеткілікті тұрақтандырылған, бірақ әлі де 3 жыл жұмыс істейді. болашақта қолдау көрсету.

Аталған жүйе қораптан тыс қажет барлық аппараттық драйверлерді қамтиды. Бізге үшінші тарап бағдарламалық құралы немесе драйверлер қажет емес.

Орнатуға дайындық

Жүйені орнату үшін бізге Ubuntu Desktop Image керек. Сервер жүйесінде UEFI жүйесінің бөлімін дискілердің біріне басу арқылы өшіруге болмайтын шамадан тыс тәуелсіздікті көрсететін күшті орнатушы бар, бұл барлық сұлулықты бұзады. Тиісінше, ол тек UEFI режимінде орнатылады. Ешқандай опцияны ұсынбайды.

Бұған көңіліміз толмайды.

Неге?Өкінішке орай, UEFI жүктеуі RAID жүктеу бағдарламалық құралымен өте нашар үйлесімді, себебі... Ешкім бізге UEFI ESP бөліміне тапсырыс беруді ұсынбайды. Интернетте USB портындағы флэш-дискке ESP бөлімін орналастыруды ұсынатын рецепттер бар, бірақ бұл сәтсіздік нүктесі. 1 метадеректер нұсқасы бар mdadm RAID 0.9 бағдарламалық құралын пайдаланатын рецепттер бар, олар UEFI BIOS-қа бұл бөлімді көруге кедергі жасамайды, бірақ бұл BIOS немесе басқа аппараттық ОЖ ESP-ге бірдеңе жазып, оны басқалармен синхрондауды ұмытатын бақытты сәтке дейін өмір сүреді. айналар.

Сонымен қатар, UEFI жүктеу NVRAM-ге байланысты, ол дискілермен бірге жаңа жүйеге ауыспайды, себебі аналық платаның бөлігі болып табылады.

Сондықтан біз жаңа дөңгелекті ойлап таппаймыз. Бізде қазірдің өзінде UEFI-үйлесімді жүйелерде CSM деген мақтаныш атауын алған Legacy/BIOS жүктеу деп аталатын дайын, уақытпен тексерілген атаның велосипеді бар. Біз оны тек сөреден алып, оны майлап, шиналарды сорып, дымқыл шүберекпен сүртеміз.

Ubuntu жұмыс үстелі нұсқасын Legacy жүктеушімен дұрыс орнату мүмкін емес, бірақ мұнда, олар айтқандай, кем дегенде опциялар бар.

Осылайша, біз жабдықты жинап, жүйені Ubuntu Live жүктелетін флэш-дискінен жүктейміз. Біз пакеттерді жүктеп алуымыз керек, сондықтан сіз үшін жұмыс істейтін желіні орнатамыз. Егер ол жұмыс істемесе, қажетті бумаларды флэш-дискке алдын ала жүктей аласыз.

Біз жұмыс үстелі ортасына кіріп, терминал эмуляторын іске қосамыз және кетеміз:

#sudo bash

Қалай…?Жоғарыдағы жол судо туралы холиварларға арналған канондық триггер болып табылады. C боүлкен мүмкіндіктер келеді жәнеоүлкен жауапкершілік. Мәселе сіз оны өзіңізге ала аласыз ба. Көптеген адамдар sudo-ны осылай пайдалану, кем дегенде, абай емес деп ойлайды. Дегенмен:

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

Неге ZFS емес...?Компьютерімізге бағдарламалық құралды орнатқанда, біз негізінен осы бағдарламалық жасақтаманы әзірлеушілерге жүргізу үшін аппараттық құралымызды қарызға береміз.
Бұл бағдарламалық жасақтамаға деректеріміздің қауіпсіздігіне сенетін болсақ, біз бұл деректерді қалпына келтіру құнына тең несие аламыз, оны бір күні төлеуге тура келеді.

Осы тұрғыдан алғанда, ZFS - Ferrari, ал mdadm+lvm - бұл велосипедке көбірек ұқсайды.

Субъективті түрде автор Ferrari көлігінің орнына белгісіз тұлғаларға несиеге велосипед бергенді жөн көреді. Онда шығарылымның бағасы жоғары емес. Құқық қажет емес. Жол қозғалысы ережелерінен оңайырақ. Автотұрақ тегін. Елді аралау мүмкіндігі жақсырақ. Сіз әрқашан велосипедке аяқтарды бекіте аласыз және велосипедті өз қолыңызбен жөндеуге болады.

Неліктен BTRFS...?Амалдық жүйені жүктеу үшін бізге Legacy/BIOS GRUB жүйесінде қолдау көрсетілетін файлдық жүйе қажет және сонымен бірге тікелей суреттерді қолдайды. Біз оны /boot бөлімі үшін қолданамыз. Сонымен қатар, автор кез келген басқа бағдарламалық жасақтама үшін LVM-де бөлек бөлімдерді жасауға және оларды қажетті каталогтарға орнатуға болатынын есте сақтауды ұмытпай, осы FS-ді / (root) үшін пайдалануды жөн көреді.

Біз бұл FS-де виртуалды машиналар немесе дерекқорлардың ешбір кескінін сақтамаймыз.
Бұл 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 гигабайт бос орын үшін біз тек 1 гигабайт SLC кэшін аламыз дегенді білдіреді.

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 функциясын әлі қосқан жоқпыз. Сондықтан біз бұл массивті әзірше "инициализацияламаймыз". Біз мұны кейінірек ОЖ орнатқаннан кейін жасаймыз.

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

Жылдамдық үшін біз түбірлік файлдық жүйені /dev/md1 болатын NVMe RAID 0 жүйесіне орналастырғымыз келеді.
Дегенмен, своп, метадеректер және LVM-кэш және LVM-жұқа метадеректер сияқты басқа қажеттіліктер үшін бізге бұл жылдам массив әлі де қажет болады, сондықтан біз осы массивте LVM VG жасаймыз.

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

Түбірлік файлдық жүйе үшін бөлім жасайық.

#lvcreate -L 128G --name root root

ЖЖҚ көлеміне сәйкес свопинг бөлімін жасайық.

#lvcreate -L 32G --name swap root

ОЖ орнату

Жалпы алғанда, бізде жүйені орнатуға қажеттінің бәрі бар.

Ubuntu Live ортасынан жүйені орнату шеберін іске қосыңыз. Қалыпты орнату. Орнату үшін дискілерді таңдау кезеңінде ғана келесілерді көрсету керек:

  • /dev/md1, - орнату нүктесі /жүктеу, FS - BTRFS
  • /dev/root/root (aka /dev/mapper/root-root), - орнату нүктесі / (түбір), FS - BTRFS
  • /dev/root/swap (aka /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). Әдепкі мәнмен дискілер бес секундтан кейін тоқтайды. Содан кейін ОЖ дискінің кэшін қалпына келтіргісі келеді, дискілер қайтадан айналады және бәрі қайтадан басталады. Дискілерде шпиндельді айналдырудың шектеулі максималды саны бар. Мұндай қарапайым әдепкі цикл бірнеше жыл ішінде дискілерді оңай өлтіруі мүмкін. Бұдан барлық дискілер зардап шекпейді, бірақ біздікі «ноутбук» болып табылады, сәйкес әдепкі параметрлері бар, олар RAID-ті мини-MAID сияқты етеді.
  • Дискілерге алдын ала оқуды орнату (айналмалы) 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

Неге бұлай..?Біз /boot бөлімін UUID арқылы іздейміз. Массив атаулары теориялық түрде өзгеруі мүмкін.

Біз қалған бөлімдерді /dev/mapper/vg-lv белгілеуінде LVM атаулары бойынша іздейміз, себебі олар бөлімдерді ерекше анықтайды.

Біз LVM үшін UUID қолданбаймыз, себебі LVM томдарының UUID және олардың суреті бірдей болуы мүмкін.Mount /dev/mapper/root-root.. екі рет?Иә. Дәл солай. BTRFS ерекшелігі. Бұл файлдық жүйені әртүрлі субвольдермен бірнеше рет орнатуға болады.

Дәл осы мүмкіндіктің арқасында белсенді 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 жүйесінде бос орынды босату кезінде DISCARD қолдауын қостық. Сақ болыңыз. Бұл SSD дискісінде LV жоюды көп уақытты қажет етеді. Бұл әсіресе SSD RAID 6-ға қатысты. Дегенмен, жоспарға сәйкес біз жұқа провизияны қолданамыз, сондықтан бұл бізге мүлде кедергі болмайды.

Initramfs кескінін жаңартайық:

#update-initramfs -u -k all

Топты орнату және конфигурациялау:

#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-де бірнеше 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 thin үшін рұқсат етілген ең аз блок өлшемі.

Сақ болыңыз..!Иә. Кэштің бұл түрі кэштелген құрылғыға жазуды синхрондауды кейінге қалдырады. Бұл кэш жоғалса, кэштелген құрылғыдағы деректерді жоғалтуыңыз мүмкін дегенді білдіреді. Кейінірек автор бұл тәуекелді өтеу үшін 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)

/dev/data/cache ішінде тек [cachedata_corig] орналасуы керек. Егер бірдеңе дұрыс болмаса, 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

Не үшін..?Бұл жерде сұрақ туындауы мүмкін: егер ол әлі де NVMe-де кэштелген болса және тез жұмыс істейтін болса, LVM жұқа метадеректерін неге бөлек орналастыру керек.

Мұнда жылдамдық маңызды болғанымен, ол негізгі себептен алыс. Мәселе мынада, кэш сәтсіздік нүктесі болып табылады. Оған бірдеңе болуы мүмкін және 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 жиегі бойынша тураланған болады. Бұл операцияны кэштелген құрылғыны айналып өтіп, толығымен кэш арқылы орындауға мүмкіндік береді.

ЖҚ-ны сәйкес 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. <name> атты әрбір жұқа том үшін <name>.кэштелген атты суретті жасаңыз.
  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 SSD дискілері екі есе ұзақ қызмет етеді. Сондықтан, біз жүктеменің көп бөлігі оқуға кетеді деп болжаймыз және бізде жазу үшін орташа жүктемемен біріктірілген өте жоғары белсенділіктің салыстырмалы түрде қысқа мерзімді жарылыстары бар.
  4. Нөлді ұстаған (немесе жасаған) бойда біз <name>.cached атауын <name>.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-ге негізделген дамумен айналысатындықтан, bash сценарийлерін әзірлеуде өзін жеткіліксіз құзыретті деп санайды, сондықтан оның қолынан шыққан қорқынышты кодты ешкім пайдаланбауы керек деп санайды. басқа.

Менің ойымша, бұл саланың мамандары, қажет болса, жоғарыда сипатталған барлық логиканы өз бетінше бейнелей алады және, мүмкін, автор жасауға тырысқандай, оны жүйелік қызмет ретінде әдемі етіп жасай алады.

Мұндай қарапайым суретті айналдыру схемасы 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>

Қонақ операциялық жүйелерінің мұндай DISCARD файлдары 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

Сценарийді көшіріп алайық:

Көптеген қорқынышты bash коды. Өз тәуекеліңізбен пайдаланыңыз. Авторға ашулы хат жазбаңыз...#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

Ол не істейді...?Құрамында ddrescue және blkdiscard арқылы thin_delta арқылы алынған екі жұқа суреттің арасындағы айырмашылықты басқа блок құрылғысына синхрондауға және жұқа суреттерді өңдеуге арналған пәрмендер жиынтығы бар.

Біз 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 пайдалануға тырысамыз.

Ақпарат көзі: www.habr.com

пікір қалдыру