Apa yang umum antara LVM dan matryoshka?

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

Program ini akan:

  • Bangun md RAID 1 dari NVMe SSD.
  • Bangun md RAID 6 dari SATA SSD dan drive biasa.
  • Fitur TRIM / DISCARD pada SSD RAID 1/6.
  • Membuat larik md RAID 1/6 yang dapat di-boot pada serangkaian disk yang umum.
  • Menginstal sistem pada NVMe RAID 1 jika tidak ada dukungan NVMe di BIOS.
  • Menggunakan LVM cache dan LVM thin.
  • Menggunakan snapshot BTRFS dan kirim / terima untuk cadangan.
  • Menggunakan snapshot tipis LVM dan thin_delta untuk backup gaya BTRFS.

Jika tertarik, silakan, di bawah kucing.

Pernyataan


Penulis tidak bertanggung jawab atas konsekuensi penggunaan 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 semua konsekuensi dari tindakan ini. Kemungkinan konsekuensi meliputi:

  • SSD NVMe Goreng Renyah.
  • Benar-benar menghabiskan sumber daya perekaman dan kegagalan drive SSD.
  • Kehilangan total semua data di semua drive, termasuk cadangan.
  • Perangkat keras komputer rusak.
  • Menghabiskan waktu, gelisah, dan uang.
  • Efek lain apa pun yang tidak tercantum di atas.

Besi


Stoknya adalah:


Motherboard ini sekitar 2013 pada chipset Z87 lengkap dengan Intel Core i7 / Haswell.

  • CPU 4 core, 8 thread
  • RAM DDR3 32 Gigabytes
  • 1 x 16 atau 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • Konektor SATA 3 6 x 6 GBps

Adaptor SAS LSI SAS9211-8I beralih ke mode IT / HBA. Firmware yang mendukung RAID telah sengaja diganti dengan firmware HBA untuk:

  1. Setiap saat dimungkinkan untuk membuang adaptor ini dan menggantinya dengan adaptor pertama lainnya.
  2. TRIM / Buang berfungsi normal pada disk, seperti dalam firmware RAID, perintah-perintah ini tidak didukung sama sekali, dan HBA, secara umum, tidak peduli perintah apa yang harus dikirim pada bus.

Hard drive - 8 buah HGST Travelstar 7K1000 dengan volume 1 TB dalam form factor 2.5, seperti untuk laptop. Drive ini sebelumnya dalam array RAID 6. Dalam sistem baru, mereka juga akan menemukan aplikasi. Untuk menyimpan cadangan lokal.

Selain itu ditambahkan:


6 buah model SATA SSD Samsung 860 QVO 2TB. SSD ini membutuhkan jumlah besar, keberadaan cache SLC, keandalan yang diinginkan, dan harga yang murah. Wajib adalah dukungan untuk membuang / nol yang diperiksa oleh garis di dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

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

Untuk SSD ini, kecepatan baca / tulis acak dan sumber daya untuk kebutuhan Anda adalah penting. Radiator untuk mereka. Wajib. Benar-benar perlu. Kalau tidak, goreng mereka sampai garing selama sinkronisasi RAIDa pertama.

Adaptor StarTech PEX8M2E2 untuk 2 x NVMe SSD dengan PCIe 3.0 8x slot. Ini, sekali lagi, hanya HBA, tetapi untuk NVMe. Ini berbeda dari adaptor murah karena tidak adanya persyaratan untuk dukungan bifurkasi PCIe dari motherboard karena adanya sakelar PCIe terintegrasi. Ini akan bekerja bahkan dalam sistem tertua di mana ada PCIe, bahkan jika itu adalah slot x1 PCIe 1.0. Wajar, dengan kecepatan yang sesuai. Tidak ada RAID di sana. Tidak ada BIOS terintegrasi di papan. Jadi, sistem Anda tidak akan secara ajaib belajar melakukan booting dari NVMe, apalagi NVMe RAID berkat perangkat ini.

Komponen ini hanya disebabkan oleh kehadiran hanya satu 8x PCIe 3.0 gratis dalam sistem, dan, dengan adanya 2 slot gratis, komponen ini mudah diganti oleh dua PEX4M2E1 atau analog murah, yang dapat dibeli di mana saja dengan harga 600 rubel.

Penolakan terhadap semua jenis perangkat keras atau chipset / BIOS RAID terintegrasi dibuat dengan sengaja, agar dapat sepenuhnya menggantikan seluruh sistem, dengan pengecualian SSD / HDD itu sendiri, menyimpan semua data. Idealnya, akan memungkinkan untuk menjaga bahkan sistem operasi yang terinstal ketika pindah ke perangkat keras yang sama sekali baru / berbeda. Yang utama adalah bahwa ada port SATA dan PCIe. Ini seperti live CD atau bootable flash drive, hanya sangat cepat dan sedikit kebesaran.

Humor
, , — . . 5.25 .

Yah, dan, tentu saja, untuk bereksperimen dengan berbagai metode caching SSD di Linux.
Penggerebekan perangkat keras, itu membosankan. Nyalakan. Itu bekerja atau tidak. Dan dengan mdadm selalu ada opsi.

Lembut


Sebelumnya, Debian 8 Jessie diinstal pada perangkat keras, yang dekat dengan EOL. RAID 6 dari HDD yang disebutkan di atas dipasangkan dengan LVM. Itu menjalankan mesin virtual di kvm / libvirt.

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

Dalam sistem yang disebutkan ada semua driver perangkat keras yang kita butuhkan di luar kotak. Kami tidak memerlukan perangkat lunak dan driver pihak ketiga.

Persiapan untuk instalasi


Untuk menginstal sistem, kita perlu Ubuntu Desktop Image. Sistem server memiliki semacam penginstal yang kuat yang menunjukkan kemandirian yang berlebihan dan tidak dapat dilepaskan, selalu mendorong partisi sistem UEFI ke salah satu disk yang merusak semua keindahan. Karenanya, ini hanya diinstal dalam mode UEFI. Itu tidak menawarkan opsi.

Ini tidak cocok untuk kita.

Mengapa?
, UEFI RAID, .. UEFI ESP . , ESP USB , , . mdadm RAID 1 0.9 UEFI BIOS , , BIOS - ESP .

, UEFI NVRAM, , .. .

, . , Legacy/BIOS boot, CSM UEFI- . , , .

Versi desktop Ubuntu juga tidak tahu cara menginstal secara normal dengan Legload bootloader, tetapi di sini, seperti yang mereka katakan, setidaknya ada opsi.

Maka, kumpulkan perangkat keras dan muat sistem dari flash drive Ubuntu Live yang dapat di-boot. Kami perlu mengunduh paket, jadi kami menyiapkan jaringan, yang menghasilkan Anda. Jika tidak berhasil, Anda dapat mengunduh paket yang diperlukan ke USB flash drive terlebih dahulu.

Kita masuk ke lingkungan Desktop, menjalankan emulator terminal, dan mari kita pergi:

#sudo bash

Bagaimana...?
sudo. . , . sudo , . :


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

Kenapa tidak ZFS ...?
, — , .
, — , - .

ZFS — , mdadm+lvm .

. . . . . . , .

Lalu mengapa BTRFS ...?
Legacy/BIOS GRUB , , , -. /boot . , / () , LVM .

, .
send/recieve.

, GPU PCI-USB Host- KVM IOMMU.

— , .

ZFS, , , .

, / RAID ZFS, BRTFS LVM.

, BTRFS , / HDD.

Scan ulang semua perangkat: Mari kita lihat-lihat

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

:

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

Mempartisi "drive"


SSD NVMe


Tetapi dengan cara apa pun kami tidak akan menandai mereka. Semua sama, BIOS kami tidak melihat drive ini. Jadi, mereka akan pergi sepenuhnya ke perangkat lunak RAID. Kami bahkan tidak akan membuat partisi di sana. Jika Anda ingin sesuai dengan "kanon" atau "prinsip" - buat satu partisi besar, seperti HDD.

HDD SATA


Tidak ada yang istimewa untuk ditemukan. Kami akan membuat satu bagian untuk semuanya. Kami akan membuat bagian karena BIOS melihat disk ini dan bahkan mungkin mencoba untuk boot dari mereka. Kami bahkan akan menginstal GRUB nanti pada disk ini sehingga sistem tiba-tiba berhasil.

#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 sini kita memiliki yang paling menarik.

Pertama, kami memiliki 2 drive TB. Ini berada dalam batas yang diizinkan untuk MBR, yang akan kami gunakan. Jika perlu, bisa diganti dengan GPT. Disk GPT memiliki lapisan kompatibilitas yang memungkinkan sistem yang kompatibel dengan MBR untuk melihat 4 partisi pertama jika mereka berada dalam 2 terabyte pertama. Yang utama adalah bahwa partisi boot dan partisi bios_grub pada disk ini harus berada di awal. Ini memungkinkan Anda untuk 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 mengambil semua ruang kosong yang tersisa dengan pengecualian area kecil yang tidak terisi pada akhir drive.

Apa area yang belum dialokasikan?
SATA SSD SLC 6 78 . 6 «» «» «» . 72 .

, SLC, 4 bit MLC. , 4 1 SLC .

72 4 288 . , SLC .

, 312 SLC . 2 RAID .

, . QLC , — . , , , SSD TBW .

#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 mobil. Ini diperlukan karena nama host adalah bagian dari nama array di suatu tempat di dalam mdadm dan memengaruhi sesuatu di suatu tempat. Array, tentu saja, dapat diubah namanya nanti, tetapi, ini adalah tindakan yang tidak perlu.

#mcedit /etc/hostname
#mcedit /etc/hosts
#hostname
vdesk0

SSD NVMe


#mdadm --create --verbose --assume-clean /dev/md0 --level=1 --raid-devices=2 /dev/nvme[0-1]n1

Kenapa - bersih-bersih ...?
. RAID 1 6 . , . , SSD — TBW. TRIM/DISCARD SSD «».

SSD RAID 1 DISCARD .

SSD RAID 6 DISCARD .

, SSD 4/5/6 discard_zeroes_data. , , , -, , . , , . DISCARD - RAID 6.

Perhatian, perintah berikut ini akan menghancurkan semua data pada drive NVMe dengan "menginisialisasi" array dengan "nol".

#blkdiscard /dev/md0

Jika terjadi kesalahan, maka coba tentukan 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 begitu besar ...?
chunk-size chunk-size . , . , IOPS . 99% IO 512K.

RAID 6 IOPS IOPS . IOPS , .
RAID 6 by-design , RAID 6 .
RAID 6 NVMe thin-provisioning.

Kami belum mengaktifkan DISCARD untuk RAID 6. Jadi, kami belum akan "menginisialisasi" array 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 FS root pada NVMe RAID 1 yang merupakan / dev / md0.
Namun demikian, kita masih memerlukan array cepat ini untuk kebutuhan lain, seperti swap, metadata dan LVM-cache dan metadata tipis-LVM, oleh karena itu, pada array ini kita akan membuat LVM VG. Buat partisi untuk root FS. Buat bagian untuk menukar ukuran RAM.

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




#lvcreate -L 128G --name root root



#lvcreate -L 32G --name swap root

Instalasi OS


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

Buka wizard penginstalan dari lingkungan Ubuntu Live. Instalasi normal. Hanya pada tahap memilih drive untuk instalasi, Anda perlu menentukan yang berikut:

  • / dev / md1, - mount point / boot, FS - BTRFS
  • / dev / root / root (alias / dev / mapper / root-root), - mount point / (root), FS - BTRFS
  • / dev / root / swap (alias / dev / mapper / root-swap), - gunakan sebagai partisi swap
  • Instal bootloader di / dev / sda

Jika Anda memilih BTRFS sebagai root FS, installer akan secara otomatis membuat dua volume BTRFS dengan nama "@" untuk / (root), dan "@home" untuk / home.

Kami memulai instalasi ...

Instalasi akan berakhir dengan kotak dialog modal yang menginformasikan tentang kesalahan instalasi bootloader. Sayangnya, keluar dari dialog ini dengan cara biasa dan melanjutkan instalasi akan gagal. Kami keluar dari sistem dan masuk lagi, masuk ke desktop Ubuntu Live yang bersih. Buka terminal, dan lagi:

#sudo bash

Buat lingkungan chroot untuk melanjutkan instalasi: Mengatur jaringan dan nama host di chroot: Pergi ke lingkungan chroot: Pertama kami mengirimkan paket: Periksa dan perbaiki semua paket yang bengkok karena instalasi sistem yang tidak lengkap:

#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



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



#chroot /mnt/chroot



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



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

Jika sesuatu tidak tumbuh bersama, Anda mungkin perlu

mengedit /etc/apt/sources.list sebelum itu. Mari kita ubah parameter untuk modul RAID 6 untuk mengaktifkan TRIM / DISCARD: Kami akan sedikit menyesuaikan array kami:

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



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

EOF

Apa itu..?
udev :

  • 2020- RAID 6. -, , Linux, .
  • / IO. , .
  • / IO. , / SSD RAID- . NVMe. ( ? . )
  • APM (HDD) 7 . APM (-B 255). - . , , , -. . - . , , - «», -, RAID- mini-MAID-.
  • readahead () 1 — /chunk RAID 6
  • readahead SATA SSD
  • readahead NVMe SSD
  • readahead LVM SSD.
  • readahead RAID .


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..?
/boot UUID .. .

LVM /dev/mapper/vg-lv, .. .

UUID LVM .. UUID LVM .
Dua kali kita me-mount / dev / mapper / root-root ..?
. . BTRFS. subvol.

- LVM BTRFS . .

Kami membuat ulang konfigurasi mdadm: Memperbaiki pengaturan LVM:

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



#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..?
LVM thin 90% 5% .

LVM cache.

LVM LVM (PV) :

  • LVM cache (cdata)
  • LVM cache (<lv_name>_corig). ( <lv_name>).
  • LVM cache (cmeta)
  • VG images. , , LVM .
  • VG backup. .
  • «gpv» ( guest physical volume )

DISCARD LVM VG. . LV SSD . SSD RAID 6. , , thin provisioning, , .

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


Drive apa yang harus dipilih?
sd*. SATA SSD.

Kenapa dipaku os-prober ..?
.

RAID- . , .

, , , . .

Dengan ini, kami menyelesaikan instalasi awal. Saatnya untuk reboot ke OS yang baru diinstal. Ingatlah untuk menghapus Live CD / USB yang dapat di-boot. Saat perangkat melakukan boot, pilih salah satu SSD SATA.

#exit
#reboot




LVM ke SSD SATA


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

#sudo bash

Lanjutkan.

“Inisialisasi” sebuah array dari SATA SSD:

#blkdiscard /dev/md2

Jika tidak, maka coba:

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

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


Kenapa lagi vg ..?
, VG root. VG?

VG PV, VG PV (online). LVM RAID, .

, ( ) RAID 6 .

, «» VG.

-, RAID « ». , VG.

LVM «» RAID - . , — bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, ZFS , .

«» , - «» LVM-, . , , .

, , - .

LVM ke SATA HDD


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


Lagi-lagi VG baru ..?
, , , , - . , - VG, — VG.

Konfigurasikan cache LVM


Buat LV pada NVMe RAID 1 untuk menggunakannya sebagai perangkat caching.

#lvcreate -L 70871154688B --name cache root

Kenapa kecil sekali ...?
, NVMe SSD SLC . 4 «» 18 3-bit MLC. - NVMe SSD SATA SSD . , LVM cache SLC NVMe . NVMe 32-64 .

64 , .

, LVM . , lvchange . , .

Mari kita buat LV pada SATA RAID 6 untuk menggunakannya sebagai perangkat yang di-cache.

#lvcreate -L 3298543271936B --name cache data

Kenapa hanya tiga terabyte ..?
, , SATA SSD RAID 6 - . , , . , , LVM-cache , , bcache, , .

Buat VG baru untuk caching. Buat LV pada perangkat yang di-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 memiliki sesuatu yang tidak dibuat di sana, Anda dapat memindahkannya menggunakan pvmove. Buat dan aktifkan cache:

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




#lvcreate -L 3298539077632B --name cachedata cache /dev/data/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 begitu bungkam ..?
, LVM cache LVM thin. , , .

64 — LVM thin.

Perhatian penulisan kembali ..!
. . , , , . , , NVMe RAID 1 , .

, RAID 6 .

Mari kita verifikasi bahwa kita berhasil: Hanya [cachedata_corig] yang berada di / dev / data / cache. Jika ada sesuatu yang salah, maka gunakan pvmove. Jika perlu, Anda dapat menonaktifkan cache dengan satu perintah: Ini dilakukan secara online. LVM hanya menyinkronkan cache ke disk, menghapusnya, dan mengganti nama cachedata_corig kembali ke cachedata.

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





#lvconvert -y --uncache cache/cachedata



Pengaturan tipis LVM


Kami memperkirakan secara kasar seberapa banyak ruang yang diperlukan untuk metadata tipis LVM : Membulatkan hingga 4 gigabita: 4294967296B Kalikan dengan dua dan tambahkan 4194304B untuk metadata LVM: 8594128896B Buat partisi terpisah di NVMe RAID 1 untuk menandai metadata tipis LVM di atasnya dan buat cadangan:

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







#lvcreate -L 8594128896B --name images root

Untuk apa..?
, LVM thin , NVMe .

, . , , . - , , LVM thin , . .

- -, , , . , . .

, , , , , , LVM thin, .

Buat VG baru yang akan bertanggung jawab untuk penyediaan tipis: Buat kelompok:

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



#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Kenapa -Z y
, , — , — zeroing 64k. 64k 64K . .

Mari pindahkan LV ke PV yang sesuai: Periksa: Buat volume tipis untuk pengujian: Pasang paket untuk pengujian dan pengamatan: Ini adalah bagaimana Anda dapat mengamati perilaku konfigurasi penyimpanan kami secara waktu nyata: Ini adalah cara Anda dapat menguji konfigurasi kami:

#pvmove -n images/thin-pool_tdata /dev/root/images /dev/cache/cachedata
#pvmove -n images/lvol0_pmspare /dev/cache/cachedata /dev/root/images
#pvmove -n images/thin-pool_tmeta /dev/cache/cachedata /dev/root/images



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



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



#apt-get install sysstat fio



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



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

Peringatan! Sumber!
36 , 4 . . 4 NVMe . 3 . , 216 SSD.

Membaca dan menulis acak?
. . , , , .

Hasilnya akan sangat bervariasi pada awal pertama dan selanjutnya sebagai cache dan volume tipis terisi, dan juga, tergantung pada apakah sistem berhasil menyinkronkan cache yang diisi pada awal terakhir.

Di antara hal-hal lain, saya sarankan mengukur kecepatan pada volume tipis yang sudah terisi dari mana snapshot baru saja dibuat. Penulis berkesempatan untuk mengamati bagaimana perekaman acak berakselerasi dengan tajam segera setelah pembuatan foto pertama, terutama ketika cache belum penuh. Hal ini disebabkan oleh semantik penulisan-pada-tulis, penjajaran blok cache dan volume yang tipis, dan fakta bahwa penulisan acak ke RAID 6 berubah menjadi pembacaan acak dari RAID 6 dan kemudian menulis ke cache. Dalam konfigurasi kami, pembacaan acak dari RAID 6 hingga 6 kali (jumlah SSD SATA dalam array) lebih cepat daripada menulis. Karena Karena blok KK dialokasikan secara berurutan dari kumpulan yang tipis, sebagian besar catatan juga berubah menjadi sekuensial.

Kedua fitur ini dapat digunakan secara menguntungkan.

Potret cache "koheren"


Untuk mengurangi risiko kehilangan data jika terjadi kerusakan / kehilangan cache, penulis menyarankan untuk memperkenalkan praktik memutar foto untuk menjamin integritasnya dalam kasus ini.

Pertama, karena fakta bahwa metadata volume tipis terletak pada perangkat yang tidak di-cache, metadata akan konsisten dan kemungkinan kerugian akan diisolasi di dalam blok data.

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

  1. Untuk setiap volume tipis dengan nama <nama>, buat snapshot dengan nama <nama> .cached
  2. Tetapkan ambang migrasi ke nilai tinggi yang masuk akal: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. : #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' . , writethrough . , SATA NVMe SSD, , TBW, , . - 100% . NVMe SSD 100% 3-4 . SATA SSD - . , , , , — .
  4. ( ) — <>.cached <>.committed. <>.committed .
  5. , 100%, , . .
  6. migration threshold : #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata .
  7. , #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' .
  8. .

migration threshold...?
, «» . - 4 , , - (+- 32K) .

migration threshold SATA SSD 64K . SATA SSD.

..?
, bash 100% «google»-driven development, , , , .

, , , , systemd , .

Skema rotasi sederhana untuk snapshot akan memungkinkan kita tidak hanya untuk selalu memiliki satu snapshot yang sepenuhnya disinkronkan pada SATA SATA, tetapi juga dengan bantuan utilitas thin_delta untuk mengetahui blok mana yang diubah setelah pembuatannya, dan dengan demikian melokalisasi kerusakan pada volume utama, sehingga lebih mudah untuk mengembalikannya. .

TRIM / DISCARD di libvirt / KVM


Karena Karena data warehouse akan digunakan untuk menjalankan libvirt KVM, alangkah baiknya untuk mengajarkan para VM kami tidak hanya untuk mengambil ruang kosong, tetapi juga membebaskan apa yang tidak lagi diperlukan.

Ini dilakukan dengan meniru dukungan TRIM / DISCARD pada disk virtual. Untuk melakukan ini, ubah tipe controller ke virtio-scsi dan edit xml. DISCARD serupa dari OS tamu diproses dengan benar oleh LVM, dan blok-blok dibebaskan dengan benar baik di cache maupun di kumpulan tipis. Dalam kasus kami, ini terjadi, terutama, ditunda, ketika Anda menghapus snapshot berikutnya.

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



Cadangan BTRFS


Gunakan skrip siap pakai dengan sangat hati - hati dan dengan risiko dan risiko Anda sendiri . Penulis menulis kode ini sendiri dan khusus untuk dirinya sendiri. Saya yakin banyak pengguna Linux yang berpengalaman memiliki kruk pengalaman seperti itu, dan menyalin yang lain tidak perlu.

Buat volume pada perangkat cadangan:

#lvcreate -L 256G --name backup backup

Format dalam BTRFS:

#mkfs.btrfs /dev/backup/backup

Buat poin mount dan mount subkunci root FS: Buat direktori untuk backup: Buat direktori untuk skrip cadangan: Salin skrip:

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

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



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



#mkdir /root/btrfs-backup



Banyak kode bash yang menakutkan. Gunakan dengan risiko Anda sendiri. Penulis tidak menulis surat kemarahan ...
#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 "%f\n" | 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 bahkan dilakukannya ..?
BTRFS BTRFS send/recieve.

Peluncuran pertama bisa relatif lama, karena di awal semua data akan disalin. Peluncuran lebih lanjut akan sangat cepat, karena hanya perubahan yang akan disalin.

Script lain untuk menjejalkan ke 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 yang sedang dilakukannya ..?
backup BTRFS-. 60 . /backup/btrfs/back/remote/ .

Mari berikan kode yang tepat untuk dieksekusi: Periksa dan masukkan ke dalam mahkota:

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



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

LVM thin backup


Buat kumpulan tipis pada perangkat cadangan:

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

Instal ddrescue, karena skrip akan menggunakan alat ini:

#apt-get install gddrescue

Buat direktori untuk skrip:

#mkdir /root/lvm-thin-backup

Salin skrip:

Banyak bash 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 yang dilakukannya ...?
, thin_delta, ddrescue blkdiscard.

Skrip lain yang akan kami jadikan mahkota:

Bash 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 yang dilakukannya ...?
, . , .

Skrip ini perlu diedit, yang menunjukkan daftar volume tipis yang memerlukan cadangan. Nama-nama yang diberikan hanya untuk tujuan ilustrasi. Jika mau, Anda dapat menulis skrip yang akan menyinkronkan semua volume.

Mari kita beri hak: Periksa dan masukkan ke dalam mahkota: Peluncuran pertama akan lama, karena volume tipis akan sepenuhnya disinkronkan dengan menyalin seluruh ruang yang digunakan. Berkat metadata tipis LVM, kami tahu blok mana yang benar-benar digunakan, jadi hanya blok volume yang benar-benar digunakan yang akan disalin. Peluncuran selanjutnya akan menyalin data secara bertahap dengan melacak perubahan melalui metadata tipis LVM.

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




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





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 .@snap.2020-03-06-09-39-37
drwxr-xr-x 1 root root 516 6 09:39 .@snap.2020-03-06-09-39-57
...
/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 @home.@snap.2020-03-06-09-39-35
drwxr-xr-x 1 root root 22 6 09:39 @home.@snap.2020-03-06-09-39-57
...
drwxr-xr-x 1 root root 240 6 09:39 @.@snap.2020-03-06-09-39-26
drwxr-xr-x 1 root root 240 6 09:39 @.@snap.2020-03-06-09-39-56
...

#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

Dan bagaimana dengan boneka bersarang?


Kemungkinan besar, meskipun volume logis LVM LV dapat volume LVM fisik untuk VG lainnya. LVM bisa bersifat rekursif, seperti boneka bersarang. Ini memberikan fleksibilitas ekstrim LVM.

PS


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

All Articles