Apakah persamaan LVM dan Matryoshka?

Hari yang baik.
Saya ingin berkongsi dengan komuniti pengalaman praktikal saya membina sistem storan data untuk KVM menggunakan md RAID + LVM.

Program ini akan merangkumi:

  • Membina md RAID 1 daripada NVMe SSD.
  • Memasang md RAID 6 daripada SATA SSD dan pemacu biasa.
  • Ciri-ciri operasi TRIM/DISCARD pada SSD RAID 1/6.
  • Mencipta tatasusunan md RAID 1/6 boleh boot pada set cakera biasa.
  • Memasang sistem pada NVMe RAID 1 apabila tiada sokongan NVMe dalam BIOS.
  • Menggunakan cache LVM dan LVM nipis.
  • Menggunakan syot kilat BTRFS dan hantar/terima untuk sandaran.
  • Menggunakan syot kilat nipis LVM dan thin_delta untuk sandaran gaya BTRFS.

Jika anda berminat, sila lihat kucing.

Penyata

Penulis tidak bertanggungjawab atas akibat menggunakan atau tidak menggunakan bahan/contoh/kod/tips/data daripada artikel ini. Dengan membaca atau menggunakan bahan ini dalam apa jua cara, anda bertanggungjawab ke atas semua akibat daripada tindakan ini. Akibat yang mungkin termasuk:

  • SSD NVMe yang digoreng garing.
  • Habis sepenuhnya sumber rakaman dan kegagalan pemacu SSD.
  • Kehilangan lengkap semua data pada semua pemacu, termasuk salinan sandaran.
  • Perkakasan komputer rosak.
  • Membuang masa, saraf dan wang.
  • Apa-apa akibat lain yang tidak disenaraikan di atas.

Besi

Tersedia ialah:

Papan induk dari sekitar 2013 dengan chipset Z87, lengkap dengan Intel Core i7 / Haswell.

  • Pemproses 4 teras, 8 benang
  • 32 GB DDR3 RAM
  • 1 x 16 atau 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • Penyambung SATA 6 6 x 3 GBps

Penyesuai SAS LSI SAS9211-8I berkelip ke mod IT / HBA. Perisian tegar yang didayakan RAID telah sengaja digantikan dengan perisian tegar HBA untuk:

  1. Anda boleh membuang penyesuai ini pada bila-bila masa dan menggantikannya dengan penyesuai lain yang anda temui.
  2. TRIM/Discard berfungsi seperti biasa pada cakera, kerana... dalam perisian tegar RAID arahan ini tidak disokong sama sekali, dan HBA, secara amnya, tidak peduli apa arahan yang dihantar melalui bas.

Pemacu keras - 8 keping HGST Travelstar 7K1000 dengan kapasiti 1 TB dalam faktor bentuk 2.5, seperti untuk komputer riba. Pemacu ini sebelum ini berada dalam tatasusunan RAID 6. Mereka juga akan mempunyai kegunaan dalam sistem baharu. Untuk menyimpan sandaran tempatan.

Tambahan ditambah:

6 keping SATA SSD model Samsung 860 QVO 2TB. SSD ini memerlukan volum yang besar, kehadiran cache SLC, kebolehpercayaan dan harga yang rendah dikehendaki. Sokongan untuk buang/sifar diperlukan, yang disemak oleh baris dalam dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 keping NVMe SSD model Samsung SSD 970 EVO 500GB.

Untuk SSD ini, kelajuan baca/tulis rawak dan kapasiti sumber untuk keperluan anda adalah penting. Radiator untuk mereka. Semestinya. betul-betul. Jika tidak, gorengkannya sehingga garing semasa penyegerakan RAID yang pertama.

Penyesuai StarTech PEX8M2E2 untuk 2 x NVMe SSD dipasang dalam slot PCIe 3.0 8x. Ini, sekali lagi, hanyalah HBA, tetapi untuk NVMe. Ia berbeza daripada penyesuai murah kerana ia tidak memerlukan sokongan bifurkasi PCIe daripada papan induk kerana kehadiran suis PCIe terbina dalam. Ia akan berfungsi walaupun dalam sistem paling kuno dengan PCIe, walaupun ia adalah slot x1 PCIe 1.0. Sememangnya, pada kelajuan yang sesuai. Tiada RAID di sana. Tiada BIOS terbina dalam pada papan. Jadi, sistem anda tidak akan belajar secara ajaib untuk but dengan NVMe, lebih-lebih lagi NVMe RAID terima kasih kepada peranti ini.

Komponen ini adalah semata-mata kerana kehadiran hanya satu 8x PCIe 3.0 percuma dalam sistem, dan, jika terdapat 2 slot percuma, ia boleh digantikan dengan mudah dengan dua sen PEX4M2E1 atau analog, yang boleh dibeli di mana-mana sahaja pada harga 600 rubel.

Penolakan semua jenis perkakasan atau cipset/BIOS RAID terbina dalam dibuat dengan sengaja, untuk dapat menggantikan sepenuhnya keseluruhan sistem, kecuali SSD/HDD itu sendiri, sambil mengekalkan semua data. Sebaik-baiknya, supaya anda boleh menyimpan walaupun sistem pengendalian yang dipasang apabila berpindah ke perkakasan yang benar-benar baharu/berbeza. Perkara utama ialah terdapat port SATA dan PCIe. Ia seperti CD langsung atau pemacu kilat boleh boot, hanya sangat laju dan sedikit besar.

ЮморJika tidak, anda tahu apa yang berlaku - kadangkala anda perlu segera membawa keseluruhan tatasusunan bersama anda untuk dibawa pergi. Tetapi saya tidak mahu kehilangan data. Untuk melakukan ini, semua media yang disebutkan terletak pada slaid di ruang 5.25 kotak standard.

Nah, dan, tentu saja, untuk bereksperimen dengan kaedah caching SSD yang berbeza di Linux.

Serbuan perkakasan membosankan. Hidupkannya. Ia sama ada berfungsi atau tidak. Dan dengan mdadm sentiasa ada pilihan.

Software

Sebelum ini, Debian 8 Jessie telah dipasang pada perkakasan, yang hampir dengan EOL. RAID 6 telah dipasang dari HDD yang disebutkan di atas dipasangkan dengan LVM. Ia menjalankan mesin maya dalam kvm/libvirt.

Kerana Penulis mempunyai pengalaman yang sesuai dalam mencipta pemacu kilat SATA/NVMe boleh boot mudah alih, dan juga, untuk tidak memecahkan templat apt biasa, Ubuntu 18.04 dipilih sebagai sistem sasaran, yang telah cukup stabil, tetapi masih mempunyai 3 tahun sokongan pada masa hadapan.

Sistem yang disebutkan mengandungi semua pemacu perkakasan yang kami perlukan di luar kotak. Kami tidak memerlukan sebarang perisian atau pemacu pihak ketiga.

Bersedia untuk pemasangan

Untuk memasang sistem kami memerlukan Imej Desktop Ubuntu. Sistem pelayan mempunyai beberapa jenis pemasang yang kuat, yang menunjukkan kebebasan yang berlebihan yang tidak boleh dilumpuhkan dengan menolak partition sistem UEFI ke salah satu cakera, merosakkan semua keindahan. Sehubungan itu, ia dipasang hanya dalam mod UEFI. Tidak menawarkan sebarang pilihan.

Kami tidak berpuas hati dengan ini.

Mengapa?Malangnya, but UEFI sangat tidak serasi dengan perisian boot RAID, kerana... Tiada siapa yang menawarkan kami tempahan untuk partition UEFI ESP. Terdapat resipi dalam talian yang mencadangkan meletakkan partition ESP pada pemacu kilat dalam port USB, tetapi ini adalah titik kegagalan. Terdapat resipi menggunakan perisian mdadm RAID 1 dengan metadata versi 0.9 yang tidak menghalang UEFI BIOS daripada melihat partition ini, tetapi ini kekal sehingga saat gembira apabila BIOS atau OS perkakasan lain menulis sesuatu kepada ESP dan terlupa untuk menyegerakkannya ke yang lain. cermin.

Di samping itu, but UEFI bergantung pada NVRAM, yang tidak akan bergerak bersama cakera ke sistem baharu, kerana adalah sebahagian daripada papan induk.

Jadi, kami tidak akan mencipta semula roda baharu. Kami sudah mempunyai basikal datuk yang sudah siap dan telah diuji masa, kini dipanggil but Legacy/BIOS, yang membawa nama kebanggaan CSM pada sistem yang serasi dengan UEFI. Kami hanya akan mengeluarkannya dari rak, melincirkannya, mengepam tayar dan mengelapnya dengan kain lembap.

Versi desktop Ubuntu juga tidak boleh dipasang dengan betul dengan pemuat but Legacy, tetapi di sini, seperti yang mereka katakan, sekurang-kurangnya terdapat pilihan.

Oleh itu, kami mengumpul perkakasan dan memuatkan sistem daripada pemacu denyar boleh boot Ubuntu Live. Kami perlu memuat turun pakej, jadi kami akan menyediakan rangkaian yang sesuai untuk anda. Jika ia tidak berfungsi, anda boleh memuatkan pakej yang diperlukan ke pemacu kilat terlebih dahulu.

Kami pergi ke persekitaran Desktop, melancarkan emulator terminal, dan kami pergi:

#sudo bash

Bagaimana…?Baris di atas ialah pencetus kanonik untuk holiwar tentang sudo. C bоpeluang yang lebih besar datang danоtanggungjawab yang lebih besar. Persoalannya ialah sama ada anda boleh mengambilnya sendiri. Ramai orang berfikir bahawa menggunakan sudo dengan cara ini sekurang-kurangnya tidak berhati-hati. Walau bagaimanapun:

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

Kenapa tidak ZFS...?Apabila kami memasang perisian pada komputer kami, kami pada dasarnya meminjamkan perkakasan kami kepada pembangun perisian ini untuk memandu.
Apabila kami mempercayai perisian ini dengan keselamatan data kami, kami mengambil pinjaman yang sama dengan kos memulihkan data ini, yang perlu kami bayar suatu hari nanti.

Dari sudut pandangan ini, ZFS ialah Ferrari, dan mdadm+lvm lebih seperti basikal.

Secara subjektif, penulis lebih suka meminjamkan basikal secara kredit kepada individu yang tidak dikenali berbanding Ferrari. Di sana, harga isu itu tidak tinggi. Tidak perlu hak. Lebih mudah daripada peraturan lalu lintas. Tempat letak kereta adalah percuma. Keupayaan merentas desa lebih baik. Anda sentiasa boleh melekatkan kaki pada basikal, dan anda boleh membaiki basikal dengan tangan anda sendiri.

Kenapa pula BTRFS...?Untuk but sistem pengendalian, kami memerlukan sistem fail yang disokong dalam Legacy/BIOS GRUB di luar kotak, dan pada masa yang sama menyokong syot kilat langsung. Kami akan menggunakannya untuk partition /boot. Di samping itu, penulis lebih suka menggunakan FS ini untuk / (root), tidak lupa untuk ambil perhatian bahawa untuk mana-mana perisian lain anda boleh membuat partition berasingan pada LVM dan memasangnya dalam direktori yang diperlukan.

Kami tidak akan menyimpan sebarang imej mesin maya atau pangkalan data pada FS ini.
FS ini hanya akan digunakan untuk mencipta syot kilat sistem tanpa mematikannya dan kemudian memindahkan syot kilat ini ke cakera sandaran menggunakan hantar/terima.

Di samping itu, pengarang secara amnya lebih suka menyimpan minimum perisian secara langsung pada perkakasan dan menjalankan semua perisian lain dalam mesin maya menggunakan perkara seperti memajukan GPU dan pengawal Hos PCI-USB ke KVM melalui IOMMU.

Satu-satunya perkara yang tinggal pada perkakasan ialah penyimpanan data, virtualisasi dan sandaran.

Jika anda lebih mempercayai ZFS, maka, pada dasarnya, untuk aplikasi tertentu ia boleh ditukar ganti.

Walau bagaimanapun, pengarang sengaja mengabaikan ciri pencerminan/RAID terbina dalam dan redundansi yang ada pada ZFS, BRTFS dan LVM.

Sebagai hujah tambahan, BTRFS mempunyai keupayaan untuk mengubah penulisan rawak menjadi berurutan, yang mempunyai kesan yang sangat positif pada kelajuan penyegerakan syot kilat / sandaran pada HDD.

Mari kita imbas semula semua peranti:

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

Mari lihat sekeliling:

#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

Susun atur cakera

NVMe SSD

Tetapi kami tidak akan menandai mereka dalam apa cara sekalipun. Bagaimanapun, BIOS kami tidak melihat pemacu ini. Jadi, mereka akan pergi sepenuhnya ke perisian RAID. Kami tidak akan membuat bahagian di sana. Jika anda ingin mengikuti "kanon" atau "terutamanya", buat satu partition besar, seperti HDD.

SATA HDD

Tidak perlu mencipta sesuatu yang istimewa di sini. Kami akan membuat satu bahagian untuk semuanya. Kami akan membuat partition kerana BIOS melihat cakera ini dan mungkin cuba boot daripadanya. Kami juga akan memasang GRUB pada cakera ini kemudian supaya sistem boleh melakukan ini secara tiba-tiba.

#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

SSD SATA

Di sinilah perkara menjadi menarik untuk kita.

Pertama, pemacu kami bersaiz 2 TB. Ini adalah dalam julat yang boleh diterima untuk MBR, yang akan kami gunakan. Jika perlu, boleh digantikan dengan GPT. Cakera GPT mempunyai lapisan keserasian yang membolehkan sistem serasi MBR melihat 4 sekatan pertama jika ia terletak dalam 2 terabait pertama. Perkara utama ialah partition boot dan partition bios_grub pada cakera ini harus berada pada permulaan. Ini malah membolehkan anda but daripada pemacu GPT Legacy/BIOS.

Tetapi ini bukan kes kami.

Di sini kita akan membuat dua bahagian. Yang pertama akan bersaiz 1 GB dan digunakan untuk RAID 1 /boot.

Yang kedua akan digunakan untuk RAID 6 dan akan mengambil semua ruang kosong yang tinggal kecuali untuk kawasan kecil yang tidak diperuntukkan di penghujung pemacu.

Apakah kawasan yang tidak bertanda ini?Menurut sumber pada rangkaian, SSD SATA kami mempunyai cache SLC yang boleh dikembangkan secara dinamik dengan saiz antara 6 hingga 78 gigabait. Kami mendapat 6 gigabait "secara percuma" kerana perbezaan antara "gigabait" dan "gibibait" dalam helaian data pemacu. Baki 72 gigabait diperuntukkan dari ruang yang tidak digunakan.

Di sini perlu diperhatikan bahawa kami mempunyai cache SLC, dan ruang diduduki dalam mod MLC 4 bit. Yang bagi kami berkesan bermakna bahawa untuk setiap 4 gigabait ruang kosong kami hanya akan mendapat 1 gigabait cache SLC.

Darab 72 gigabait dengan 4 dan dapatkan 288 gigabait. Ini adalah ruang kosong yang tidak akan kami tandakan untuk membolehkan pemacu menggunakan sepenuhnya cache SLC.

Oleh itu, kami akan memperoleh sehingga 312 gigabait cache SLC secara berkesan daripada sejumlah enam pemacu. Daripada semua pemacu, 2 akan digunakan dalam RAID untuk lebihan.

Jumlah cache ini akan membolehkan kita sangat jarang dalam kehidupan sebenar menghadapi situasi di mana penulisan tidak pergi ke cache. Ini sangat baik mengimbangi kelemahan memori QLC yang paling menyedihkan - kelajuan tulis yang sangat rendah apabila data ditulis memintas cache. Jika beban anda tidak sepadan dengan ini, maka saya syorkan anda berfikir keras tentang berapa lama SSD anda akan bertahan di bawah beban sedemikian, dengan mengambil kira TBW dari helaian data.

#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

Mencipta Tatasusunan

Pertama, kita perlu menamakan semula mesin itu. Ini perlu kerana nama hos adalah sebahagian daripada nama tatasusunan di suatu tempat di dalam mdadm dan mempengaruhi sesuatu di suatu tempat. Sudah tentu, tatasusunan boleh dinamakan semula kemudian, tetapi ini adalah langkah yang tidak perlu.

#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

Kenapa -anggap-bersih...?Untuk mengelakkan memulakan tatasusunan. Untuk kedua-dua peringkat RAID 1 dan 6 ini sah. Semuanya boleh berfungsi tanpa permulaan jika ia adalah tatasusunan baharu. Selain itu, memulakan tatasusunan SSD semasa penciptaan adalah pembaziran sumber TBW. Kami menggunakan TRIM/DISCARD jika boleh pada tatasusunan SSD yang dipasang untuk "memulakan" mereka.

Untuk tatasusunan SSD, RAID 1 DISCARD disokong di luar kotak.

Untuk tatasusunan SSD RAID 6 DISCARD, anda mesti mendayakannya dalam parameter modul kernel.

Ini hanya perlu dilakukan jika semua SSD yang digunakan dalam tatasusunan tahap 4/5/6 dalam sistem ini mempunyai sokongan yang berfungsi untuk discard_zeroes_data. Kadang-kadang anda menjumpai pemacu aneh yang memberitahu kernel bahawa fungsi ini disokong, tetapi sebenarnya ia tidak ada, atau fungsi itu tidak selalu berfungsi. Pada masa ini, sokongan tersedia hampir di mana-mana, bagaimanapun, terdapat pemacu lama dan perisian tegar dengan ralat. Atas sebab ini, sokongan DISCARD dilumpuhkan secara lalai untuk RAID 6.

Perhatian, arahan berikut akan memusnahkan semua data pada pemacu NVMe dengan "memulakan" tatasusunan dengan "sifar".

#blkdiscard /dev/md0

Jika berlaku kesilapan, cuba nyatakan langkah.

#blkdiscard --step 65536 /dev/md0

SSD SATA

#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

Kenapa besar sangat...?Meningkatkan saiz ketulan mempunyai kesan positif ke atas kelajuan bacaan rawak dalam blok sehingga inklusif saiz ketulan. Ini berlaku kerana satu operasi dengan saiz yang sesuai atau lebih kecil boleh diselesaikan sepenuhnya pada satu peranti. Oleh itu, IOPS dari semua peranti disimpulkan. Mengikut statistik, 99% daripada IO tidak melebihi 512K.

RAID mempunyai 6 IOPS setiap tulis sentiasa kurang daripada atau sama dengan IOPS satu pemacu. Apabila, sebagai bacaan rawak, IOPS boleh menjadi beberapa kali lebih besar daripada satu pemacu, dan di sini saiz blok adalah penting.
Penulis tidak melihat gunanya cuba mengoptimumkan parameter yang tidak baik dalam reka bentuk sampingan RAID 6 dan sebaliknya mengoptimumkan apa yang RAID 6 mahir.
Kami akan memberi pampasan untuk penulisan rawak yang lemah bagi RAID 6 dengan cache NVMe dan helah penyediaan nipis.

Kami belum mendayakan DISCARD untuk RAID 6. Jadi kami tidak akan "memulakan" tatasusunan ini buat masa ini. Kami akan melakukan ini kemudian, selepas memasang OS.

SATA HDD

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

LVM pada NVMe RAID

Untuk kelajuan, kami ingin meletakkan sistem fail akar pada NVMe RAID 1 iaitu /dev/md0.
Walau bagaimanapun, kami masih memerlukan tatasusunan pantas ini untuk keperluan lain, seperti swap, metadata dan LVM-cache dan metadata nipis LVM, jadi kami akan mencipta LVM VG pada tatasusunan ini.

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

Mari buat partition untuk sistem fail root.

#lvcreate -L 128G --name root root

Jom buat partition untuk swapping mengikut saiz RAM.

#lvcreate -L 32G --name swap root

Pemasangan OS

Secara keseluruhan, kami mempunyai segala yang diperlukan untuk memasang sistem.

Lancarkan wizard pemasangan sistem daripada persekitaran Ubuntu Live. Pemasangan biasa. Hanya pada peringkat memilih cakera untuk pemasangan, anda perlu menentukan perkara berikut:

  • /dev/md1, - titik lekap /boot, FS - BTRFS
  • /dev/root/root (aka /dev/mapper/root-root), - titik lekap / (root), FS - BTRFS
  • /dev/root/swap (aka /dev/mapper/root-swap), - gunakan sebagai partition swap
  • Pasang pemuat but pada /dev/sda

Apabila anda memilih BTRFS sebagai sistem fail akar, pemasang akan membuat dua jilid BTRFS secara automatik bernama "@" untuk / (root), dan "@home" untuk /home.

Mari mulakan pemasangan...

Pemasangan akan berakhir dengan kotak dialog modal yang menunjukkan ralat dalam memasang pemuat but. Malangnya, anda tidak akan dapat keluar dari dialog ini menggunakan cara standard dan meneruskan pemasangan. Kami log keluar daripada sistem dan log masuk semula, berakhir dengan desktop Ubuntu Live yang bersih. Buka terminal, dan sekali lagi:

#sudo bash

Cipta persekitaran chroot untuk meneruskan pemasangan:

#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

Mari konfigurasikan rangkaian dan nama hos dalam chroot:

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

Mari kita masuk ke persekitaran chroot:

#chroot /mnt/chroot

Pertama sekali, kami akan menghantar pakej:

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

Mari kita semak dan betulkan semua pakej yang dipasang secara bengkok disebabkan pemasangan sistem yang tidak lengkap:

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

Jika sesuatu tidak berjaya, anda mungkin perlu mengedit /etc/apt/sources.list terlebih dahulu

Mari kita laraskan parameter untuk modul RAID 6 untuk mendayakan TRIM/DISCARD:

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

Mari kita tweak tatasusunan kita sedikit:

#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

Apa tadi..?Kami telah mencipta satu set peraturan udev yang akan melakukan perkara berikut:

  • Tetapkan saiz cache blok untuk RAID 2020 kepada memadai untuk 6. Nilai lalai, nampaknya, tidak berubah sejak penciptaan Linux, dan tidak mencukupi untuk masa yang lama.
  • Simpan minimum IO untuk tempoh pemeriksaan/penyegerakan tatasusunan. Ini adalah untuk mengelakkan tatasusunan anda daripada tersekat dalam keadaan penyegerakan kekal di bawah beban.
  • Hadkan IO maksimum semasa pemeriksaan/penyegerakan tatasusunan. Ini adalah perlu supaya penyegerakan/pemeriksaan SSD RAID tidak menyebabkan pemacu anda menjadi garing. Ini benar terutamanya untuk NVMe. (Ingat tentang radiator? Saya tidak bergurau.)
  • Larang cakera daripada menghentikan putaran gelendong (HDD) melalui APM dan tetapkan tamat masa tidur untuk pengawal cakera kepada 7 jam. Anda boleh melumpuhkan APM sepenuhnya jika pemacu anda boleh melakukannya (-B 255). Dengan nilai lalai, pemacu akan berhenti selepas lima saat. Kemudian OS mahu menetapkan semula cache cakera, cakera akan berputar semula, dan semuanya akan bermula semula. Cakera mempunyai bilangan putaran spindle maksimum yang terhad. Kitaran lalai yang mudah sedemikian boleh membunuh cakera anda dengan mudah dalam beberapa tahun. Tidak semua cakera mengalami ini, tetapi cakera kami adalah "komputer riba", dengan tetapan lalai yang sesuai, yang menjadikan RAID kelihatan seperti PEMBANTU mini.
  • Pasang readahead pada cakera (berputar) 1 megabait - dua blok/ketulan berturut-turut RAID 6
  • Lumpuhkan readahead pada tatasusunan itu sendiri.

Mari edit /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

Kenapa begitu..?Kami akan mencari partition /boot oleh UUID. Penamaan tatasusunan secara teorinya boleh berubah.

Kami akan mencari bahagian yang tinggal dengan nama LVM dalam notasi /dev/mapper/vg-lv, kerana mereka mengenal pasti partition dengan agak unik.

Kami tidak menggunakan UUID untuk LVM kerana UUID volum LVM dan syot kilatnya mungkin sama.Lekapkan /dev/mapper/root-root.. dua kali?ya. Tepat sekali. Ciri BTRFS. Sistem fail ini boleh dipasang beberapa kali dengan subvol yang berbeza.

Disebabkan oleh ciri yang sama ini, saya syorkan jangan sekali-kali membuat petikan LVM bagi volum BTRFS aktif. Anda mungkin mendapat kejutan apabila anda but semula.

Mari kita jana semula konfigurasi mdadm:

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

Mari laraskan tetapan 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

Apa tadi..?Kami telah mendayakan pengembangan automatik kumpulan nipis LVM apabila mencapai 90% daripada ruang yang diduduki sebanyak 5% daripada volum.

Kami telah meningkatkan bilangan maksimum blok cache untuk cache LVM.

Kami telah menghalang LVM daripada mencari volum LVM (PV) pada:

  • peranti yang mengandungi cache LVM (cdata)
  • peranti dicache menggunakan cache LVM, memintas cache ( _corig). Dalam kes ini, peranti cache itu sendiri masih akan diimbas melalui cache (hanya ).
  • peranti yang mengandungi metadata cache LVM (cmeta)
  • semua peranti dalam VG dengan imej nama. Di sini kami akan mempunyai imej cakera mesin maya, dan kami tidak mahu LVM pada hos mengaktifkan volum kepunyaan OS tetamu.
  • semua peranti dalam VG dengan sandaran nama. Di sini kita akan mempunyai salinan sandaran imej mesin maya.
  • semua peranti yang namanya berakhir dengan "gpv" (volume fizikal tetamu)

Kami telah mendayakan sokongan DISCARD apabila mengosongkan ruang kosong pada LVM VG. Berhati-hati. Ini akan menjadikan pemadaman LV pada SSD agak memakan masa. Ini terutama berlaku untuk SSD RAID 6. Walau bagaimanapun, mengikut rancangan, kami akan menggunakan peruntukan yang tipis, jadi ini tidak akan menghalang kami sama sekali.

Mari kemas kini imej initramfs:

#update-initramfs -u -k all

Pasang dan konfigurasikan grub:

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

Cakera mana yang hendak dipilih?Semua yang sd*. Sistem mesti boleh but dari mana-mana pemacu SATA atau SSD yang berfungsi.

Mengapa mereka menambah os-prober..?Untuk kebebasan yang berlebihan dan tangan yang suka bermain.

Ia tidak berfungsi dengan betul jika salah satu RAID berada dalam keadaan terdegradasi. Ia cuba mencari OS pada partition yang digunakan dalam mesin maya yang berjalan pada perkakasan ini.

Jika anda memerlukannya, anda boleh meninggalkannya, tetapi perlu diingat semua perkara di atas. Saya mengesyorkan mencari resipi untuk menghilangkan tangan nakal dalam talian.

Dengan ini kami telah menyelesaikan pemasangan awal. Sudah tiba masanya untuk but semula ke OS yang baru dipasang. Jangan lupa untuk mengalih keluar Live CD/USB boleh boot.

#exit
#reboot

Pilih mana-mana SSD SATA sebagai peranti but.

LVM pada SSD SATA

Pada ketika ini, kami telah pun boot ke dalam OS baharu, mengkonfigurasi rangkaian, apt, membuka emulator terminal, dan menjalankan:

#sudo bash

Jom sambung.

"Memulakan" tatasusunan daripada SATA SSD:

#blkdiscard /dev/md2

Jika ia tidak berjaya, cuba:

#blkdiscard --step 65536 /dev/md2
Buat LVM VG pada SATA SSD:

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

Kenapa VG lain..?Sebenarnya, kami sudah mempunyai VG bernama root. Mengapa tidak menambah semuanya ke dalam satu VG?

Jika terdapat beberapa PV dalam VG, maka untuk VG diaktifkan dengan betul, semua PV mesti ada (dalam talian). Pengecualian ialah LVM RAID, yang kami sengaja tidak gunakan.

Kami benar-benar mahu jika terdapat kegagalan (baca kehilangan data) pada mana-mana tatasusunan RAID 6, sistem pengendalian akan boot secara normal dan memberi kami peluang untuk menyelesaikan masalah tersebut.

Untuk melakukan ini, pada tahap abstraksi pertama kami akan mengasingkan setiap jenis "media" fizikal ke dalam VG yang berasingan.

Secara saintifiknya, tatasusunan RAID yang berbeza tergolong dalam "domain kebolehpercayaan" yang berbeza. Anda tidak seharusnya mencipta titik kegagalan biasa tambahan untuk mereka dengan menjejalkannya ke dalam satu VG.

Kehadiran LVM pada tahap "perkakasan" akan membolehkan kami memotong kepingan tatasusunan RAID yang berbeza dengan sewenang-wenangnya dengan menggabungkannya dalam cara yang berbeza. Contohnya - lari serentak bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, konfigurasi ZFS yang kompleks dengan cache atau mana-mana campuran neraka lain untuk mencuba dan membandingkan semuanya.

Pada peringkat "perkakasan", kami tidak akan menggunakan apa-apa selain daripada volum LVM "tebal" lama yang baik. Pengecualian kepada peraturan ini mungkin partition sandaran.

Saya rasa pada masa ini, ramai pembaca sudah mula mengesyaki sesuatu tentang anak patung bersarang itu.

LVM pada HDD SATA

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

VG baru lagi..?Kami benar-benar mahu jika tatasusunan cakera yang akan kami gunakan untuk sandaran data gagal, sistem pengendalian kami akan terus berfungsi seperti biasa, sambil mengekalkan akses kepada data bukan sandaran seperti biasa. Oleh itu, untuk mengelakkan masalah pengaktifan VG, kami mencipta VG yang berasingan.

Menyediakan cache LVM

Mari buat LV pada NVMe RAID 1 untuk menggunakannya sebagai peranti caching.

#lvcreate -L 70871154688B --name cache root

Kenapa sedikit...?Hakikatnya ialah SSD NVMe kami juga mempunyai cache SLC. 4 gigabait "percuma" dan 18 gigabait dinamik kerana ruang kosong yang diduduki dalam MLC 3-bit. Setelah cache ini habis, SSD NVMe tidak akan lebih pantas daripada SSD SATA kami dengan cache. Sebenarnya, atas sebab ini, tidak masuk akal untuk kita menjadikan partition cache LVM lebih besar daripada dua kali ganda saiz cache SLC pemacu NVMe. Untuk pemacu NVMe yang digunakan, penulis menganggap adalah munasabah untuk membuat 32-64 gigabait cache.

Saiz partition yang diberikan diperlukan untuk menyusun 64 gigabait cache, metadata cache dan sandaran metadata.

Selain itu, saya perhatikan bahawa selepas penutupan sistem yang kotor, LVM akan menandakan keseluruhan cache sebagai kotor dan akan menyegerakkan semula. Selain itu, ini akan diulang setiap kali lvchange digunakan pada peranti ini sehingga sistem dibut semula. Oleh itu, saya mengesyorkan untuk mencipta semula cache dengan segera menggunakan skrip yang sesuai.

Mari buat LV pada SATA RAID 6 untuk menggunakannya sebagai peranti cache.

#lvcreate -L 3298543271936B --name cache data

Mengapa hanya tiga terabait..?Jadi, jika perlu, anda boleh menggunakan SATA SSD RAID 6 untuk beberapa keperluan lain. Saiz ruang cache boleh ditingkatkan secara dinamik, dengan cepat, tanpa menghentikan sistem. Untuk melakukan ini, anda perlu menghentikan sementara dan mendayakan semula cache, tetapi kelebihan tersendiri LVM-cache berbanding, sebagai contoh, bcache ialah ini boleh dilakukan dengan cepat.

Mari buat VG baharu untuk caching.

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

Mari buat LV pada peranti cache.

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

Di sini kami segera mengambil semua ruang kosong pada /dev/data/cache supaya semua partition lain yang diperlukan dibuat serta-merta pada /dev/root/cache. Jika anda mencipta sesuatu di tempat yang salah, anda boleh mengalihkannya menggunakan pvmove.

Mari buat dan dayakan cache:

#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

Kenapa chunksize begitu..?Melalui eksperimen amali, penulis dapat mengetahui bahawa hasil terbaik dicapai sekiranya saiz blok cache LVM bertepatan dengan saiz blok nipis LVM. Selain itu, lebih kecil saiznya, lebih baik prestasi konfigurasi dalam rakaman rawak.

64k ialah saiz blok minimum yang dibenarkan untuk LVM nipis.

Berhati-hati menulis balik..!ya. Cache jenis ini menangguhkan penyegerakan tulis ke peranti cache. Ini bermakna jika cache hilang, anda mungkin kehilangan data pada peranti cache. Kemudian, penulis akan memberitahu anda apakah langkah, sebagai tambahan kepada NVMe RAID 1, boleh diambil untuk mengimbangi risiko ini.

Jenis cache ini dipilih secara sengaja untuk mengimbangi prestasi penulisan rawak yang lemah bagi RAID 6.

Mari semak apa yang kami dapat:

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

Hanya [cachedata_corig] harus terletak pada /dev/data/cache. Jika ada yang salah, gunakan pvmove.

Anda boleh melumpuhkan cache jika perlu dengan satu arahan:

#lvconvert -y --uncache cache/cachedata

Ini dilakukan dalam talian. LVM hanya akan menyegerakkan cache ke cakera, mengalih keluarnya dan menamakan semula cachedata_corig kembali kepada cachedata.

Menyediakan LVM nipis

Mari kita anggaran secara kasar berapa banyak ruang yang kita perlukan untuk metadata nipis 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"

Bundarkan kepada 4 gigabait: 4294967296B

Darab dengan dua dan tambah 4194304B untuk metadata PV LVM: 8594128896B
Mari buat partition berasingan pada NVMe RAID 1 untuk meletakkan metadata nipis LVM dan salinan sandarannya padanya:

#lvcreate -L 8594128896B --name images root

Untuk apa..?Di sini persoalan mungkin timbul: mengapa meletakkan metadata nipis LVM secara berasingan jika ia masih akan dicache pada NVMe dan akan berfungsi dengan cepat.

Walaupun kelajuan adalah penting di sini, ia jauh dari sebab utama. Masalahnya ialah cache adalah titik kegagalan. Sesuatu boleh berlaku padanya, dan jika metadata nipis LVM dicache, ia akan menyebabkan semuanya hilang sepenuhnya. Tanpa metadata lengkap, hampir mustahil untuk memasang volum nipis.

Dengan mengalihkan metadata ke volum berasingan bukan cache, tetapi pantas, kami menjamin keselamatan metadata sekiranya berlaku kehilangan atau kerosakan cache. Dalam kes ini, semua kerosakan yang disebabkan oleh kehilangan cache akan disetempatkan dalam jilid nipis, yang akan memudahkan prosedur pemulihan mengikut urutan magnitud. Dengan kebarangkalian yang tinggi, kerosakan ini akan dipulihkan menggunakan log FS.

Lebih-lebih lagi, jika syot kilat volum nipis telah diambil sebelum ini, dan selepas itu cache disegerakkan sepenuhnya sekurang-kurangnya sekali, maka, disebabkan reka bentuk dalaman LVM nipis, integriti syot kilat akan terjamin sekiranya kehilangan cache .

Mari buat VG baharu yang akan bertanggungjawab untuk penyediaan tipis:

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

Mari buat kolam:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Mengapa -Z ySebagai tambahan kepada tujuan sebenar mod ini - untuk mengelakkan data daripada satu mesin maya daripada bocor ke mesin maya yang lain apabila mengagihkan semula ruang - sifar juga digunakan untuk meningkatkan kelajuan penulisan rawak dalam blok yang lebih kecil daripada 64k. Sebarang tulis kurang daripada 64k ke kawasan volum nipis yang tidak diperuntukkan sebelum ini akan menjadi 64K sejajar tepi dalam cache. Ini akan membolehkan operasi dilakukan sepenuhnya melalui cache, memintas peranti cache.

Mari kita alihkan LV ke PV yang sepadan:

#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

Mari semak:

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

Mari buat volum nipis untuk ujian:

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

Kami akan memasang pakej untuk ujian dan pemantauan:

#apt-get install sysstat fio

Beginilah cara anda boleh melihat gelagat konfigurasi storan kami dalam masa nyata:

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

Inilah cara kami boleh menguji konfigurasi kami:

#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

Berhati-hati! Sumber!Kod ini akan menjalankan 36 ujian berbeza, setiap satu berjalan selama 4 saat. Separuh daripada ujian adalah untuk rakaman. Anda boleh merakam banyak pada NVMe dalam 4 saat. Sehingga 3 gigabait sesaat. Jadi, setiap ujian penulisan boleh memakan sehingga 216 gigabait sumber SSD daripada anda.

Membaca dan menulis bercampur?ya. Adalah masuk akal untuk menjalankan ujian baca dan tulis secara berasingan. Selain itu, masuk akal untuk memastikan semua cache disegerakkan supaya penulisan yang dibuat sebelum ini tidak menjejaskan bacaan.

Hasilnya akan sangat berbeza semasa pelancaran pertama dan seterusnya apabila cache dan volum nipis diisi, dan juga bergantung pada sama ada sistem berjaya menyegerakkan cache yang diisi semasa pelancaran terakhir.

Antara lain, saya mengesyorkan mengukur kelajuan pada volum nipis yang sudah penuh yang mana syot kilat baru diambil. Penulis berpeluang memerhatikan bagaimana penulisan rawak memecut dengan mendadak sejurus selepas mencipta syot kilat pertama, terutamanya apabila cache belum penuh sepenuhnya. Ini berlaku disebabkan oleh semantik tulis salin atas tulis, penjajaran cache dan blok volum nipis, dan fakta bahawa penulisan rawak ke RAID 6 bertukar menjadi bacaan rawak daripada RAID 6 diikuti dengan tulis ke cache. Dalam konfigurasi kami, bacaan rawak daripada RAID 6 adalah sehingga 6 kali ganda (bilangan SSD SATA dalam tatasusunan) lebih pantas daripada menulis. Kerana blok untuk CoW diperuntukkan secara berurutan daripada kumpulan nipis, kemudian rakaman, sebahagian besarnya, juga bertukar menjadi berurutan.

Kedua-dua ciri ini boleh digunakan untuk kelebihan anda.

Cache syot kilat "koheren".

Untuk mengurangkan risiko kehilangan data sekiranya berlaku kerosakan/kehilangan cache, penulis mencadangkan untuk memperkenalkan amalan snapshot berputar bagi menjamin integritinya dalam kes ini.

Pertama, kerana metadata volum nipis berada pada peranti yang tidak dicache, metadata akan konsisten dan kemungkinan kehilangan akan diasingkan dalam blok data.

Kitaran putaran syot kilat berikut menjamin integriti data di dalam syot kilat sekiranya kehilangan cache:

  1. Untuk setiap kelantangan nipis dengan nama <nama>, buat syot kilat dengan nama <name>.cached
  2. Mari kita tetapkan ambang migrasi kepada nilai tinggi yang munasabah: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Dalam gelung kami menyemak bilangan blok kotor dalam cache: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' sehingga kita mendapat sifar. Jika sifar hilang terlalu lama, ia boleh dibuat dengan menukar cache kepada mod tulis lalu buat sementara waktu. Walau bagaimanapun, dengan mengambil kira ciri-ciri kelajuan susunan SATA dan NVMe SSD kami, serta sumber TBW mereka, anda sama ada akan dapat menangkap masa dengan cepat tanpa menukar mod cache, atau perkakasan anda akan memakan sepenuhnya keseluruhan sumbernya dalam beberapa hari. Disebabkan oleh keterbatasan sumber, sistem, pada dasarnya, tidak boleh berada di bawah 100% beban tulis sepanjang masa. SSD NVMe kami di bawah 100% beban tulis akan meletihkan sepenuhnya sumber itu hari 3-4. SSD SATA hanya akan bertahan dua kali lebih lama. Oleh itu, kami akan menganggap bahawa kebanyakan beban pergi ke bacaan, dan kami mempunyai letusan jangka pendek aktiviti yang sangat tinggi digabungkan dengan beban rendah secara purata untuk menulis.
  4. Sebaik sahaja kami menangkap (atau membuat) sifar, kami menamakan semula <name>.cached kepada <name>.committed. <name>.committed lama dipadamkan.
  5. Secara pilihan, jika cache 100% penuh, ia boleh dicipta semula dengan skrip, sekali gus mengosongkannya. Dengan cache separuh kosong, sistem berfungsi lebih pantas semasa menulis.
  6. Tetapkan ambang migrasi kepada sifar: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Ini akan menghalang cache daripada menyegerak ke media utama buat sementara waktu.
  7. Kami menunggu sehingga banyak perubahan terkumpul dalam cache #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' atau pemasa akan berbunyi.
  8. Kita ulang lagi.

Mengapa kesukaran dengan ambang penghijrahan...?Masalahnya ialah dalam amalan sebenar, rakaman "rawak" sebenarnya tidak sepenuhnya rawak. Jika kita menulis sesuatu pada sektor bersaiz 4 kilobait, terdapat kebarangkalian tinggi bahawa dalam beberapa minit akan datang rekod akan dibuat kepada sektor yang sama atau salah satu daripada sektor yang berdekatan (+- 32K).

Dengan menetapkan ambang migrasi kepada sifar, kami menangguhkan penyegerakan tulis pada SSD SATA dan mengagregatkan beberapa perubahan kepada satu blok 64K dalam cache. Ini menjimatkan sumber SSD SATA dengan ketara.

Mana kodnya..?Malangnya, penulis menganggap dirinya tidak cukup cekap dalam pembangunan skrip bash kerana dia 100% otodidak dan mengamalkan pembangunan yang didorong oleh "google", oleh itu dia percaya bahawa kod mengerikan yang keluar dari tangannya tidak boleh digunakan oleh sesiapa pun lain.

Saya fikir bahawa profesional dalam bidang ini akan dapat menggambarkan secara bebas semua logik yang diterangkan di atas, jika perlu, dan, mungkin, bahkan mereka bentuknya dengan indah sebagai perkhidmatan systemd, seperti yang cuba dilakukan oleh pengarang.

Skim putaran syot kilat yang mudah sedemikian akan membolehkan kami bukan sahaja sentiasa mempunyai satu syot kilat disegerakkan sepenuhnya pada SSD SATA, tetapi juga akan membolehkan kami, menggunakan utiliti thin_delta, untuk mengetahui blok mana yang telah ditukar selepas penciptaannya, dan dengan itu menyetempatkan kerosakan pada jilid utama, sangat memudahkan pemulihan .

TRIM/DISCARD dalam libvirt/KVM

Kerana storan data akan digunakan untuk KVM menjalankan libvirt, maka adalah idea yang baik untuk mengajar VM kami bukan sahaja untuk menggunakan ruang kosong, tetapi juga untuk mengosongkan perkara yang tidak diperlukan lagi.

Ini dilakukan dengan meniru sokongan TRIM/DISCARD pada cakera maya. Untuk melakukan ini, anda perlu menukar jenis pengawal kepada virtio-scsi dan mengedit 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 sedemikian daripada OS tetamu diproses dengan betul oleh LVM, dan blok dibebaskan dengan betul dalam cache dan dalam kumpulan nipis. Dalam kes kami, ini berlaku terutamanya dalam cara yang tertangguh, apabila memadamkan syot kilat seterusnya.

Sandaran BTRFS

Gunakan skrip siap pakai dengan melampau berhati-hati dan atas risiko seseorang. Penulis menulis kod ini sendiri dan secara eksklusif untuk dirinya sendiri. Saya pasti ramai pengguna Linux berpengalaman mempunyai alatan yang serupa, dan tidak perlu menyalin alat orang lain.

Mari buat volum pada peranti sandaran:

#lvcreate -L 256G --name backup backup

Mari formatkannya dalam BTRFS:

#mkfs.btrfs /dev/backup/backup

Mari buat titik lekap dan lekapkan subseksyen akar sistem fail:

#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

Mari buat direktori untuk sandaran:

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

Mari buat direktori untuk skrip sandaran:

#mkdir /root/btrfs-backup

Mari salin skrip:

Banyak kod bash yang menakutkan. Gunakan atas risiko anda sendiri. Jangan tulis surat marah kepada penulis...#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

Apa yang ia lakukan..?Mengandungi satu set arahan mudah untuk mencipta syot kilat BTRFS dan menyalinnya ke FS lain menggunakan hantar/terima BTRFS.

Pelancaran pertama mungkin agak lama, kerana... Pada mulanya, semua data akan disalin. Pelancaran selanjutnya akan menjadi sangat pantas, kerana... Hanya perubahan akan disalin.

Skrip lain yang akan kami masukkan ke dalam cron:

Beberapa lagi kod 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

Apa yang dilakukannya..?Mencipta dan menyegerakkan syot kilat tambahan bagi volum BTRFS yang disenaraikan pada FS sandaran. Selepas ini, ia memadam semua gambar yang dibuat 60 hari yang lalu. Selepas pelancaran, syot kilat bertarikh volum tersenarai akan muncul dalam subdirektori /backup/btrfs/back/remote/.

Mari berikan hak pelaksanaan kod:

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

Mari kita periksa dan masukkan ke dalam cron:

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

Sandaran nipis LVM

Mari buat kumpulan nipis pada peranti sandaran:

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

Mari pasang ddrescue, kerana... skrip akan menggunakan alat ini:

#apt-get install gddrescue

Mari buat direktori untuk skrip:

#mkdir /root/lvm-thin-backup

Mari salin skrip:

Banyak bash dalam...#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

Apa yang dilakukannya...?Mengandungi satu set perintah untuk memanipulasi syot kilat nipis dan menyegerakkan perbezaan antara dua syot kilat nipis yang diterima melalui thin_delta ke peranti blok lain menggunakan ddrescue dan blkdiscard.

Skrip lain yang akan kami masukkan ke dalam cron:

Sikit lagi 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

Apa yang dilakukannya...?Menggunakan skrip sebelumnya untuk mencipta dan menyegerakkan sandaran volum nipis yang disenaraikan. Skrip akan meninggalkan syot kilat tidak aktif bagi volum tersenarai, yang diperlukan untuk menjejaki perubahan sejak penyegerakan terakhir.

Skrip ini mesti diedit, menyatakan senarai jilid nipis yang mana salinan sandaran perlu dibuat. Nama-nama yang diberikan adalah untuk tujuan ilustrasi sahaja. Jika anda mahu, anda boleh menulis skrip yang akan menyegerakkan semua jilid.

Mari berikan hak:

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

Mari kita periksa dan masukkan ke dalam cron:

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

Pelancaran pertama akan lama, kerana... volum nipis akan disegerakkan sepenuhnya dengan menyalin semua ruang yang digunakan. Terima kasih kepada metadata nipis LVM, kami tahu blok mana yang sebenarnya sedang digunakan, jadi hanya blok volum nipis yang digunakan sebenarnya akan disalin.

Larian berikutnya akan menyalin data secara berperingkat berkat perubahan penjejakan melalui metadata nipis LVM.

Mari lihat apa yang berlaku:

#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

Apa kaitannya dengan anak patung bersarang?

Kemungkinan besar, memandangkan volum logik LVM LV boleh menjadi volum fizikal PV LVM untuk VG lain. LVM boleh menjadi rekursif, seperti anak patung bersarang. Ini memberikan fleksibiliti melampau LVM.

PS

Dalam artikel seterusnya, kami akan cuba menggunakan beberapa sistem storan mudah alih/KVM yang serupa sebagai asas untuk mencipta kluster storan/vm teragih geo dengan redundansi di beberapa benua menggunakan desktop rumah, Internet rumah dan rangkaian P2P.

Sumber: www.habr.com

Tambah komen