Apa persamaan LVM dan Matryoshka?

Selamat sore.
Saya ingin berbagi dengan komunitas pengalaman praktis saya dalam membangun sistem penyimpanan data untuk KVM menggunakan md RAID + LVM.

Program ini akan mencakup:

  • Membangun md RAID 1 dari NVMe SSD.
  • Merakit md RAID 6 dari SATA SSD dan drive biasa.
  • Fitur operasi TRIM/DISCARD pada SSD RAID 1/6.
  • Membuat array md RAID 1/6 yang dapat di-boot pada kumpulan disk umum.
  • Menginstal sistem pada NVMe RAID 1 ketika tidak ada dukungan NVMe di BIOS.
  • Menggunakan LVM cache dan LVM tipis.
  • Menggunakan snapshot BTRFS dan kirim/terima untuk cadangan.
  • Menggunakan snapshot tipis LVM dan thin_delta untuk pencadangan gaya BTRFS.

Jika Anda tertarik, silakan lihat kucing.

Pernyataan

Penulis tidak bertanggung jawab atas akibat menggunakan atau tidak menggunakan bahan/contoh/kode/tips/data dari artikel ini. Dengan membaca atau menggunakan materi ini dengan cara apa pun, Anda bertanggung jawab atas segala akibat dari tindakan tersebut. Konsekuensi yang mungkin terjadi meliputi:

  • SSD NVMe yang digoreng renyah.
  • Sumber daya perekaman benar-benar habis dan kegagalan drive SSD.
  • Hilangnya seluruh data di semua drive, termasuk salinan cadangan.
  • Perangkat keras komputer rusak.
  • Buang-buang waktu, saraf, dan uang.
  • Konsekuensi lain yang tidak tercantum di atas.

Besi

Tersedia adalah:

Motherboard sekitar tahun 2013 dengan chipset Z87, lengkap dengan Intel Core i7/Haswell.

  • Prosesor 4 core, 8 thread
  • RAM DDR32 3GB
  • 1x16 atau 2x8 PCIe 3.0
  • 1x4 + 1x1 PCIe 2.0
  • Konektor SATA 6 6 x 3 GBps

Adaptor SAS LSI SAS9211-8Saya mem-flash ke mode IT / HBA. Firmware berkemampuan RAID sengaja diganti dengan firmware HBA untuk:

  1. Anda dapat membuang adaptor ini kapan saja dan menggantinya dengan adaptor lain yang Anda temukan.
  2. TRIM/Discard berfungsi normal pada disk, karena... dalam firmware RAID, perintah ini tidak didukung sama sekali, dan HBA, secara umum, tidak peduli perintah apa yang dikirimkan melalui bus.

Harddisk - 8 buah HGST Travelstar 7K1000 berkapasitas 1 TB dalam form faktor 2.5, seperti untuk laptop. Drive ini sebelumnya berada dalam array RAID 6. Mereka juga akan berguna dalam sistem baru. Untuk menyimpan cadangan lokal.

Selain itu ditambahkan:

6 buah SATA SSD model Samsung 860 QVO 2TB. SSD ini membutuhkan volume yang besar, keberadaan cache SLC, keandalan, dan harga yang murah adalah hal yang diinginkan. Dukungan untuk membuang/nol diperlukan, yang diperiksa oleh baris di dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

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

Untuk SSD ini, kecepatan baca/tulis acak dan kapasitas sumber daya untuk kebutuhan Anda adalah hal yang penting. Radiator untuk mereka. Perlu. Sangat. Jika tidak, goreng hingga renyah selama sinkronisasi RAID pertama.

Adaptor StarTech PEX8M2E2 untuk 2 x NVMe SSD dipasang di slot PCIe 3.0 8x. Ini, sekali lagi, hanyalah HBA, tapi untuk NVMe. Ini berbeda dari adaptor murah karena tidak memerlukan dukungan bifurkasi PCIe dari motherboard karena adanya saklar PCIe bawaan. Ini akan berfungsi bahkan pada sistem paling kuno dengan PCIe, meskipun itu adalah slot x1 PCIe 1.0. Tentu saja, dengan kecepatan yang sesuai. Tidak ada RAID di sana. Tidak ada BIOS bawaan di dalamnya. Jadi, sistem Anda tidak akan secara ajaib belajar melakukan booting dengan NVMe, apalagi melakukan NVMe RAID berkat perangkat ini.

Komponen ini semata-mata karena hanya terdapat satu 8x PCIe 3.0 gratis di sistem, dan jika ada 2 slot kosong, dapat dengan mudah diganti dengan dua sen PEX4M2E1 atau analog, yang dapat dibeli di mana saja dengan harga 600. rubel.

Penolakan terhadap segala jenis perangkat keras atau RAID chipset/BIOS bawaan dilakukan dengan sengaja, agar dapat sepenuhnya menggantikan keseluruhan sistem, kecuali SSD/HDD itu sendiri, dengan tetap menjaga semua data. Idealnya, agar Anda dapat menyimpan bahkan sistem operasi yang diinstal saat berpindah ke perangkat keras yang benar-benar baru/berbeda. Yang penting ada port SATA dan PCIe. Ini seperti live CD atau flash drive yang dapat di-boot, hanya saja sangat cepat dan sedikit besar.

ЮморJika tidak, Anda tahu apa yang terjadi - terkadang Anda harus segera membawa seluruh rangkaian untuk dibawa pulang. Tapi saya tidak ingin kehilangan data. Untuk melakukan ini, semua media yang disebutkan ditempatkan dengan nyaman pada slide dalam wadah standar 5.25 bay.

Dan, tentu saja, untuk bereksperimen dengan berbagai metode caching SSD di Linux.

Penggerebekan perangkat keras itu membosankan. Hidupkan. Entah itu berhasil atau tidak. Dan dengan mdadm selalu ada pilihan.

Perangkat lunak

Sebelumnya Debian 8 Jessie diinstal pada hardware yang mendekati EOL. RAID 6 dirakit dari HDD yang disebutkan di atas yang dipasangkan dengan LVM. Itu menjalankan mesin virtual di kvm/libvirt.

Karena Penulis memiliki pengalaman yang sesuai dalam membuat flash drive SATA/NVMe portabel yang dapat di-boot, dan juga, agar tidak merusak template apt yang biasa, Ubuntu 18.04 dipilih sebagai sistem target, yang sudah cukup stabil, namun masih memiliki 3 tahun masa pakai. dukungan di masa depan.

Sistem yang disebutkan berisi semua driver perangkat keras yang kami butuhkan. Kami tidak memerlukan perangkat lunak atau driver pihak ketiga.

Persiapan untuk instalasi

Untuk menginstal sistem kita memerlukan Ubuntu Desktop Image. Sistem server memiliki semacam penginstal yang kuat, yang menunjukkan independensi berlebihan yang tidak dapat dinonaktifkan dengan memasukkan partisi sistem UEFI ke salah satu disk, merusak semua keindahan. Oleh karena itu, ini hanya diinstal dalam mode UEFI. Tidak menawarkan opsi apa pun.

Kami tidak senang dengan ini.

Kenapa?Sayangnya, boot UEFI sangat kurang kompatibel dengan perangkat lunak boot RAID, karena... Tidak ada yang menawarkan kami reservasi untuk partisi UEFI ESP. Ada resep di Internet yang menyarankan untuk menempatkan partisi ESP pada flash drive di port USB, tetapi ini adalah titik kegagalan. Ada resep menggunakan perangkat lunak mdadm RAID 1 dengan metadata versi 0.9 yang tidak mencegah UEFI BIOS melihat partisi ini, tetapi ini bertahan hingga saat bahagia ketika BIOS atau OS perangkat keras lain menulis sesuatu ke ESP dan lupa menyinkronkannya ke yang lain cermin.

Selain itu, boot UEFI bergantung pada NVRAM, yang tidak akan berpindah bersama disk ke sistem baru, karena merupakan bagian dari motherboard.

Jadi, kami tidak akan menciptakan roda baru. Kami telah memiliki sepeda kakek yang sudah jadi dan telah teruji waktu, yang sekarang disebut boot Legacy/BIOS, dengan nama bangga CSM pada sistem yang kompatibel dengan UEFI. Kita tinggal melepasnya dari rak, melumasinya, memompa bannya dan menyekanya dengan kain lembab.

Versi desktop Ubuntu juga tidak dapat diinstal dengan benar dengan bootloader Legacy, tetapi di sini, seperti yang mereka katakan, setidaknya ada opsi.

Jadi, kami mengumpulkan perangkat keras dan memuat sistem dari flash drive flash Ubuntu Live yang dapat di-boot. Kami perlu mengunduh paket, jadi kami akan menyiapkan jaringan yang sesuai untuk Anda. Jika tidak berhasil, Anda dapat memuat paket yang diperlukan ke flash drive terlebih dahulu.

Kita masuk ke lingkungan Desktop, meluncurkan emulator terminal, dan berangkat:

#sudo bash

Bagaimana…?Baris di atas adalah pemicu kanonik untuk holiwar tentang sudo. C bоpeluang lebih besar datang danоtanggung jawab yang lebih besar. Pertanyaannya adalah apakah Anda bisa menanggungnya sendiri. Banyak orang yang menganggap penggunaan sudo dengan cara ini setidaknya tidak hati-hati. Namun:

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

Mengapa tidak ZFS...?Saat kami menginstal perangkat lunak di komputer kami, pada dasarnya kami meminjamkan perangkat keras kami kepada pengembang perangkat lunak tersebut untuk menjalankannya.
Ketika kami memercayai perangkat lunak ini dengan keamanan data kami, kami mengambil pinjaman sebesar biaya pemulihan data ini, yang harus kami bayar suatu hari nanti.

Dari sudut pandang ini, ZFS adalah Ferrari, dan mdadm+lvm lebih mirip sepeda.

Secara subyektif, penulis lebih memilih meminjamkan sepeda secara kredit kepada orang tak dikenal dibandingkan Ferrari. Di sana, harga masalah ini tidak mahal. Tidak perlu hak. Lebih sederhana dari peraturan lalu lintas. Parkir tersedia gratis. Kemampuan lintas negara lebih baik. Anda selalu dapat memasang kaki ke sepeda, dan Anda dapat memperbaiki sepeda dengan tangan Anda sendiri.

Lalu mengapa BTRFS...?Untuk mem-boot sistem operasi, kita memerlukan sistem file yang didukung di Legacy/BIOS GRUB, dan pada saat yang sama mendukung snapshot langsung. Kami akan menggunakannya untuk partisi /boot. Selain itu, penulis lebih suka menggunakan FS ini untuk / (root), tidak lupa mencatat bahwa untuk perangkat lunak lain Anda dapat membuat partisi terpisah di LVM dan memasangnya di direktori yang diperlukan.

Kami tidak akan menyimpan gambar mesin virtual atau database apa pun di FS ini.
FS ini hanya akan digunakan untuk membuat snapshot sistem tanpa mematikannya dan kemudian mentransfer snapshot tersebut ke disk cadangan menggunakan kirim/terima.

Selain itu, penulis umumnya lebih memilih untuk menyimpan perangkat lunak minimum secara langsung pada perangkat keras dan menjalankan semua perangkat lunak lainnya di mesin virtual menggunakan hal-hal seperti meneruskan GPU dan pengontrol Host PCI-USB ke KVM melalui IOMMU.

Satu-satunya hal yang tersisa di perangkat keras adalah penyimpanan data, virtualisasi, dan pencadangan.

Jika Anda lebih mempercayai ZFS, maka, pada prinsipnya, untuk aplikasi tertentu keduanya dapat dipertukarkan.

Namun penulis sengaja mengabaikan fitur mirroring/RAID dan redundansi bawaan yang dimiliki ZFS, BRTFS, dan LVM.

Sebagai argumen tambahan, BTRFS memiliki kemampuan untuk mengubah penulisan acak menjadi penulisan berurutan, yang memiliki efek sangat positif pada kecepatan sinkronisasi snapshot/cadangan pada HDD.

Mari pindai ulang semua perangkat:

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

Mari kita melihat-lihat:

#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

Tata letak disk

NVMe SSD

Tapi kami tidak akan menandainya dengan cara apa pun. Bagaimanapun, BIOS kita tidak melihat drive ini. Jadi, mereka akan sepenuhnya beralih ke RAID perangkat lunak. Kami bahkan tidak akan membuat bagian di sana. Jika Anda ingin mengikuti “kanon” atau “prinsipnya”, buatlah satu partisi besar, seperti HDD.

HDD SATA

Tidak perlu menciptakan sesuatu yang istimewa di sini. Kami akan membuat satu bagian untuk semuanya. Kami akan membuat partisi karena BIOS melihat disk ini dan bahkan mungkin mencoba melakukan booting dari disk tersebut. Kami bahkan akan menginstal GRUB pada disk ini nanti sehingga sistem dapat melakukan hal 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 hal-hal menjadi menarik bagi kami.

Pertama, drive kami berukuran 2 TB. Ini berada dalam kisaran yang dapat diterima untuk MBR, yang akan kami gunakan. Jika perlu, bisa diganti dengan GPT. Disk GPT memiliki lapisan kompatibilitas yang memungkinkan sistem yang kompatibel dengan MBR melihat 4 partisi pertama jika berada dalam 2 terabyte pertama. Hal utama adalah partisi boot dan partisi bios_grub pada disk ini harus berada di awal. Ini bahkan memungkinkan Anda melakukan booting dari drive GPT Legacy/BIOS.

Tapi ini bukan kasus kami.

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

Yang kedua akan digunakan untuk RAID 6 dan akan menggunakan semua ruang kosong yang tersisa kecuali area kecil yang tidak terisi di ujung drive.

Apa area yang tidak ditandai ini?Menurut sumber di jaringan, SSD SATA kami memiliki cache SLC yang dapat diperluas secara dinamis dengan ukuran mulai dari 6 hingga 78 gigabyte. Kami mendapatkan 6 gigabyte “gratis” karena perbedaan antara “gigabytes” dan “gibibytes” di lembar data drive. Sisanya 72 gigabyte dialokasikan dari ruang yang tidak terpakai.

Di sini perlu dicatat bahwa kami memiliki cache SLC, dan ruang tersebut ditempati dalam mode MLC 4 bit. Yang bagi kami secara efektif berarti bahwa untuk setiap 4 gigabyte ruang kosong kami hanya akan mendapatkan 1 gigabyte cache SLC.

Kalikan 72 gigabyte dengan 4 dan dapatkan 288 gigabyte. Ini adalah ruang kosong yang tidak akan kami tandai agar drive dapat memanfaatkan cache SLC sepenuhnya.

Dengan demikian, kami secara efektif akan mendapatkan cache SLC hingga 312 gigabyte dari total enam drive. Dari semua drive, 2 akan digunakan dalam RAID untuk redundansi.

Jumlah cache ini akan memungkinkan kita untuk sangat jarang menghadapi situasi di kehidupan nyata di mana penulisan tidak masuk ke cache. Ini mengkompensasi kelemahan paling menyedihkan dari memori QLC dengan sangat baik - kecepatan tulis yang sangat rendah saat data ditulis tanpa melewati cache. Jika beban Anda tidak sesuai dengan ini, saya sarankan Anda berpikir keras tentang berapa lama SSD Anda akan bertahan di bawah beban seperti itu, dengan mempertimbangkan TBW dari lembar 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

Membuat Array

Pertama, kita perlu mengganti nama mesin. Hal ini diperlukan karena nama host adalah bagian dari nama array di suatu tempat di dalam mdadm dan mempengaruhi sesuatu di suatu tempat. Tentu saja, array dapat diganti namanya nanti, tapi 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

Mengapa -berasumsi-bersih...?Untuk menghindari inisialisasi array. Untuk RAID level 1 dan 6, hal ini valid. Semuanya dapat bekerja tanpa inisialisasi jika itu adalah array baru. Selain itu, menginisialisasi susunan SSD saat pembuatan adalah pemborosan sumber daya TBW. Kami menggunakan TRIM/DISCARD jika memungkinkan pada susunan SSD yang dirakit untuk “menginisialisasi” mereka.

Untuk susunan SSD, RAID 1 DISCARD langsung didukung.

Untuk array SSD RAID 6 DISCARD, Anda harus mengaktifkannya di parameter modul kernel.

Ini hanya boleh dilakukan jika semua SSD yang digunakan dalam array level 4/5/6 di sistem ini memiliki dukungan yang berfungsi untuk membuang_zeroes_data. Terkadang Anda menemukan drive aneh yang memberi tahu kernel bahwa fungsi ini didukung, tetapi kenyataannya tidak ada, atau fungsi tersebut tidak selalu berfungsi. Saat ini, dukungan tersedia hampir di semua tempat, namun ada drive dan firmware lama yang mengalami kesalahan. Karena alasan ini, dukungan DISCARD dinonaktifkan secara default untuk RAID 6.

Perhatian, perintah berikut akan menghancurkan semua data di drive NVMe dengan “menginisialisasi” array dengan “nol”.

#blkdiscard /dev/md0

Jika terjadi kesalahan, coba tentukan langkahnya.

#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

Mengapa begitu besar...?Meningkatkan ukuran bongkahan memiliki efek positif pada kecepatan pembacaan acak dalam blok hingga ukuran bongkahan inklusif. Hal ini terjadi karena satu operasi dengan ukuran yang sesuai atau lebih kecil dapat diselesaikan seluruhnya pada satu perangkat. Oleh karena itu, IOPS dari semua perangkat dijumlahkan. Menurut statistik, 99% IO tidak melebihi 512K.

RAID 6 IOPS per penulisan selalu kurang dari atau sama dengan IOPS satu drive. Ketika, sebagai pembacaan acak, IOPS bisa beberapa kali lebih besar dari satu drive, dan di sini ukuran blok adalah kuncinya.
Penulis tidak melihat gunanya mencoba mengoptimalkan parameter yang buruk dalam desain RAID 6 dan malah mengoptimalkan kelebihan RAID 6.
Kami akan mengkompensasi penulisan acak RAID 6 yang buruk dengan cache NVMe dan trik penyediaan yang tipis.

Kami belum mengaktifkan DISCARD untuk RAID 6. Jadi kami tidak akan “menginisialisasi” array ini untuk saat ini. Kami akan melakukannya nanti, setelah menginstal OS.

HDD SATA

#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 kecepatan, kami ingin menempatkan sistem file root pada NVMe RAID 1 yaitu /dev/md0.
Namun, kita masih memerlukan array cepat ini untuk kebutuhan lain, seperti swap, metadata dan LVM-cache dan metadata tipis-LVM, jadi kita akan membuat LVM VG pada array ini.

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

Mari buat partisi untuk sistem file root.

#lvcreate -L 128G --name root root

Mari kita buat partisi untuk swapping sesuai dengan ukuran RAM.

#lvcreate -L 32G --name swap root

instalasi sistem operasi

Secara total, kami memiliki semua yang diperlukan untuk menginstal sistem.

Luncurkan wizard instalasi sistem dari lingkungan Ubuntu Live. Instalasi biasa. Hanya pada tahap memilih disk untuk instalasi, Anda perlu menentukan hal berikut:

  • /dev/md1, - titik pemasangan /boot, FS - BTRFS
  • /dev/root/root (alias /dev/mapper/root-root), - titik pemasangan / (root), FS - BTRFS
  • /dev/root/swap (alias /dev/mapper/root-swap), - digunakan sebagai partisi swap
  • Instal bootloader di /dev/sda

Ketika Anda memilih BTRFS sebagai sistem file root, penginstal akan secara otomatis membuat dua volume BTRFS bernama "@" untuk / (root), dan "@home" untuk /home.

Mari kita mulai instalasinya...

Instalasi akan diakhiri dengan kotak dialog modal yang menunjukkan kesalahan dalam instalasi bootloader. Sayangnya, Anda tidak dapat keluar dari dialog ini menggunakan cara standar dan melanjutkan instalasi. Kami keluar dari sistem dan masuk lagi, berakhir di desktop Ubuntu Live yang bersih. Buka terminal, dan lagi:

#sudo bash

Buat lingkungan chroot untuk melanjutkan instalasi:

#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 jaringan dan nama host di 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 masuk ke lingkungan chroot:

#chroot /mnt/chroot

Pertama-tama, kami akan mengirimkan paket:

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

Mari kita periksa dan perbaiki semua paket yang diinstal secara tidak benar karena instalasi sistem yang tidak lengkap:

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

Jika ada yang tidak berhasil, Anda mungkin perlu mengedit /etc/apt/sources.list terlebih dahulu

Mari sesuaikan parameter modul RAID 6 untuk mengaktifkan TRIM/DISCARD:

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

Mari kita ubah sedikit array kita:

#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 itu..?Kami telah membuat seperangkat aturan udev yang akan melakukan hal berikut:

  • Tetapkan ukuran cache blok untuk RAID 2020 agar memadai untuk tahun 6. Nilai defaultnya, tampaknya, tidak berubah sejak pembuatan Linux, dan sudah tidak memadai untuk waktu yang lama.
  • Cadangan minimum IO selama durasi pemeriksaan/sinkronisasi array. Hal ini untuk mencegah array Anda terjebak dalam kondisi sinkronisasi abadi saat dimuat.
  • Batasi IO maksimum selama pemeriksaan/sinkronisasi array. Hal ini diperlukan agar sinkronisasi/pemeriksaan RAID SSD tidak membuat drive Anda menjadi garing. Hal ini terutama berlaku untuk NVMe. (Ingat tentang radiatornya? Saya tidak bercanda.)
  • Melarang disk menghentikan rotasi spindel (HDD) melalui APM dan mengatur batas waktu tidur untuk pengontrol disk menjadi 7 jam. Anda dapat menonaktifkan APM sepenuhnya jika drive Anda dapat melakukannya (-B 255). Dengan nilai default, drive akan berhenti setelah lima detik. Kemudian OS ingin mereset cache disk, disk akan berputar kembali, dan semuanya akan dimulai dari awal lagi. Cakram memiliki jumlah putaran spindel maksimum yang terbatas. Siklus default yang sederhana dapat dengan mudah mematikan disk Anda dalam beberapa tahun. Tidak semua disk mengalami hal ini, tetapi disk kami adalah disk “laptop”, dengan pengaturan default yang sesuai, yang membuat RAID terlihat seperti mini-MAID.
  • Instal readahead pada disk (berputar) 1 megabyte - dua blok/potongan RAID 6 berturut-turut
  • Nonaktifkan readahead pada array itu sendiri.

Mari kita 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

Mengapa demikian..?Kami akan mencari partisi /boot dengan UUID. Penamaan array secara teoritis bisa berubah.

Kami akan mencari bagian yang tersisa berdasarkan nama LVM dalam notasi /dev/mapper/vg-lv, karena mereka mengidentifikasi partisi dengan cukup unik.

Kami tidak menggunakan UUID untuk LVM karena UUID volume LVM dan snapshotnya bisa sama.Pasang /dev/mapper/root-root.. dua kali?Ya. Tepat. Fitur BTRFS. Sistem file ini dapat di-mount beberapa kali dengan subvol yang berbeda.

Karena fitur yang sama, saya sarankan untuk tidak pernah membuat snapshot LVM dari volume BTRFS aktif. Anda mungkin mendapat kejutan saat melakukan boot ulang.

Mari kita buat ulang konfigurasi mdadm:

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

Mari sesuaikan pengaturan 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 itu..?Kami telah mengaktifkan perluasan otomatis kumpulan tipis LVM setelah mencapai 90% ruang yang ditempati sebesar 5% volume.

Kami telah meningkatkan jumlah maksimum blok cache untuk cache LVM.

Kami telah mencegah LVM mencari volume LVM (PV) di:

  • perangkat yang berisi cache LVM (cdata)
  • perangkat di-cache menggunakan cache LVM, melewati cache ( _corig). Dalam hal ini, perangkat yang di-cache itu sendiri akan tetap dipindai melalui cache (hanya ).
  • perangkat yang berisi metadata cache LVM (cmeta)
  • semua perangkat di VG dengan nama gambar. Di sini kita akan memiliki image disk mesin virtual, dan kita tidak ingin LVM di host mengaktifkan volume milik OS tamu.
  • semua perangkat di VG dengan nama cadangan. Di sini kita akan memiliki salinan cadangan image mesin virtual.
  • semua perangkat yang namanya diakhiri dengan “gpv” (volume fisik tamu)

Kami telah mengaktifkan dukungan DISCARD saat mengosongkan ruang kosong di LVM VG. Hati-hati. Hal ini akan membuat penghapusan LV pada SSD cukup memakan waktu. Hal ini terutama berlaku pada SSD RAID 6. Namun rencananya kami akan menggunakan thin provisi sehingga hal ini tidak akan menghambat kami sama sekali.

Mari perbarui gambar initramfs:

#update-initramfs -u -k all

Instal dan konfigurasikan grub:

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

Disk mana yang harus dipilih?Semua yang sd*. Sistem harus dapat melakukan booting dari drive SATA atau SSD apa pun yang berfungsi.

Mengapa mereka menambahkan os-prober..?Untuk kemandirian yang berlebihan dan tangan yang lucu.

Ini tidak berfungsi dengan benar jika salah satu RAID berada dalam kondisi terdegradasi. Ia mencoba mencari OS pada partisi yang digunakan di mesin virtual yang berjalan pada perangkat keras ini.

Jika Anda membutuhkannya, Anda dapat meninggalkannya, tetapi ingatlah semua hal di atas. Saya sarankan mencari resep menghilangkan tangan nakal secara online.

Dengan ini kami telah menyelesaikan instalasi awal. Saatnya untuk reboot ke OS yang baru diinstal. Jangan lupa untuk melepas Live CD/USB yang dapat di-boot.

#exit
#reboot

Pilih salah satu SSD SATA sebagai perangkat boot.

LVM pada SSD SATA

Pada titik ini, kita sudah boot ke OS baru, mengkonfigurasi jaringan, apt, membuka emulator terminal, dan menjalankan:

#sudo bash

Ayo lanjutkan.

“Inisialisasi” array dari SATA SSD:

#blkdiscard /dev/md2

Jika tidak berhasil, coba:

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

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

Kenapa VG lagi..?Sebenarnya kita sudah mempunyai VG bernama root. Mengapa tidak menambahkan semuanya menjadi satu VG?

Jika terdapat beberapa PV dalam satu VG, maka agar VG dapat diaktifkan dengan benar, semua PV harus ada (online). Pengecualiannya adalah LVM RAID, yang sengaja tidak kami gunakan.

Kami benar-benar ingin jika terjadi kegagalan (kehilangan data baca) pada salah satu array RAID 6, sistem operasi akan melakukan booting secara normal dan memberi kami kesempatan untuk menyelesaikan masalah tersebut.

Untuk melakukan ini, pada abstraksi tingkat pertama kita akan mengisolasi setiap jenis "media" fisik ke dalam VG terpisah.

Secara ilmiah, susunan RAID yang berbeda termasuk dalam “domain keandalan” yang berbeda. Anda tidak boleh membuat titik kegagalan tambahan bagi mereka dengan menjejalkannya ke dalam satu VG.

Kehadiran LVM di tingkat "perangkat keras" akan memungkinkan kita untuk secara sewenang-wenang memotong bagian-bagian array RAID yang berbeda dengan menggabungkannya dengan cara yang berbeda. Misalnya - lari serempak bcache + LVM tipis, bcache + BTRFS, LVM cache + LVM tipis, konfigurasi ZFS yang kompleks dengan cache, atau campuran jahat lainnya untuk mencoba dan membandingkan semuanya.

Pada tingkat "perangkat keras", kami tidak akan menggunakan apa pun selain volume LVM "tebal" lama yang bagus. Pengecualian terhadap aturan ini mungkin adalah partisi cadangan.

Saya rasa saat ini, banyak pembaca yang mulai mencurigai sesuatu tentang boneka bersarang itu.

LVM pada HDD SATA

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

VG baru lagi..?Kami sangat ingin jika array disk yang akan kami gunakan untuk backup data gagal, sistem operasi kami akan tetap bekerja normal, dengan tetap menjaga akses ke data non-backup seperti biasa. Oleh karena itu, untuk menghindari masalah aktivasi VG, kami membuat VG tersendiri.

Menyiapkan cache LVM

Mari buat LV di NVMe RAID 1 untuk digunakan sebagai perangkat caching.

#lvcreate -L 70871154688B --name cache root

Mengapa jumlahnya sangat sedikit...?Faktanya adalah SSD NVMe kami juga memiliki cache SLC. 4 gigabyte "gratis" dan 18 gigabyte dinamis karena ruang kosong yang ditempati di MLC 3-bit. Setelah cache ini habis, SSD NVMe tidak akan lebih cepat dibandingkan SSD SATA kami dengan cache. Sebenarnya, karena alasan ini, tidak masuk akal bagi kami untuk membuat partisi cache LVM jauh lebih besar dari dua kali ukuran cache SLC pada drive NVMe. Untuk drive NVMe yang digunakan, penulis menganggap wajar untuk membuat cache sebesar 32-64 gigabyte.

Ukuran partisi yang diberikan diperlukan untuk mengatur 64 gigabyte cache, metadata cache, dan cadangan metadata.

Selain itu, saya perhatikan bahwa setelah sistem dimatikan secara kotor, LVM akan menandai seluruh cache sebagai kotor dan akan melakukan sinkronisasi lagi. Selain itu, ini akan berulang setiap kali lvchange digunakan pada perangkat ini hingga sistem di-boot ulang kembali. Oleh karena itu, saya sarankan segera membuat ulang cache menggunakan script yang sesuai.

Mari buat LV pada SATA RAID 6 untuk digunakan sebagai perangkat cache.

#lvcreate -L 3298543271936B --name cache data

Kenapa hanya tiga terabyte..?Sehingga bila diperlukan, Anda bisa menggunakan SATA SSD RAID 6 untuk beberapa kebutuhan lainnya. Ukuran ruang cache dapat ditingkatkan secara dinamis, dengan cepat, tanpa menghentikan sistem. Untuk melakukan ini, Anda perlu menghentikan sementara dan mengaktifkan kembali cache, tetapi keunggulan khas LVM-cache dibandingkan, misalnya, bcache adalah hal ini dapat dilakukan dengan cepat.

Mari buat VG baru untuk caching.

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

Mari buat LV di perangkat yang di-cache.

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

Di sini kami segera mengambil semua ruang kosong di /dev/data/cache sehingga semua partisi lain yang diperlukan segera dibuat di /dev/root/cache. Jika Anda membuat sesuatu di tempat yang salah, Anda dapat memindahkannya menggunakan pvmove.

Mari buat dan aktifkan 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

Mengapa ukurannya begitu besar..?Melalui eksperimen praktis, penulis dapat menemukan bahwa hasil terbaik dicapai jika ukuran blok cache LVM sama dengan ukuran blok tipis LVM. Selain itu, semakin kecil ukurannya, semakin baik kinerja konfigurasinya dalam perekaman acak.

64k adalah ukuran blok minimum yang diperbolehkan untuk LVM tipis.

Hati-hati menulis balik..!Ya. Jenis cache ini menunda sinkronisasi penulisan ke perangkat yang di-cache. Artinya, jika cache hilang, Anda mungkin kehilangan data di perangkat yang di-cache. Nanti penulis akan memberi tahu Anda tindakan apa saja, selain NVMe RAID 1, yang dapat diambil untuk mengkompensasi risiko ini.

Jenis cache ini sengaja dipilih untuk mengkompensasi buruknya kinerja penulisan acak RAID 6.

Mari kita periksa apa yang kita dapatkan:

#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] yang boleh ditempatkan di /dev/data/cache. Jika ada yang salah, gunakan pvmove.

Anda dapat menonaktifkan cache jika perlu dengan satu perintah:

#lvconvert -y --uncache cache/cachedata

Hal ini dilakukan secara online. LVM hanya akan menyinkronkan cache ke disk, menghapusnya, dan mengganti nama cachedata_corig kembali menjadi cachedata.

Menyiapkan LVM tipis

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

Pembulatan hingga 4 gigabyte: 4294967296B

Kalikan dengan dua dan tambahkan 4194304B untuk metadata LVM PV: 8594128896B
Mari buat partisi terpisah di NVMe RAID 1 untuk menempatkan metadata tipis LVM dan salinan cadangannya di dalamnya:

#lvcreate -L 8594128896B --name images root

Untuk apa..?Di sini mungkin timbul pertanyaan: mengapa menempatkan metadata tipis LVM secara terpisah jika masih di-cache di NVMe dan akan bekerja dengan cepat.

Meskipun kecepatan penting di sini, itu bukan alasan utama. Masalahnya adalah cache adalah titik kegagalan. Sesuatu bisa terjadi padanya, dan jika metadata tipis LVM di-cache, itu akan menyebabkan semuanya hilang sepenuhnya. Tanpa metadata yang lengkap, hampir mustahil untuk mengumpulkan volume yang tipis.

Dengan memindahkan metadata ke volume terpisah yang tidak di-cache, namun cepat, kami menjamin keamanan metadata jika terjadi kehilangan atau kerusakan cache. Dalam hal ini, semua kerusakan yang disebabkan oleh hilangnya cache akan dilokalisasi di dalam volume yang tipis, yang akan menyederhanakan prosedur pemulihan hingga beberapa kali lipat. Dengan kemungkinan besar, kerusakan ini akan dipulihkan menggunakan log FS.

Selain itu, jika snapshot volume tipis diambil sebelumnya, dan setelah itu cache disinkronkan sepenuhnya setidaknya sekali, maka, karena desain internal LVM tipis, integritas snapshot akan terjamin jika cache hilang. .

Mari buat VG baru yang akan bertanggung jawab atas penyediaan tipis:

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

Mari membuat kolam:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Mengapa -Z kamuSelain tujuan sebenarnya dari mode ini - untuk mencegah kebocoran data dari satu mesin virtual ke mesin virtual lain saat mendistribusikan ulang ruang - zeroing juga digunakan untuk meningkatkan kecepatan penulisan acak dalam blok yang lebih kecil dari 64k. Setiap penulisan yang kurang dari 64k ke area volume tipis yang sebelumnya tidak terisi akan menjadi 64K sejajar tepi dalam cache. Ini akan memungkinkan operasi dilakukan sepenuhnya melalui cache, melewati perangkat yang di-cache.

Mari kita pindahkan LV ke PV yang sesuai:

#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 kita periksa:

#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 volume tipis untuk pengujian:

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

Kami akan menginstal paket untuk pengujian dan pemantauan:

#apt-get install sysstat fio

Inilah cara Anda dapat mengamati perilaku konfigurasi penyimpanan kami secara real time:

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

Dengan hati-hati! Sumber!Kode ini akan menjalankan 36 pengujian berbeda, masing-masing berjalan selama 4 detik. Setengah dari tes ditujukan untuk perekaman. Anda dapat merekam banyak hal di NVMe dalam 4 detik. Hingga 3 gigabyte per detik. Jadi, setiap pengujian penulisan dapat memakan sumber daya SSD Anda hingga 216 gigabyte.

Membaca dan menulis bercampur?Ya. Masuk akal untuk menjalankan tes baca dan tulis secara terpisah. Selain itu, masuk akal untuk memastikan bahwa semua cache disinkronkan sehingga penulisan yang dilakukan sebelumnya tidak mempengaruhi pembacaan.

Hasilnya akan sangat bervariasi selama peluncuran pertama dan berikutnya seiring dengan terisinya cache dan volume tipis, dan juga bergantung pada apakah sistem berhasil menyinkronkan cache yang diisi selama peluncuran terakhir.

Antara lain, saya menyarankan untuk mengukur kecepatan pada volume tipis penuh yang baru saja diambil gambarnya. Penulis berkesempatan mengamati bagaimana penulisan acak meningkat tajam segera setelah snapshot pertama dibuat, terutama saat cache belum sepenuhnya penuh. Hal ini terjadi karena semantik penulisan copy-on-write, penyelarasan cache dan blok volume yang tipis, dan fakta bahwa penulisan acak ke RAID 6 berubah menjadi pembacaan acak dari RAID 6 diikuti dengan penulisan ke cache. Dalam konfigurasi kami, pembacaan acak dari RAID 6 hingga 6 kali (jumlah SSD SATA dalam array) lebih cepat dibandingkan penulisan. Karena blok untuk Kontrak Karya dialokasikan secara berurutan dari kumpulan tipis, kemudian pencatatan, sebagian besar, juga berubah menjadi berurutan.

Kedua fitur ini dapat digunakan untuk keuntungan Anda.

Simpan snapshot yang “koheren” dalam cache

Untuk mengurangi risiko kehilangan data jika terjadi kerusakan/kehilangan cache, penulis mengusulkan untuk memperkenalkan praktik rotasi snapshot untuk menjamin integritasnya dalam kasus ini.

Pertama, karena metadata volume tipis berada pada perangkat yang tidak di-cache, metadata akan konsisten dan kemungkinan kehilangan akan diisolasi dalam blok data.

Siklus rotasi snapshot berikut menjamin integritas data di dalam snapshot jika cache hilang:

  1. Untuk setiap volume tipis dengan nama <name>, buat snapshot dengan nama <name>.cached
  2. Mari kita tetapkan ambang migrasi ke nilai tinggi yang wajar: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Dalam loop kami memeriksa jumlah blok kotor di cache: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' sampai kita mendapatkan nol. Jika angka nol hilang terlalu lama, angka tersebut dapat dibuat dengan mengalihkan sementara cache ke mode writethrough. Namun, dengan mempertimbangkan karakteristik kecepatan rangkaian SSD SATA dan NVMe kami, serta sumber daya TBW-nya, Anda akan dapat menangkap momen dengan cepat tanpa mengubah mode cache, atau perangkat keras Anda akan menghabiskan seluruh sumber dayanya dalam waktu singkat. beberapa hari. Karena keterbatasan sumber daya, sistem pada prinsipnya tidak dapat selalu memuat beban tulis di bawah 100%. SSD NVMe kami dengan beban tulis di bawah 100% akan menghabiskan sumber daya sepenuhnya hari 3-4. SSD SATA hanya akan bertahan dua kali lebih lama. Oleh karena itu, kita akan berasumsi bahwa sebagian besar beban dihabiskan untuk membaca, dan kita memiliki lonjakan aktivitas yang sangat tinggi dalam jangka waktu yang relatif pendek dikombinasikan dengan rata-rata beban yang rendah untuk menulis.
  4. Segera setelah kami menangkap (atau membuat) angka nol, kami mengganti nama <name>.cached menjadi <name>.commited. <name>.commit yang lama telah dihapus.
  5. Opsional, jika cache 100% penuh, cache dapat dibuat ulang dengan skrip, sehingga membersihkannya. Dengan cache yang setengah kosong, sistem bekerja lebih cepat saat menulis.
  6. Tetapkan ambang migrasi ke nol: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Ini untuk sementara akan mencegah cache disinkronkan ke media utama.
  7. Kita tunggu hingga cukup banyak perubahan yang terakumulasi di cache #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' atau pengatur waktunya akan mati.
  8. Kami ulangi lagi.

Mengapa kesulitan dengan ambang migrasi...?Masalahnya, dalam praktik nyata, pencatatan “acak” sebenarnya tidak sepenuhnya acak. Jika kita menulis sesuatu ke sektor berukuran 4 kilobyte, ada kemungkinan besar bahwa dalam beberapa menit ke depan, rekor akan dibuat ke sektor yang sama atau salah satu sektor yang berdekatan (+- 32K).

Dengan menetapkan ambang migrasi ke nol, kami menunda sinkronisasi penulisan pada SSD SATA dan menggabungkan beberapa perubahan ke satu blok 64K di cache. Ini secara signifikan menghemat sumber daya SATA SSD.

Dimana kodenya..?Sayangnya, penulis menganggap dirinya kurang kompeten dalam pengembangan skrip bash karena ia 100% otodidak dan mempraktikkan pengembangan berbasis “google”, oleh karena itu ia percaya bahwa kode buruk yang keluar dari tangannya tidak boleh digunakan oleh siapa pun. kalau tidak.

Saya pikir para profesional di bidang ini akan dapat secara mandiri menggambarkan semua logika yang dijelaskan di atas, jika perlu, dan, mungkin, bahkan mendesainnya dengan indah sebagai layanan systemd, seperti yang coba dilakukan oleh penulis.

Skema rotasi snapshot yang sederhana akan memungkinkan kita tidak hanya untuk terus-menerus memiliki satu snapshot yang tersinkronisasi sepenuhnya pada SSD SATA, tetapi juga akan memungkinkan kita, menggunakan utilitas thin_delta, untuk mengetahui blok mana yang diubah setelah pembuatannya, dan dengan demikian melokalisasi kerusakan pada volume utama, sangat menyederhanakan pemulihan.

TRIM/BUANG di libvirt/KVM

Karena penyimpanan data akan digunakan untuk KVM yang menjalankan libvirt, maka merupakan ide bagus untuk mengajari VM kita tidak hanya menggunakan ruang kosong, tetapi juga mengosongkan apa yang tidak lagi diperlukan.

Hal ini dilakukan dengan meniru dukungan TRIM/DISCARD pada disk virtual. Untuk melakukan ini, Anda perlu mengubah tipe pengontrol menjadi 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 dari OS tamu diproses dengan benar oleh LVM, dan blok dibebaskan dengan benar baik di cache maupun di kumpulan tipis. Dalam kasus kami, ini terjadi terutama secara tertunda, saat snapshot berikutnya dihapus.

Cadangan BTRFS

Gunakan skrip yang sudah jadi dengan крайней hati-hati dan resiko ditanggung sendiri. Penulis menulis kode ini sendiri dan khusus untuk dirinya sendiri. Saya yakin banyak pengguna Linux berpengalaman yang memiliki alat serupa, dan tidak perlu menyalin milik orang lain.

Mari buat volume di perangkat cadangan:

#lvcreate -L 256G --name backup backup

Mari kita format di BTRFS:

#mkfs.btrfs /dev/backup/backup

Mari buat titik pemasangan dan pasang subbagian root dari sistem file:

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

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

Mari buat direktori untuk skrip cadangan:

#mkdir /root/btrfs-backup

Mari kita salin skripnya:

Banyak kode bash yang menakutkan. Gunakan dengan risiko Anda sendiri. Jangan menulis surat kemarahan 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 fungsinya..?Berisi serangkaian perintah sederhana untuk membuat snapshot BTRFS dan menyalinnya ke FS lain menggunakan pengiriman/penerimaan BTRFS.

Peluncuran pertama bisa memakan waktu yang relatif lama, karena... Pada awalnya, semua data akan disalin. Peluncuran selanjutnya akan sangat cepat, karena... Hanya perubahan yang akan disalin.

Skrip lain yang akan kita masukkan ke dalam cron:

Beberapa kode bash lagi#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 fungsinya..?Membuat dan menyinkronkan snapshot tambahan dari volume BTRFS yang terdaftar di FS cadangan. Setelah ini, ia akan menghapus semua gambar yang dibuat 60 hari yang lalu. Setelah peluncuran, snapshot bertanggal dari volume yang terdaftar akan muncul di subdirektori /backup/btrfs/back/remote/.

Mari berikan hak eksekusi kode:

#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

Cadangan tipis LVM

Mari buat kumpulan tipis di perangkat cadangan:

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

Mari kita instal ddrescue, karena... skrip akan menggunakan alat ini:

#apt-get install gddrescue

Mari buat direktori untuk skrip:

#mkdir /root/lvm-thin-backup

Mari kita salin skripnya:

Banyak pesta di 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 fungsinya...?Berisi sekumpulan perintah untuk memanipulasi snapshot tipis dan menyinkronkan perbedaan antara dua snapshot tipis yang diterima melalui thin_delta ke perangkat blok lain menggunakan ddrescue dan blkdiscard.

Script lain yang akan kita masukkan ke dalam cron:

Sedikit pesta lagi#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 fungsinya...?Menggunakan skrip sebelumnya untuk membuat dan menyinkronkan cadangan volume tipis yang terdaftar. Skrip akan meninggalkan snapshot tidak aktif dari volume yang terdaftar, yang diperlukan untuk melacak perubahan sejak sinkronisasi terakhir.

Skrip ini harus diedit, menentukan daftar volume tipis yang salinan cadangannya harus dibuat. Nama-nama yang diberikan hanya untuk tujuan ilustrasi. Jika mau, Anda dapat menulis skrip yang akan menyinkronkan semua volume.

Mari kita berikan haknya:

#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

Peluncuran pertama akan memakan waktu lama, karena... volume tipis akan disinkronkan sepenuhnya dengan menyalin semua ruang yang digunakan. Berkat metadata tipis LVM, kami mengetahui blok mana yang sebenarnya digunakan, jadi hanya blok volume tipis bekas yang akan disalin.

Proses selanjutnya akan menyalin data secara bertahap berkat pelacakan perubahan melalui metadata tipis LVM.

Mari kita lihat apa yang terjadi:

#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 hubungannya ini dengan boneka bersarang?

Kemungkinan besar, mengingat volume logis LVM LV dapat menjadi volume fisik LVM PV untuk VG lainnya. LVM bisa bersifat rekursif, seperti boneka bersarang. Hal ini memberikan fleksibilitas ekstrim pada LVM.

PS

Pada artikel berikutnya, kami akan mencoba menggunakan beberapa sistem penyimpanan seluler/KVM serupa sebagai dasar untuk membuat cluster penyimpanan/vm yang terdistribusi secara geografis dengan redundansi di beberapa benua menggunakan desktop rumah, Internet rumah, dan jaringan P2P.

Sumber: www.habr.com

Tambah komentar