LVM və matryoshka arasında ortaq nə var?

Yaxşı gün.
Mən md RAID + LVM istifadə edərək KVM üçün saxlama sisteminin qurulmasında öz praktiki təcrübəmi cəmiyyətlə bölüşmək istəyirəm.

Proqramda:

  • NVMe SSD-dən md RAID 1 qurulması.
  • SATA SSD və adi disklərdən md RAID 6 qurmaq.
  • SSD RAID 1/6-da TRIM/DISCARD xüsusiyyətləri.
  • Paylaşılan disklər dəstində yüklənə bilən md RAID 1/6 massivinin yaradılması.
  • BIOS-da NVMe dəstəyi olmadıqda sistemin NVMe RAID 1-də quraşdırılması.
  • LVM önbelleği və LVM nazik istifadə.
  • BTRFS anlık görüntülərindən istifadə edin və ehtiyat nüsxə üçün göndərin/qəbul edin.
  • BTRFS stil ehtiyat nüsxələri üçün LVM nazik snapshots və thin_delta istifadə.

Əgər maraqlanırsınızsa, zəhmət olmasa pişik altında.

Bəyanat

Müəllif bu məqalədəki materiallardan/nümunələrdən/kodlardan/məsləhətlərdən/məlumatlardan istifadə və ya istifadə etməməyin nəticələrinə görə heç bir məsuliyyət daşımır. Bu materialı oxumaqla və ya hər hansı bir şəkildə istifadə etməklə siz bu hərəkətlərin bütün nəticələrinə görə məsuliyyət daşıyırsınız. Mümkün nəticələrə aşağıdakılar daxildir:

  • Xırtıldayan qızardılmış NVMe SSD-lər.
  • Tamamilə istehlak edilmiş yazma resursu və SSD sürücülərinin uğursuzluğu.
  • Ehtiyat nüsxələr də daxil olmaqla, bütün disklərdəki bütün məlumatların tam itirilməsi.
  • Səhv kompüter avadanlığı.
  • Boş yerə vaxt, əsəb və pul.
  • Yuxarıda sadalanmayan hər hansı digər nəticələr.

Dəmir

Mövcud idi:

Intel Core i2013 / Haswell ilə tamamlanan Z87 çipsetli 7-cü il ətrafında ana plata.

  • Prosessor 4 nüvə, 8 ip
  • 32 GB DDR3 RAM
  • 1 x 16 və ya 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 konnektorları

SAS adapteri LSI SAS9211-8I IT / HBA rejimində yandı. RAID-i aktivləşdirən mikroproqram aşağıdakıları etmək üçün qəsdən HBA proqram təminatına dəyişdirilib:

  1. İstənilən vaxt bu adapteri atıb ilk rast gəlinən digəri ilə əvəz etmək mümkün idi.
  2. TRIM/Discard disklərdə yaxşı işləyirdi, çünki RAID mikroproqramında bu əmrlər ümumiyyətlə dəstəklənmir və HBA, ümumiyyətlə, avtobusda hansı əmrlərin göndərilməsinə əhəmiyyət vermir.

Sərt disklər - 8 ədəd HGST Travelstar 7K1000 1 forma faktorunda 2.5 TB, noutbuklarda olduğu kimi. Bu disklər əvvəllər RAID 6 massivində idi. Yeni sistemdə onlar da tətbiq tapacaqlar. Yerli ehtiyat nüsxələrini saxlamaq üçün.

Əlavə olaraq əlavə edildi:

6 ədəd SATA SSD modeli Samsung 860 QVO 2TB. Bu SSD-lər böyük həcm, SLC önbelleğinin olması, etibarlılıq arzuolunandır və aşağı qiymət tələb edirdi. Dmesg-də sətirlə yoxlanılan discard/sıfırı dəstəkləmək məcburi idi:

kernel: ata1.00: Enabling discard_zeroes_data

2 ədəd NVMe SSD modeli Samsung SSD 970 EVO 500GB.

Bu SSD-lər üçün təsadüfi oxuma/yazma sürəti və ehtiyaclarınız üçün bir mənbə vacibdir. onlar üçün radiator. Mütləq. Tamamilə lazımdır. Əks halda, ilk RAIDa sinxronizasiyasında onları xırtıldayan qədər qızardın.

PCIe 8 2x yuvasında quraşdırılmış 2 x NVMe SSD üçün adapter StarTech PEX2M3.0E8. Bu, yenə də sadəcə HBA-dır, lakin NVMe üçün. İnteqrasiya edilmiş PCIe keçidinin olması səbəbindən anakartdan PCIe bifurkasiyasını dəstəkləmək tələbinin olmaması ilə ucuz adapterlərdən fərqlənir. Hətta x1 PCIe 1.0 yuvası olsa belə, PCIe olan ən qədim sistemdə işləyəcək. Təbii ki, uyğun sürətlə. RAID-lər yoxdur. Bortda quraşdırılmış BIOS yoxdur. Beləliklə, sisteminiz bu cihaz sayəsində NVMe RAID etməyi bir yana, NVMe-dən yükləməyi sehrli şəkildə öyrənməyəcək.

Bu komponent yalnız sistemdə yalnız bir pulsuz 8x PCIe 3.0 olması ilə əlaqədar idi və 2 pulsuz slot varsa, onu asanlıqla iki qəpiklik PEX4M2E1 və ya analoqları ilə əvəz etmək olar, hər yerdə 600 qiymətə almaq olar. rubl.

Bütün məlumatları saxlamaqla SSD / HDD istisna olmaqla, bütün sistemi tamamilə əvəz edə bilmək üçün hər cür avadanlıq və ya quraşdırılmış çipset / BIOS RAID-lərinin rədd edilməsi şüurlu şəkildə edildi. İdeal olaraq, tamamilə yeni / fərqli bir aparata keçərkən quraşdırılmış əməliyyat sistemini belə saxlaya bilərsiniz. Əsas odur ki, SATA və PCIe portları var. Bu, canlı CD və ya yüklənə bilən flash sürücü kimidir, yalnız çox sürətli və bir az həcmlidir.

YumorVə sonra, bunun necə baş verdiyini bilirsiniz - bəzən götürmək üçün təcili olaraq bütün massivi özünüzlə götürməlisiniz. Və məlumatlarınızı itirmək istəmirsiniz. Bunu etmək üçün, bütün qeyd olunan media standart qutunun 5.25 bölmələrində slaydda rahat şəkildə yerləşdirilir.

Yaxşı və əlbəttə ki, Linux-da SSD keşləməsinin müxtəlif yollarını sınaqdan keçirmək üçün.

Avadanlıq reydləri darıxdırıcıdır. Siz onu yandırın. Ya işləyir, ya da işləmir. Və mdadm ilə həmişə variantlar var.

Yumşaq

Əvvəllər Debian 8 Jessie EOL-a yaxın olan aparatda quraşdırılmışdı. RAID 6 yuxarıda göstərilən LVM ilə birləşdirilmiş HDD-lərdən yığılmışdır. O, kvm/libvirt-də virtual maşınları idarə edirdi.

Çünki müəllif portativ yüklənə bilən SATA / NVMe fləş sürücülərinin yaradılmasında uyğun təcrübəyə malikdir, həmçinin adi apt şablonunu cırmamaq üçün hədəf sistem olaraq Ubuntu 18.04 seçilmişdir, o, artıq kifayət qədər sabitləşib, lakin hələ də 3 ildir. gələcəkdə dəstək.

Qeyd olunan sistem qutudan kənarda bizə lazım olan bütün hardware sürücülərini ehtiva edir. Bizə heç bir üçüncü tərəf proqram təminatı və sürücülər lazım deyil.

Quraşdırmaya hazırlaşırıq

Sistemi quraşdırmaq üçün bizə Ubuntu Desktop Image lazımdır. Server sistemində həddindən artıq dəyişdirilə bilməyən müstəqillik göstərən, UEFI sistem bölməsini mütləq disklərdən birinə itələyərək bütün gözəlliyi korlayan bir növ güclü quraşdırıcı var. Müvafiq olaraq, yalnız UEFI rejimində quraşdırılır. Seçimlər təklif etmir.

Biz bununla kifayətlənmirik.

Niyə?Təəssüf ki, UEFI açılışı yüklənə bilən proqram təminatı RAID ilə son dərəcə uyğun deyil. heç kim bizə UEFI ESP bölməsi üçün rezervasiya təklif etmir. Şəbəkədə ESP bölməsini USB portunda bir flash sürücüyə yerləşdirməyi təklif edən reseptlər var, lakin bu, uğursuzluq nöqtəsidir. 1 metaməlumatlı mdadm RAID 0.9 proqram təminatından istifadə edən reseptlər var ki, onlar UEFI BIOS-un bu bölməni görməsinə mane olmur, lakin BIOS və ya başqa bir OS-nin digərləri ilə sinxronizasiya etməyi unudaraq ESP-yə nəsə yazdığı zaman o xoşbəxt an qədər yaşayır. güzgülər.

Bundan əlavə, UEFI açılışı NVRAM-dan asılıdır, disklərlə birlikdə yeni sistemə keçməyəcək, çünki. ana platanın bir hissəsidir.

Beləliklə, biz təkəri yenidən kəşf etməyəcəyik. Artıq illər ərzində sübut edilmiş, indi Legacy / BIOS açılışı adlanan, UEFI uyğun sistemlərdə CSM-nin qürurlu adını daşıyan hazır baba velosipedimiz var. Biz sadəcə rəfdən çıxarırıq, yağlayırıq, təkərləri pompalayırıq və nəm bir parça ilə silirik.

Ubuntu-nun masaüstü versiyası da Legacy bootloader ilə normal şəkildə necə qurulacağını bilmir, amma burada, necə deyərlər, heç olmasa seçimlər var.

Beləliklə, biz avadanlığı yığırıq və sistemi Ubuntu Live yüklənə bilən flash sürücüsündən yükləyirik. Paketləri endirməliyik, ona görə də qazandığınız şəbəkəni qurduq. Bu işləmirsə, lazımi paketləri əvvəlcədən USB flash sürücüsünə endirə bilərsiniz.

Desktop mühitinə daxil oluruq, terminal emulyatorunu işə salırıq və gedək:

#sudo bash

Necə…?Yuxarıdakı xətt kanonik sudo holivar tetikleyicisidir. C bоdaha çox imkanlar gəlir və bоdaha çox məsuliyyət. Sual budur ki, bunu özünüz götürə bilərsiniz. Bir çox insanlar sudo-dan bu şəkildə istifadə etməyin ən azı ehtiyatlı olmadığını düşünür. Lakin:

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

Niyə ZFS olmasın...?Proqram təminatını kompüterimizə quraşdırdığımız zaman, biz, mahiyyətcə, avadanlıqlarımızı həmin proqram təminatının tərtibatçılarına borc veririk.
Bu proqram təminatına məlumatlarımızın təhlükəsizliyinə güvəndiyimiz zaman bu məlumatların bərpası dəyərinə bərabər kredit götürürük və nə vaxtsa ödəməli olacağıq.

Bu baxımdan ZFS Ferraridir, mdadm+lvm isə daha çox velosipedə bənzəyir.

Müəllif subyektiv olaraq Ferrari əvəzinə naməlum şəxslərə borc götürülmüş velosiped verməyə üstünlük verir. Orada məsələnin qiyməti yüksək deyil. Hüquqlara ehtiyacınız yoxdur. Daha asan yol hərəkəti qaydaları. Parkinq pulsuzdur. Gəzinti daha yaxşıdır. Həmişə ayaqları velosipedə bağlaya bilərsiniz və öz əllərinizlə bir velosiped düzəldə bilərsiniz.

Bəs niyə BTRFS...?Əməliyyat sistemini yükləmək üçün bizə Legacy / BIOS GRUB tərəfindən dəstəklənən və eyni zamanda canlı görüntüləri dəstəkləyən fayl sistemi lazımdır. Biz onu /boot bölməsi üçün istifadə edəcəyik. Bundan əlavə, müəllif bu FS-dən / (kök) üçün istifadə etməyi üstün tutur, hər hansı digər proqram üçün LVM-də ayrıca bölmələr yarada və istədiyiniz qovluqlara quraşdıra biləcəyinizi unutmayın.

Biz bu FS-də virtual maşınların və ya verilənlər bazalarının şəkillərini saxlamayacağıq.
Bu FS yalnız sistemin qapanmadan snapşotlarını yaratmaq üçün istifadə olunacaq, ardınca göndərmə/qəbul funksiyasından istifadə edərək bu snapşotları ehtiyat diskə köçürmək.

Bundan əlavə, müəllif ümumiyyətlə minimum proqram təminatını birbaşa aparatda saxlamağa və proqram təminatının qalan hissəsini GPU və PCI-USB Host nəzarətçilərini IOMMU vasitəsilə KVM-ə yönləndirmək kimi şeylərdən istifadə edərək virtual maşınlarda işə salmağa üstünlük verir.

Aparatda yalnız məlumatların saxlanması, virtuallaşdırma və ehtiyat nüsxə qalır.

ZFS-ə daha çox güvənirsinizsə, o zaman, prinsipcə, göstərilən tətbiq üçün onlar bir-birini əvəz edə bilər.

Bununla belə, müəllif ZFS, BRTFS və LVM-də olan daxili güzgü/RAID və artıqlıq xüsusiyyətlərinə qəsdən məhəl qoymur.

Əlavə bir arqument olaraq, BTRFS təsadüfi yazıları ardıcıl yazılara çevirmək qabiliyyətinə malikdir ki, bu da HDD-də anlıq görüntülərin / ehtiyat nüsxələrin sinxronizasiya sürətinə çox müsbət təsir göstərir.

Bütün cihazları yenidən skan edin:

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

Gəlin ətrafa baxaq:

#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

"Diskləri" bölmək

NVMe SSD

Ancaq heç bir şəkildə onları qeyd etməyəcəyik. Eyni zamanda, BIOS-umuz bu sürücüləri görmür. Beləliklə, onlar tamamilə RAID proqram təminatına keçəcəklər. Hətta orada bölmələr də yaratmayacağıq. "Canon" və ya "əsaslı" olaraq istəsəniz - HDD kimi böyük bir bölmə yaradın.

SATA HDD

Burada ixtira etmək üçün xüsusi bir şey yoxdur. Hər şey üçün bir bölmə yaradacağıq. Biz bölmə yaradacağıq, çünki BIOS bu diskləri görür və hətta onlardan yükləməyə cəhd edə bilər. Biz hətta GRUB-u daha sonra bu disklərə quraşdıracağıq ki, sistem birdən onu əldə etsin.

#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

Burada ən maraqlısı var.

Birincisi, 2 TB diskimiz var. Bu, istifadə edəcəyimiz MBR üçün məqbul diapazon daxilindədir. Lazım gələrsə, onu GPT ilə əvəz edə bilərsiniz. GPT disklərində MBR uyğun sistemlərə ilk 4 terabayt daxilində yerləşdiyi təqdirdə ilk 2 bölməni görməyə imkan verən uyğunluq təbəqəsi var. Əsas odur ki, bu disklərdə açılış bölməsi və bios_grub bölməsi başlanğıcdadır. Hətta Legacy/BIOS GPT disklərindən yükləməyə imkan verir.

Ancaq bu, bizim vəziyyətimiz deyil.

Burada iki bölmə yaradacağıq. Birincisi 1GB ölçüsündə olacaq və RAID 1 /boot üçün istifadə ediləcək.

İkincisi, RAID 6 üçün istifadə ediləcək və sürücünün sonunda kiçik ayrılmamış sahə istisna olmaqla, qalan bütün boş yerləri tutacaq.

Bölünməmiş sahə nədir?Şəbəkədəki mənbələrə görə, SATA SSD-lərimiz 6 ilə 78 giqabayt arasında dəyişən dinamik olaraq genişlənən SLC keşinə malikdir. Sürücünün məlumat vərəqindəki "giqabayt" və "gibibayt" arasındakı fərqə görə "pulsuz" 6 gigabayt alırıq. Qalan 72 giqabayt istifadə olunmamış yerdən ayrılır.

Burada qeyd etmək lazımdır ki, keş SLC-dir və yer 4 bit MLC rejimində tutur. Bu, bizim üçün effektiv o deməkdir ki, hər 4 giqabayt boş yer üçün biz yalnız 1 giqabayt SLC önbelleği alırıq.

72 gigabaytı 4-ə vururuq və 288 gigabayt alırıq. Bu, disklərə SLC keşindən tam istifadə etməyə icazə vermək üçün qeyd etməyəcəyimiz boş yerdir.

Beləliklə, altı sürücüdən cəmi 312 giqabayta qədər SLC önbelleği əldə edəcəyik. Bütün disklərdən 2-si artıqlıq üçün RAID-də istifadə olunacaq.

Belə bir önbellek miqdarı, yazının real həyatda önbelleğe getmədiyi bir vəziyyətlə nadir hallarda qarşılaşmağa imkan verəcəkdir. Bu, QLC yaddaşının ən kədərli çatışmazlığını çox yaxşı kompensasiya edir - keşdən yan keçmək üçün verilənlər yazıldıqda çox aşağı yazma sürəti. Yükləriniz buna uyğun gəlmirsə, məlumat vərəqindəki TBW-ni nəzərə alaraq SSD-lərinizin belə bir yük altında nə qədər yaşayacağı barədə ciddi düşünməyi məsləhət görürəm.

#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

Massivlərin yaradılması

Əvvəlcə maşının adını dəyişdirməliyik. Bu lazımdır, çünki host adı mdadm daxilində bir yerdə massiv adının bir hissəsidir və haradasa nəyəsə təsir edir. Massivlər, əlbəttə ki, sonradan adlandırıla bilər, lakin bunlar lazımsız addımlardır.

#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

Niyə --təmiz-təmiz...?Massivləri işə salmamaq üçün. Həm RAID səviyyəsi 1, həm də 6 üçün bu məqbuldur. Yeni bir massivdirsə, hər şey başlatmadan işləyə bilər. Üstəlik, yaradılarkən SSD massivinin işə salınması TBW resursunun itkisidir. Biz yığılmış SSD massivlərində onları "başlamaq" üçün mümkün olduqda TRIM/DISCARD-dan istifadə edirik.

SSD massivləri üçün RAID 1 DISCARD qutudan kənarda dəstəklənir.

SSD RAID 6 massivləri üçün nüvə modulunun parametrlərində DISCARD aktivləşdirilməlidir.

Bu, yalnız bu sistemdə 4/5/6 səviyyəli massivlərdə istifadə edilən bütün SSD-lərin discard_zeroes_data dəstəyi işlədiyi halda edilməlidir. Bəzən qəribə disklərə rast gəlinir ki, kernelə bu funksiyanın dəstəkləndiyini bildirir, amma əslində o yoxdur və ya funksiya həmişə işləmir. Hal-hazırda dəstək demək olar ki, hər yerdə mövcuddur, lakin səhvləri olan köhnə disklər və proqram təminatı ilə qarşılaşır. Bu səbəbdən RAID 6 üçün DISCARD dəstəyi defolt olaraq qeyri-aktivdir.

Diqqət, aşağıdakı əmr massivi "sıfırlarla" "başlatmaqla" NVMe disklərindəki bütün məlumatları məhv edəcək.

#blkdiscard /dev/md0

Əgər bir şey səhv olarsa, addımı göstərməyə çalışın.

#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

Niyə belə böyük...?Parça ölçüsünün artırılması blok ölçüsü daxil olmaqla bloklarda təsadüfi oxunma sürətinə müsbət təsir göstərir. Bunun səbəbi, uyğun ölçüdə və ya daha az bir əməliyyatın tamamilə bir cihazda həyata keçirilə bilməsidir. Buna görə də, bütün cihazlardan IOPS yekunlaşdırılır. Statistikaya görə, IO-nun 99% -i 512K-dan çox deyil.

Hər yazı üçün RAID 6 IOPS həmişə hər sürücü üçün IOPS-dən az və ya ona bərabərdir. Təsadüfi oxumağa gəldikdə, IOPS bir sürücüdən bir neçə dəfə böyük ola bilər və burada blok ölçüsü əsas əhəmiyyət kəsb edir.
Müəllif RAID 6 tərəfindən dizaynın pis olduğu və bunun əvəzinə RAID 6-nın yaxşı performans göstərdiyi parametri optimallaşdırmağa çalışmağın mənasını görmür.
RAID 6-nın səhv təsadüfi yazısını NVMe önbelleği və nazik təminat fəndləri ilə kompensasiya edəcəyik.

Biz RAID 6 üçün DISCARD funksiyasını hələ aktiv etməmişik. Ona görə də bu massivi hələ “başlatmayacağıq”. Bunu daha sonra, OS quraşdırdıqdan sonra edəcəyik.

SATA HDD

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

NVMe RAID-də LVM

Sürət üçün FS kökünü /dev/md1 olan NVMe RAID 0-ə yerləşdirmək istəyirik.
Bununla belə, dəyişdirmə, LVM-keş metadata və keş və LVM-nazik metadata kimi digər ehtiyaclar üçün hələ də bu sürətli massivə ehtiyacımız olacaq, ona görə də bu massivdə LVM VG yaradacağıq.

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

FS kökü üçün bölmə yaradaq.

#lvcreate -L 128G --name root root

RAM ölçüsünə uyğun olaraq dəyişdirmə bölməsi yaradaq.

#lvcreate -L 32G --name swap root

OS quraşdırılması

Ümumilikdə, sistemi quraşdırmaq üçün lazım olan hər şey bizdə var.

Ubuntu Live mühitindən sistem quraşdırma sihirbazını işə salırıq. Normal quraşdırma. Yalnız quraşdırma üçün disklərin seçilməsi mərhələsində aşağıdakıları göstərməlisiniz:

  • /dev/md1, - quraşdırma nöqtəsi /boot, FS - BTRFS
  • /dev/root/root (aka /dev/mapper/root-root), - quraşdırma nöqtəsi / (kök), FS - BTRFS
  • /dev/root/swap (aka /dev/mapper/root-swap), - dəyişdirmə bölməsi kimi istifadə edin
  • /dev/sda-da bootloader quraşdırın

Kök FS kimi BTRFS-ni seçərkən quraşdırıcı avtomatik olaraq / (root) üçün "@" və /home üçün "@home" adlı iki BTRFS həcmi yaradacaq.

Quraşdırmaya başlayaq...

Quraşdırma, yükləyicini quraşdırarkən xəta haqqında məlumat verən modal dialoq qutusu ilə başa çatacaq. Təəssüf ki, siz standart vasitələrdən istifadə edərək bu dialoqdan çıxa və quraşdırmaya davam edə bilməyəcəksiniz. Sistemdən çıxırıq və təmiz Ubuntu Live iş masasına daxil olaraq yenidən daxil oluruq. Terminal açın və yenidən:

#sudo bash

Quraşdırmaya davam etmək üçün chroot mühiti yaradın:

#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-da şəbəkə və host adını qurun:

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

Chroot mühitinə daxil oluruq:

#chroot /mnt/chroot

Əvvəlcə paketləri çatdıracağıq:

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

Sistemin tamamlanmamış quraşdırılması səbəbindən əyri şəkildə quraşdırılmış bütün paketləri yoxlayaq və düzəldək:

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

Əgər bir şey birlikdə inkişaf etmirsə, bunu etməzdən əvvəl /etc/apt/sources.list redaktə etməli ola bilərsiniz

TRIM/DISCARD funksiyasını aktivləşdirmək üçün RAID 6 modulu üçün parametrləri düzəldək:

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

Gəlin massivlərimizi bir az tənzimləyək:

#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

Bu nə idi..?Aşağıdakıları yerinə yetirəcək bir sıra udev qaydaları yaratdıq:

  • RAID 2020 üçün 6-ci il üçün adekvat blok keş ölçüsünü təyin edin. Defolt dəyər Linux yaradılandan bəri dəyişməyib və çoxdan qeyri-adekvatdır.
  • Massivlərin yoxlanılması/sinxronizasiyası dövrü üçün ən azı IO ehtiyatını saxlayın. Bu, seriallarınızın yük altında əbədi sinxronizasiya vəziyyətində ilişib qalmaması üçün lazımdır.
  • Massivlərin yoxlanılması/sinxronizasiyası müddəti üçün maksimum IO-nu məhdudlaşdırın. Bu, SSD RAID-lərinin sinxronizasiyası/yoxlanmasının sürücülərinizi kəskin şəkildə qızartmamasını təmin etmək üçündür. Bu xüsusilə NVMe üçün doğrudur. (Radiatoru xatırlayırsınız? Mən zarafat etmirdim.)
  • APM vasitəsilə disklərin iş mili fırlanmasını (HDD) dayandırmasının qarşısını alın və disk kontrollerləri üçün yuxu vaxtını 7 saata təyin edin. Sürücüləriniz bunu edə bilirsə, siz APM-i tamamilə söndürə bilərsiniz (-B 255). Varsayılan dəyərlə disklər beş saniyədən sonra dayanacaq. Sonra OS disk önbelleğini təmizləmək istəyəcək, disklər yenidən fırlanacaq və hər şey yenidir. Disklərdə məhdud sayda spindle spinləri var. Belə sadə bir standart dövr bir neçə il ərzində disklərinizi asanlıqla öldürə bilər. Bütün disklər bundan əziyyət çəkmir, lakin RAID-dən əyri mini-MAID yaradan müvafiq standart parametrlərə malik “notebook”larımız.
  • Disklərdə (fırlanan) 1 meqabayta qədər oxunuşunu təyin edin - iki ardıcıl blok/bölmə RAID 6
  • Massivlərin özləri üzrə oxunuşunu söndürün.

Redaktə et /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

Niyə belə..?UUID ilə /boot bölməsini axtaracağıq. massivlərin adlandırılması nəzəri cəhətdən dəyişə bilər.

Biz /dev/mapper/vg-lv qeydində LVM adları üzrə qalan bölmələri axtaracağıq, çünki arakəsmələri unikal şəkildə müəyyənləşdirirlər.

LVM üçün UUID istifadə etmirik. LVM həcmlərinin UUID-i və onların anlıq görüntüləri eyni ola bilər.Mount /dev/mapper/root-root iki dəfə..?Bəli. Tam olaraq. BTRFS-in xüsusiyyəti. Bu FS müxtəlif subvol ilə bir neçə dəfə quraşdırıla bilər.

Bu xüsusiyyətin nəticəsi olaraq, mən sizə heç vaxt aktiv BTRFS həcmlərinin LVM snapshotlarını yaratmamağınızı tövsiyə edirəm. Yenidən başlatdığınız zaman sürprizlə qarşılaşa bilərsiniz.

Mdadm konfiqurasiyasını bərpa edin:

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

LVM parametrlərini tənzimləyək:

#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

Bu nə idi..?Biz zəbt olunmuş yerin 90%-nə həcmin 5%-nə çatdıqdan sonra LVM nazik hovuzlarının avtomatik genişləndirilməsini təmin etdik.

LVM keşi üçün keş bloklarının maksimum sayını artırdıq.

LVM-nin LVM həcmlərini (PV) axtarmasının qarşısını aldıq:

  • LVM önbelleği (cdata) olan cihazlar
  • LVM keşi ilə keşlənmiş cihazlar keşi keçərək ( _corig). Bu halda, keşlənmiş cihazın özü hələ də önbellek vasitəsilə skan ediləcək (yalnız ).
  • LVM keş metadatası (cmeta) olan cihazlar
  • VG-dəki bütün cihazlar şəkillər adlanır. Burada virtual maşınların disk şəkillərinə sahib olacağıq və biz hostda LVM-nin qonaq ƏS-ə aid həcmləri aktivləşdirməsini istəmirik.
  • VG-dəki bütün qurğular ehtiyat adlanır. Burada virtual maşın şəkillərinin ehtiyat nüsxələri olacaq.
  • adı "gpv" ilə bitən bütün cihazlar (qonaq fiziki həcmi)

LVM VG-də yer boşaldarkən DISCARD dəstəyini aktiv etdik. Ehtiyatlı ol. Bu, SSD-də LV-nin silinməsini kifayət qədər uzun edəcək. Bu, xüsusilə SSD RAID 6 üçün doğrudur. Ancaq plana görə, biz nazik təminatdan istifadə edəcəyik, ona görə də bu, bizi heç narahat etməyəcək.

İnitramfs şəklini yeniləyin:

#update-initramfs -u -k all

Qrupu quraşdırın və konfiqurasiya edin:

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

Hansı diskləri seçməlisiniz?Bütün bunlar sd*. Sistem istənilən işləyən SATA sürücüsündən və ya SSD-dən yüklənə bilməlidir.

Niyə mismarlanmış os-prober..?Həddindən artıq müstəqillik və oynaq əllər üçün.

RAID-lərdən biri pozulmuş vəziyyətdədirsə, o, düzgün işləmir. Bu aparatda işləyən virtual maşınlarda istifadə olunan bölmələrdə ƏS-ni axtarmağa çalışır.

Əgər ehtiyacınız varsa, onu tərk edə bilərsiniz, lakin yuxarıda göstərilənlərin hamısını unutmayın. Şəbəkədə oynaq əllərdən qurtulmaq üçün reseptlər axtarmağı məsləhət görürəm.

Bu, ilkin quraşdırmanı tamamlayır. Yeni quraşdırılmış OS-yə yenidən başlama vaxtıdır. Yüklənə bilən Live CD/USB-ni çıxarmağı unutmayın.

#exit
#reboot

Yükləmə cihazı olaraq SATA SSD-lərdən birini seçin.

SATA SSD-də LVM

Bu nöqtədə, biz artıq yeni OS-yə yükləndik, şəbəkəni qurduq, apt etdik, terminal emulyatorunu açdıq və işə başladıq:

#sudo bash

Davam edək.

SATA SSD sırasını "başladın":

#blkdiscard /dev/md2

Əgər işləmirsə, o zaman cəhd edirik:

#blkdiscard --step 65536 /dev/md2
SATA SSD-də LVM VG yaradın:

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

Niyə başqa VG..?Həqiqətən, bizdə kök adlı bir VG var. Niyə hər şeyi bir VG-yə qoymayaq?

Əgər VG-də bir neçə PV varsa, onda VG-nin düzgün işə salınması üçün bütün PV-lər mövcud (onlayn) olmalıdır. İstisna, qəsdən istifadə etmədiyimiz LVM RAID-dir.

Biz həqiqətən istəyirik ki, RAID 6 massivlərindən hər hansı birində qəza baş verərsə (məlumatların oxunması itkisi) əməliyyat sistemi normal şəkildə yüklənsin və bizə problemi həll etmək imkanı versin.

Bunun üçün birinci abstraksiya səviyyəsində biz hər bir fiziki "daşıyıcı" növünü ayrıca VG-yə təcrid edəcəyik.

Elmi desək, müxtəlif RAID massivləri müxtəlif "etibarlılıq sahələrinə" aiddir. Onları bir VG-yə dolduraraq, onlar üçün əlavə ümumi uğursuzluq nöqtəsi yaratmamalısınız.

LVM-nin "dəmir" səviyyəsində olması bizə müxtəlif RAID massivlərinin hissələrini müxtəlif yollarla birləşdirərək özbaşına kəsməyə imkan verəcək. Məsələn, qaç eyni zamanda bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, keşləri olan mürəkkəb ZFS konfiqurasiyası və ya hamısını hiss etmək və müqayisə etmək üçün hər hansı digər cəhənnəm qarışığı.

"Dəmir" səviyyəsində köhnə yaxşı "qalın" LVM həcmlərindən başqa heç nə istifadə etməyəcəyik. Bu qaydanın istisnası ehtiyat bölmə ola bilər.

Düşünürəm ki, bu nöqtəyə qədər bir çox oxucu artıq matryoshka haqqında nədənsə şübhələnməyə başlayıb.

SATA HDD-də LVM

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

Daha bir yeni VG..?Biz həqiqətən istəyirik ki, məlumatların ehtiyat nüsxəsi üçün istifadə edəcəyimiz disklər sırası uğursuz olduqda, əməliyyat sistemimizin ehtiyat nüsxəsi olmayan məlumatlara çıxışı təmin etməklə yanaşı, normal işləməyə davam etməsi. Buna görə də, VG-nin aktivləşdirilməsi ilə bağlı problemlərin qarşısını almaq üçün biz ayrıca VG yaradırıq.

LVM keşinin qurulması

NVMe RAID 1-də onu keşləmə cihazı kimi istifadə etmək üçün LV yaradaq.

#lvcreate -L 70871154688B --name cache root

Niyə bu qədər az...?Fakt budur ki, NVMe SSD-lərimiz də SLC önbelleğine malikdir. 4 bitlik MLC-də boş yer tutduğuna görə 18 gigabayt "pulsuz" və 3 gigabayt dinamik. Bu keşi boşaltdıqdan sonra NVMe SSD-lər keşlənmiş SATA SSD-lərimizdən çox da sürətli olmayacaq. Əslində, bu səbəbdən, LVM önbelleği bölməsini NVMe sürücüsünün SLC keşinin ölçüsündən iki dəfə daha böyük etmək bizim üçün mənasızdır. İstifadə olunan NVMe diskləri üçün müəllif 32-64 giqabayt keş yaddaş yaratmağı məqsədəuyğun hesab edir.

Verilmiş bölmə ölçüsü 64 giqabayt keş, keş metadata və metadata ehtiyat nüsxəsini təşkil etmək üçün tələb olunur.

Əlavə olaraq qeyd edirəm ki, sistemin çirkli bağlanmasından sonra LVM bütün önbelleği çirkli olaraq qeyd edəcək və yenidən sinxronizasiya edəcək. Üstəlik, bu, yeni sistem yenidən işə salınana qədər həmin cihazda lvchange istifadə etdiyiniz hər dəfə təkrarlanacaq. Buna görə də, mən dərhal önbelleği müvafiq skriptlə yenidən yaratmağı məsləhət görürəm.

Gəlin SATA RAID 6-da LV yaradaq ki, onu önbelleğe alına bilən cihaz kimi istifadə edək.

#lvcreate -L 3298543271936B --name cache data

Niyə cəmi üç terabayt..?Beləliklə, lazım gələrsə, bəzi digər ehtiyaclar üçün SATA SSD RAID 6-dan istifadə edə bilərsiniz. Keşlənmiş məkanın ölçüsü sistemi dayandırmadan dinamik şəkildə artırıla bilər. Bunu etmək üçün siz müvəqqəti olaraq keşi dayandırmalı və yenidən aktivləşdirməlisiniz, lakin LVM-keşin, məsələn, bcache-dən fərqli üstünlükləri ondan ibarətdir ki, bunu tez bir zamanda etmək olar.

Keşləmə üçün yeni VG yaradaq.

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

Keşlənmiş cihazda LV yaradaq.

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

Burada dərhal /dev/data/cache-də bütün boş yerləri götürdük ki, bütün digər lazımi bölmələr dərhal /dev/root/cache-də yaradılsın. Səhv yerdə yaradılmış bir şey varsa, onu pvmove istifadə edərək köçürə bilərsiniz.

Keşi yaradaq və aktiv edək:

#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

Niyə belə bir ölçü..?Müəllif praktiki təcrübələr vasitəsilə LVM keş blokunun ölçüsü LVM nazik blokunun ölçüsü ilə eyni olduqda ən yaxşı nəticənin əldə olunduğunu öyrənə bildi. Eyni zamanda, ölçüsü nə qədər kiçik olsa, konfiqurasiya təsadüfi qeyddə bir o qədər yaxşı görünür.

64k nazik LVM üçün icazə verilən minimum blok ölçüsüdür.

Diqqət yazın..!Bəli. Bu tip keş keşlənmiş cihazla yazma sinxronizasiyasını təxirə salır. Bu, önbellek itkisi halında, keşlənmiş cihazdakı məlumatları itirə biləcəyinizə gətirib çıxarır. Daha sonra müəllif bu riski kompensasiya etmək üçün NVMe RAID 1-dən başqa hansı tədbirlərin görülə biləcəyini sizə xəbər verəcəkdir.

Bu tip keş RAID 6-nın təsadüfi yazılarda zəif performansını kompensasiya etmək üçün qəsdən seçilmişdir.

Nə əldə etdiyimizi yoxlayaq:

#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 yalnız [cachedata_corig] ehtiva etməlidir. Bir şey səhv olarsa, pvmove istifadə edin.

Lazım gələrsə, bir əmrlə keşi söndürə bilərsiniz:

#lvconvert -y --uncache cache/cachedata

Bu onlayn edilir. LVM sadəcə olaraq keşi diskə sinxronizasiya edir, onu silir və cachedata_corig adını yenidən cachedata ilə dəyişdirir.

LVM nazik qurulması

LVM nazik metadata üçün bizə nə qədər yer lazım olduğunu təxmini olaraq təxmin edək:

#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 giqabayta qədər yuvarlaqlaşdırın: 4294967296B

LVM PV metadata üçün ikiyə vurun və 4194304B əlavə edin: 8594128896B
LVM nazik metadatasını və onun ehtiyat nüsxəsini yerləşdirmək üçün NVMe RAID 1-də ayrıca bölmə yaradaq:

#lvcreate -L 8594128896B --name images root

Nə üçün..?Burada sual yarana bilər, əgər onlar hər halda NVMe-də keşlənəcəklərsə və tez işləyəcəklərsə, LVM nazik metaməlumatlarını niyə ayrıca yerləşdirmək lazımdır.

Burada sürət vacibdir, amma əsas səbəb deyil. İş ondadır ki, önbellek uğursuzluq nöqtəsidir. Onun başına bir şey gələ bilər və LVM nazik metadata keşlənərsə, bu, hər şeyin tamamilə itirilməsinə səbəb olacaqdır. Bütün metadata olmadan nazik həcmlər yaratmaq qeyri-mümkün olardı.

Metaməlumatları ayrıca, keşlənməyən, lakin sürətli həcmə köçürməklə, biz keşin itirilməsi və ya zədələnməsi halında metadatanın təhlükəsizliyinə zəmanət veririk. Bu halda, keşin itirilməsi nəticəsində yaranan bütün zərərlər nazik həcmlər daxilində lokallaşdırılacaq ki, bu da bərpa prosedurunu böyüklük əmrləri ilə asanlaşdıracaq. Yüksək ehtimalla, bu zərərlər FS qeydlərindən istifadə etməklə bərpa olunacaq.

Üstəlik, əvvəllər nazik həcmli bir şəkil çəkilibsə və bundan sonra keş ən azı bir dəfə tam sinxronlaşdırılıbsa, LVM nazik daxili cihazın təbiətinə görə, snapshotın bütövlüyü təmin ediləcəkdir. önbelleğin itirilməsi.

İncə təminatdan məsul olacaq yeni VG yaradaq:

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

Bir hovuz yaradaq:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Niyə -Z yBu rejimin əslində nə üçün nəzərdə tutulduğuna əlavə olaraq - məkanı yenidən bölüşdürərkən bir virtual maşından məlumatın digər virtual maşına sızmasının qarşısını almaq üçün - sıfırlama əlavə olaraq 64k-dan az bloklarda təsadüfi yazma sürətini artırmaq üçün istifadə olunur. İncə həcmin əvvəllər bölüşdürülməmiş sahəsinə 64k-dan az olan hər hansı yazı 64K önbelleğe uyğunlaşdırılacaq. Bu, əməliyyatı keşlənmiş cihazdan yan keçməklə, tamamilə keş vasitəsilə yerinə yetirməyə imkan verəcək.

LV-ləri müvafiq PV-lərə köçürək:

#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

yoxlayaq:

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

Testlər üçün nazik bir həcm yaradaq:

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

Test və monitorinq üçün paketləri quraşdıraq:

#apt-get install sysstat fio

Yaddaş konfiqurasiyamızın davranışını real vaxtda belə müşahidə edə bilərsiniz:

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

Konfiqurasiyamızı belə sınaya bilərik:

#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

Diqqətlə! Resurs!Bu kod hər biri 36 saniyə işləyən 4 fərqli testi həyata keçirəcək. Yazı testlərinin yarısı. NVMe-də 4 saniyə ərzində çox şey yaza bilərsiniz. Saniyədə 3 giqabayta qədər. Beləliklə, hər yazma testi sizdən 216 giqabayta qədər SSD resursunu yeyə bilər.

Oxumaq və yazmaq qarışıqdır?Bəli. Oxuma və yazma testlərini ayrıca icra etməyin mənası var. Üstəlik, əvvəlki yazının oxumağa təsir etməməsi üçün bütün önbelleklərin sinxronlaşdırıldığına əmin olmaq məntiqlidir.

Nəticələr, keş və nazik həcm dolduqca ilk və sonrakılarda, həmçinin sistemin son işdə doldurulmuş keşləri sinxronlaşdıra bilib-bilməməsindən asılı olaraq çox dəyişəcək.

Digər şeylər arasında sürəti artıq doldurulmuş nazik həcmdə ölçməyi məsləhət görürəm, hansı ki, indicə bir şəkil çəkilmişdir. Müəllif, ilk snapshot yaradıldıqdan dərhal sonra, xüsusən də keş hələ tam dolmadıqda, təsadüfi yazmanın necə kəskin surətdə sürətləndiyini müşahidə etmək imkanı əldə etdi. Bu, yazmanın surəti-on-yazma semantikası, önbelleğin və nazik həcm bloklarının uyğunlaşdırılması və RAID 6-ya təsadüfi yazının RAID 6-dan təsadüfi oxunuşdan sonra keş yaddaşa yazılmasına çevrilməsi ilə bağlıdır. . Konfiqurasiyamızda RAID 6-dan təsadüfi oxunmalar yazıdan 6 dəfəyə qədər daha sürətlidir (massivdəki SATA SSD-lərin sayı). Çünki CoW üçün bloklar nazik hovuzdan ardıcıl olaraq ayrılır, sonra rekord, əksər hallarda, ardıcıllığa çevrilir.

Bu xüsusiyyətlərin hər ikisi üstünlük əldə etmək üçün istifadə edilə bilər.

"Koherent" snapshotları keş edin

Keşin zədələnməsi / itməsi halında məlumat itkisi riskini azaltmaq üçün müəllif bu halda onların bütövlüyünə zəmanət verən snapshot fırlanma təcrübəsini tətbiq etməyi təklif edir.

Birincisi, nazik həcmli metadata keşlənməyən cihazda yerləşdiyi üçün metadata ardıcıl olacaq və mümkün itkilər məlumat blokları daxilində təcrid olunacaq.

Aşağıdakı snapshot fırlanma dövrü keş itkisi halında snapshotlar daxilində məlumatların bütövlüyünə zəmanət verir:

  1. <name> adlı hər nazik həcm üçün <name>.cached adlı bir şəkil yaradın
  2. Miqrasiya həddini kifayət qədər yüksək dəyərə təyin edin: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Döngədə keşdəki çirkli blokların sayını yoxlayırıq: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' sıfıra çatana qədər. Sıfır çox uzun müddət əskik olarsa, keşi müvəqqəti olaraq yazma rejiminə təyin etməklə onu yaratmaq olar. Bununla belə, SATA və NVMe SSD massivlərimizin sürət xüsusiyyətlərini, eləcə də onların TBW resursunu nəzərə alaraq, siz ya keş rejimini dəyişmədən anı tez tuta biləcəksiniz, ya da aparatınız bir neçə müddət ərzində bütün resursunu tamamilə yeyəcək. günlər. Resurs məhdudiyyətlərinə görə, sistem prinsipcə hər zaman 100% yazma yükünün altında ola bilmir. 100% yazma yükü altında olan NVMe SSD-lərimiz içindəki resursu tamamilə istifadə edəcək 3-4 gün. SATA SSD-lər yalnız iki dəfə daha uzun sürəcək. Buna görə də, yükün çoxunun oxumağa getdiyini güman edəcəyik və yazmaq üçün orta hesabla aşağı yüklə birlikdə olduqca yüksək fəaliyyətin nisbətən qısa partlamaları var.
  4. Sıfırı tutan kimi (və ya düzəldən) biz <name>.cached adını <name>.committed olaraq dəyişdiririk. Köhnə <ad>. törədilən silindi.
  5. İsteğe bağlı olaraq, keş 100% doludursa, skript tərəfindən yenidən yaradıla bilər, beləliklə onu təmizləyir. Yarım boş keş ilə sistem yazılarda daha sürətli işləyir.
  6. Miqrasiya həddini sıfıra təyin edin: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Bu müvəqqəti olaraq keşin əsas media ilə sinxronizasiyasının qarşısını alacaq.
  7. Keş yaddaşında kifayət qədər dəyişikliklərin yığılmasını gözləyirik #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' və ya taymer işləyəcək.
  8. Yenidən təkrar edirik.

Niyə miqrasiya həddi ilə çətinlik...?İş ondadır ki, real təcrübədə “təsadüfi” qeyd əslində tamamilə təsadüfi deyil. Əgər 4 kilobaytlıq sektora nəsə yazmışıqsa, yaxın bir neçə dəqiqə ərzində eyni və ya qonşu (+- 32K) sektorlardan birinə rekordun vurulması ehtimalı yüksəkdir.

Miqrasiya həddini sıfıra təyin etməklə biz SATA SSD-yə yazma sinxronizasiyasını təxirə salırıq və keşdəki eyni 64K bloka çoxsaylı dəyişiklikləri birləşdiririk. Beləliklə, SATA SSD resursu nəzərəçarpacaq dərəcədə saxlanılır.

kod haradadır..?Təəssüf ki, müəllif özünü bash skriptlərinin hazırlanmasında kifayət qədər səriştəsiz hesab edir, çünki o, 100% özünü öyrədir və "google" tərəfindən idarə olunan inkişafı tətbiq edir, buna görə də onun əlindən çıxan dəhşətli kodun olmamağın daha yaxşı olduğuna inanır. başqası tərəfindən istifadə olunur.

Düşünürəm ki, bu sahənin peşəkarları zərurət yaranarsa, yuxarıda təsvir olunan bütün məntiqi müstəqil şəkildə təsvir edə və hətta müəllifin etməyə çalışdığı kimi onu sistemli xidmət kimi gözəl şəkildə təşkil edə biləcəklər.

Belə bir sadə snapshot fırlanma sxemi bizə nəinki daim SATA SSD-də tam sinxronlaşdırılan bir snapshot əldə etməyə imkan verəcək, həm də thin_delta yardım proqramından istifadə edərək yaradıldıqdan sonra hansı blokların dəyişdirildiyini öyrənməyə və bununla da əsas zədələnməni lokallaşdırmağa imkan verəcəkdir. həcmlər, bərpanı xeyli asanlaşdırır. .

libvirt/KVM-də KESİN/ATIN

Çünki Məlumat anbarı libvirt ilə işləyən KVM üçün istifadə ediləcəyi üçün VM-lərimizə təkcə boş yer tutmağı deyil, həm də lazımsız yerləri boşaltmağı öyrətmək gözəl olardı.

Bu, virtual disklərdə TRIM/DISCARD dəstəyini təqlid etməklə həyata keçirilir. Bunun üçün siz nəzarətçi tipini virtio-scsi-yə dəyişməli və xml-i redaktə etməlisiniz.

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

Qonaq OS-lərdən belə DISCARD-lar LVM tərəfindən düzgün idarə olunur və bloklar həm keş, həm də nazik hovuzda düzgün şəkildə ayrılır. Bizim vəziyyətimizdə bu, əsasən təxirə salınmış, növbəti snapshot silindikdə baş verir.

BTRFS ehtiyat nüsxəsi

ilə hazır skriptlərdən istifadə edin həddindən artıq ehtiyatla və öz riski ilə. Müəllif bu kodu özü və yalnız özü üçün yazıb. Əminəm ki, bir çox təcrübəli Linux istifadəçilərinin oxşar qoltuqları var və başqalarını kopyalamağa ehtiyac yoxdur.

Yedək cihazında həcm yaradaq:

#lvcreate -L 256G --name backup backup

BTRFS-də format:

#mkfs.btrfs /dev/backup/backup

Quraşdırma nöqtələrini yaradaq və fayl sisteminin kök alt bölmələrini quraşdıraq:

#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

Yedəkləmə üçün qovluqlar yaradın:

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

Yedək skriptləri üçün bir kataloq yaradaq:

#mkdir /root/btrfs-backup

Skripti kopyalayaq:

Çox qorxulu bash kodu. Öz riskinizlə istifadə edin. Müəllifə qəzəbli məktublar yazmayın ...#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

Hətta nə edir..?BTRFS snapshotlarını yaratmaq və BTRFS göndərmək/qəbul etməkdən istifadə edərək onları başqa fayl sisteminə köçürmək üçün bir sıra sadə əmrləri ehtiva edir.

İlk başlanğıc kimi, nisbətən uzun ola bilər bütün məlumatlar əvvəlində kopyalanacaq. Növbəti buraxılışlar çox sürətli olacaq, çünki. yalnız dəyişikliklər kopyalanacaq.

Cron-a köçürəcəyimiz başqa bir skript:

Daha bir neçə bash kodu#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

Bu nə edir..?Siyahıda göstərilən BTRFS həcmlərinin artımlı anlıq görüntülərini yaradır və ehtiyat FS ilə sinxronlaşdırır. Bundan sonra, 60 gün əvvəl yaradılan bütün snapshotları silir. Başladıqdan sonra /backup/btrfs/back/remote/ alt kataloqlarında sadalanan cildlərin tarixli anlıq görüntüləri olacaq.

Koda icra hüququ verək:

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

Gəlin onu yoxlayaq və cron-a qoyaq:

#/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 incə ehtiyat nüsxəsi

Yedək cihazında nazik bir hovuz yaradaq:

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

Ddrescue quraşdırın, çünki skriptlər bu alətdən istifadə edəcək:

#apt-get install gddrescue

Skriptlər üçün kataloq yaradaq:

#mkdir /root/lvm-thin-backup

Skriptləri kopyalayaq:

İçəridə çoxlu çaşqınlıq...#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

Bu nə edir...?ddrescue və blkdiscard istifadə edərək thin_delta vasitəsilə əldə edilmiş iki nazik snapşot arasındakı fərqi digər blok cihazı ilə sinxronlaşdırmaq üçün incə snapshotları idarə etmək və sinxronizasiya etmək üçün bir sıra əmrləri ehtiva edir.

Cron-a sıxışdıracağımız başqa bir skript:

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

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

BACKUP_SCRIPT="$SCRIPT_DIR/lvm-thin-backup.sh"
RETENTION="-60 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

Bu nə edir...?Sadalanan nazik həcmlərin ehtiyat nüsxələrini yaratmaq və sinxronlaşdırmaq üçün əvvəlki skriptdən istifadə edir. Skript son sinxronizasiyadan sonra dəyişiklikləri izləmək üçün lazım olan sadalanan cildlərin qeyri-aktiv şəkillərini tərk edəcək.

Bu skript ehtiyat nüsxəsini çıxarmaq lazım olan nazik cildlərin siyahısını daxil etmək üçün redaktə edilməlidir. Verilən adlar yalnız misaldır. İstəyirsinizsə, bütün həcmləri sinxronlaşdıracaq bir skript yaza bilərsiniz.

Gəlin hüquqlar verək:

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

Gəlin onu yoxlayaq və cron-a qoyaq:

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

İlk buraxılış uzun olacaq, çünki. nazik həcmlər bütün istifadə olunan məkanı kopyalayaraq tam sinxronlaşdırılacaq. LVM nazik metadata sayəsində biz hansı blokların əslində istifadə edildiyini bilirik, ona görə də yalnız nazik həcmlərin həqiqətən istifadə olunan blokları kopyalanacaq.

Sonrakı əməliyyatlar LVM nazik metadata vasitəsilə izləməni dəyişmək sayəsində məlumatları tədricən kopyalayacaq.

Nə baş verdiyinə baxaq:

#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

Bəs yuva quran kuklalar haqqında nə demək olar?

Çox güman ki, LVM LV-ləri digər VG-lər üçün fiziki LVM PV ola bilər. LVM yuva quran kuklalar kimi rekursiv ola bilər. Bu, LVM-ə həddindən artıq elastiklik verir.

PS

Növbəti məqalədə bir neçə oxşar mobil yaddaşdan / KVM-dən ev masası, ev İnterneti və P2P şəbəkələri vasitəsilə bir neçə qitədə ehtiyatla geo-paylanmış saxlama / vm klaster yaratmaq üçün əsas kimi istifadə etməyə çalışacağıq.

Mənbə: www.habr.com

Добавить комментарий