LVM và Matryoshka có điểm gì chung?

Xin chào buổi ngày.
Tôi muốn chia sẻ với cộng đồng kinh nghiệm thực tế của tôi khi xây dựng hệ thống lưu trữ dữ liệu cho KVM bằng md RAID + LVM.

Chương trình sẽ bao gồm:

  • Xây dựng md RAID 1 từ SSD NVMe.
  • Lắp ráp md RAID 6 từ SSD SATA và ổ đĩa thông thường.
  • Tính năng hoạt động TRIM/DISCARD trên SSD RAID 1/6.
  • Tạo mảng md RAID 1/6 có khả năng khởi động trên một bộ đĩa chung.
  • Cài đặt hệ thống trên NVMe RAID 1 khi chưa có hỗ trợ NVMe trong BIOS.
  • Sử dụng bộ đệm LVM và LVM mỏng.
  • Sử dụng ảnh chụp nhanh BTRFS và gửi/nhận để sao lưu.
  • Sử dụng ảnh chụp nhanh LVM và Thin_delta để sao lưu kiểu BTRFS.

Nếu bạn quan tâm, vui lòng xem mèo.

Заявление

Tác giả không chịu bất kỳ trách nhiệm nào về hậu quả của việc sử dụng hoặc không sử dụng tài liệu/ví dụ/mã/mẹo/dữ liệu từ bài viết này. Bằng cách đọc hoặc sử dụng tài liệu này theo bất kỳ cách nào, bạn phải chịu trách nhiệm về mọi hậu quả của những hành động này. Hậu quả có thể xảy ra bao gồm:

  • SSD NVMe chiên giòn.
  • Đã sử dụng hết tài nguyên ghi và lỗi ổ SSD.
  • Mất toàn bộ dữ liệu trên tất cả các ổ đĩa, kể cả các bản sao lưu.
  • Phần cứng máy tính bị lỗi.
  • Lãng phí thời gian, thần kinh và tiền bạc.
  • Bất kỳ hậu quả nào khác không được liệt kê ở trên.

Sắt

Có sẵn là:

Bo mạch chủ từ khoảng năm 2013 với chipset Z87, hoàn chỉnh với Intel Core i7 / Haswell.

  • Bộ xử lý 4 nhân 8 luồng
  • RAM 32GB DDR3
  • 1 x 16 hoặc 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • Đầu nối SATA 6 6 x 3Gbps

Bộ chuyển đổi SAS LSI SAS9211-8I flash sang chế độ IT/HBA. Phần sụn hỗ trợ RAID đã được cố ý thay thế bằng phần sụn HBA để:

  1. Bạn có thể vứt bỏ bộ chuyển đổi này bất cứ lúc nào và thay thế nó bằng bất kỳ bộ chuyển đổi nào khác mà bạn gặp.
  2. TRIM/Discard hoạt động bình thường trên các đĩa, vì... trong phần mềm RAID, các lệnh này hoàn toàn không được hỗ trợ và HBA nói chung không quan tâm đến lệnh nào được truyền qua bus.

Ổ cứng - 8 chiếc HGST Travelstar 7K1000 dung lượng 1 TB dạng 2.5 dành cho máy tính xách tay. Các ổ đĩa này trước đây nằm trong mảng RAID 6. Họ cũng sẽ có ích trong hệ thống mới. Để lưu trữ các bản sao lưu cục bộ.

Ngoài ra đã thêm:

6 chiếc SSD SATA model Samsung 860 QVO 2TB. Những ổ SSD này yêu cầu dung lượng lớn, sự hiện diện của bộ đệm SLC, độ tin cậy và mức giá thấp là điều mong muốn. Cần có hỗ trợ loại bỏ/không, được kiểm tra bằng dòng trong dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 chiếc SSD NVMe model Samsung SSD 970 EVO 500GB.

Đối với những ổ SSD này, tốc độ đọc/ghi ngẫu nhiên và dung lượng tài nguyên đáp ứng nhu cầu của bạn là rất quan trọng. Bộ tản nhiệt cho họ. Cần thiết. Tuyệt đối. Nếu không, hãy chiên chúng cho đến khi giòn trong lần đồng bộ hóa RAID đầu tiên.

Bộ chuyển đổi StarTech PEX8M2E2 dành cho 2 x SSD NVMe được cài đặt trong khe cắm PCIe 3.0 8x. Một lần nữa, đây chỉ là HBA, dành cho NVMe. Nó khác với các bộ điều hợp giá rẻ ở chỗ nó không yêu cầu hỗ trợ phân nhánh PCIe từ bo mạch chủ do có bộ chuyển đổi PCIe tích hợp. Nó sẽ hoạt động ngay cả trong hệ thống cổ xưa nhất có PCIe, ngay cả khi đó là khe cắm x1 PCIe 1.0. Đương nhiên, với tốc độ thích hợp. Không có RAID ở đó. Không có BIOS tích hợp trên tàu. Vì vậy, hệ thống của bạn sẽ không học cách khởi động bằng NVMe một cách thần kỳ, càng không thể thực hiện RAID NVMe nhờ thiết bị này.

Thành phần này chỉ là do hệ thống chỉ có một 8x PCIe 3.0 miễn phí và nếu có 2 khe cắm trống, nó có thể dễ dàng thay thế bằng hai xu PEX4M2E1 hoặc các loại tương tự, có thể mua ở bất cứ đâu với mức giá 600 rúp.

Việc từ chối tất cả các loại phần cứng hoặc chipset/BIOS RAID tích hợp được thực hiện có chủ ý để có thể thay thế hoàn toàn toàn bộ hệ thống, ngoại trừ chính SSD/HDD, trong khi vẫn bảo toàn tất cả dữ liệu. Lý tưởng nhất là bạn có thể lưu ngay cả hệ điều hành đã cài đặt khi chuyển sang phần cứng hoàn toàn mới/khác. Cái chính là có cổng SATA và PCIe. Nó giống như một đĩa CD trực tiếp hoặc ổ đĩa flash có khả năng khởi động, chỉ có điều là rất nhanh và hơi cồng kềnh.

ЮморNếu không, bạn biết điều gì sẽ xảy ra - đôi khi bạn cần gấp mang theo toàn bộ mảng để mang đi. Nhưng tôi không muốn mất dữ liệu. Để thực hiện điều này, tất cả các phương tiện được đề cập đều được đặt ở vị trí thuận tiện trên các slide trong khoang 5.25 của hộp đựng tiêu chuẩn.

Vâng, và tất nhiên là để thử nghiệm các phương pháp lưu trữ SSD khác nhau trong Linux.

Các cuộc tấn công phần cứng thật nhàm chán. Bật nó lên. Nó hoạt động hoặc không. Và với mdadm luôn có nhiều lựa chọn.

Phần mềm

Trước đây, Debian 8 Jessie đã được cài đặt trên phần cứng gần với EOL. RAID 6 được tập hợp từ các ổ cứng HDD nêu trên được ghép nối với LVM. Nó chạy các máy ảo trong kvm/libvirt.

Bởi vì Tác giả có kinh nghiệm phù hợp trong việc tạo ổ đĩa flash SATA/NVMe có khả năng khởi động di động, đồng thời, để không phá vỡ mẫu apt thông thường, Ubuntu 18.04 đã được chọn làm hệ thống mục tiêu, hệ thống này đã đủ ổn định nhưng vẫn còn 3 năm hoạt động. hỗ trợ trong tương lai.

Hệ thống được đề cập chứa tất cả các trình điều khiển phần cứng mà chúng tôi cần ngay lập tức. Chúng tôi không cần bất kỳ phần mềm hoặc trình điều khiển nào của bên thứ ba.

Chuẩn bị cài đặt

Để cài đặt hệ thống, chúng ta cần Ubuntu Desktop Image. Hệ thống máy chủ có một số loại trình cài đặt mạnh mẽ, thể hiện tính độc lập quá mức mà không thể vô hiệu hóa bằng cách đẩy phân vùng hệ thống UEFI vào một trong các đĩa, làm hỏng tất cả vẻ đẹp. Theo đó, nó chỉ được cài đặt ở chế độ UEFI. Không cung cấp bất kỳ tùy chọn nào.

Chúng tôi không hài lòng với điều này.

Tại sao?Thật không may, UEFI boot cực kỳ kém tương thích với RAID phần mềm khởi động, bởi vì... Không ai đề nghị chúng tôi đặt trước phân vùng UEFI ESP. Có những công thức trực tuyến đề xuất đặt phân vùng ESP trên ổ flash qua cổng USB, nhưng đây là một điểm thất bại. Có những công thức sử dụng phần mềm mdadm RAID 1 với siêu dữ liệu phiên bản 0.9 không ngăn UEFI BIOS nhìn thấy phân vùng này, nhưng điều này vẫn tồn tại cho đến thời điểm vui vẻ khi BIOS hoặc một hệ điều hành phần cứng khác ghi nội dung nào đó vào ESP và quên đồng bộ hóa nó với phần mềm khác. những tấm gương.

Ngoài ra, khả năng khởi động UEFI phụ thuộc vào NVRAM, sẽ không di chuyển cùng với các đĩa sang hệ thống mới, bởi vì là một phần của bo mạch chủ.

Vì vậy, chúng tôi sẽ không phát minh lại một bánh xe mới. Chúng tôi đã có sẵn một chiếc xe đạp dành cho ông nội đã được thử nghiệm theo thời gian, hiện được gọi là Legacy/BIOS boot, mang cái tên đáng tự hào là CSM trên các hệ thống tương thích với UEFI. Chúng ta sẽ chỉ cần lấy nó ra khỏi kệ, bôi trơn, bơm lốp và lau bằng khăn ẩm.

Phiên bản Ubuntu dành cho máy tính để bàn cũng không thể được cài đặt đúng cách với bộ tải khởi động Legacy, nhưng ở đây, như người ta nói, ít nhất cũng có các tùy chọn.

Vì vậy, chúng tôi thu thập phần cứng và tải hệ thống từ ổ flash có khả năng khởi động Ubuntu Live. Chúng tôi sẽ cần tải xuống các gói nên chúng tôi sẽ thiết lập mạng phù hợp với bạn. Nếu nó không hoạt động, bạn có thể tải trước các gói cần thiết vào ổ đĩa flash.

Chúng tôi đi vào môi trường Máy tính để bàn, khởi chạy trình mô phỏng thiết bị đầu cuối và bắt đầu:

#sudo bash

Làm sao…?Dòng trên là trình kích hoạt chuẩn cho các kỳ nghỉ lễ về sudo. C bоcơ hội lớn hơn đến vàоtrách nhiệm lớn hơn. Câu hỏi là liệu bạn có thể tự mình gánh lấy nó hay không. Nhiều người cho rằng dùng sudo theo cách này ít nhất là không cẩn thận. Tuy nhiên:

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

Tại sao không phải là ZFS...?Khi chúng tôi cài đặt phần mềm trên máy tính của mình, về cơ bản, chúng tôi cho các nhà phát triển phần mềm này mượn phần cứng của mình để điều khiển.
Khi chúng tôi tin tưởng phần mềm này đảm bảo an toàn cho dữ liệu của mình, chúng tôi sẽ vay một khoản bằng chi phí khôi phục dữ liệu này và một ngày nào đó chúng tôi sẽ phải trả hết.

Từ quan điểm này, ZFS là một chiếc Ferrari và mdadm+lvm giống một chiếc xe đạp hơn.

Về mặt chủ quan, tác giả thích cho những người không quen biết mượn một chiếc xe đạp thay vì một chiếc Ferrari. Ở đó, giá phát hành không cao. Không cần quyền lợi. Đơn giản hơn quy tắc giao thông. Bãi đậu xe miễn phí. Khả năng xuyên quốc gia tốt hơn. Bạn luôn có thể gắn chân vào xe đạp và bạn có thể sửa xe đạp bằng chính đôi tay của mình.

Tại sao lại là BTRFS...?Để khởi động hệ điều hành, chúng tôi cần một hệ thống tệp được hỗ trợ ngay trong Legacy/BIOS GRUB, đồng thời hỗ trợ ảnh chụp nhanh trực tiếp. Chúng ta sẽ sử dụng nó cho phân vùng /boot. Ngoài ra, tác giả thích sử dụng FS này cho / (root), không quên lưu ý rằng đối với bất kỳ phần mềm nào khác, bạn có thể tạo các phân vùng riêng trên LVM và mount chúng vào các thư mục cần thiết.

Chúng tôi sẽ không lưu trữ bất kỳ hình ảnh nào của máy ảo hoặc cơ sở dữ liệu trên FS này.
FS này sẽ chỉ được sử dụng để tạo các ảnh chụp nhanh của hệ thống mà không cần tắt hệ thống và sau đó chuyển các ảnh chụp nhanh này sang đĩa sao lưu bằng cách sử dụng gửi/nhận.

Ngoài ra, tác giả thường thích giữ tối thiểu phần mềm trực tiếp trên phần cứng và chạy tất cả phần mềm khác trong máy ảo bằng cách sử dụng những thứ như chuyển tiếp GPU và bộ điều khiển máy chủ PCI-USB sang KVM thông qua IOMMU.

Những thứ duy nhất còn lại trên phần cứng là lưu trữ dữ liệu, ảo hóa và sao lưu.

Nếu bạn tin tưởng ZFS hơn, thì về nguyên tắc, đối với ứng dụng được chỉ định, chúng có thể thay thế cho nhau.

Tuy nhiên, tác giả cố tình bỏ qua các tính năng phản chiếu/RAID và dự phòng tích hợp mà ZFS, BRTFS và LVM có.

Là một lập luận bổ sung, BTRFS có khả năng biến việc ghi ngẫu nhiên thành ghi tuần tự, điều này có tác động cực kỳ tích cực đến tốc độ đồng bộ hóa ảnh chụp nhanh/sao lưu trên ổ cứng.

Hãy quét lại tất cả các thiết bị:

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

Chúng ta hãy nhìn xung quanh:

#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

Bố trí đĩa

SSD NVMe

Nhưng chúng tôi sẽ không đánh dấu chúng dưới bất kỳ hình thức nào. Tương tự, BIOS của chúng tôi không nhìn thấy các ổ đĩa này. Vì vậy, họ sẽ hoàn toàn chuyển sang RAID phần mềm. Chúng tôi thậm chí sẽ không tạo các phần ở đó. Nếu bạn muốn làm theo “chuẩn” hoặc “chủ yếu”, hãy tạo một phân vùng lớn, chẳng hạn như ổ cứng HDD.

Ổ cứng SATA

Không cần phải phát minh ra bất cứ điều gì đặc biệt ở đây. Chúng tôi sẽ tạo một phần cho mọi thứ. Chúng tôi sẽ tạo một phân vùng vì BIOS nhìn thấy những đĩa này và thậm chí có thể cố gắng khởi động từ chúng. Chúng tôi thậm chí sẽ cài đặt GRUB trên các đĩa này sau để hệ thống có thể bất ngờ thực hiện việc này.

#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

Đây là nơi mọi thứ trở nên thú vị đối với chúng tôi.

Thứ nhất, ổ đĩa của chúng tôi có kích thước 2 TB. Giá trị này nằm trong phạm vi chấp nhận được đối với MBR, đây là phạm vi chúng tôi sẽ sử dụng. Nếu cần thiết có thể thay thế bằng GPT. Đĩa GPT có lớp tương thích cho phép các hệ thống tương thích MBR nhìn thấy 4 phân vùng đầu tiên nếu chúng nằm trong 2 terabyte đầu tiên. Điều chính là phân vùng khởi động và phân vùng bios_grub trên các đĩa này phải ở đầu. Điều này thậm chí còn cho phép bạn khởi động từ ổ đĩa GPT Legacy/BIOS.

Nhưng đây không phải là trường hợp của chúng tôi.

Ở đây chúng ta sẽ tạo hai phần. Cái đầu tiên sẽ có kích thước 1 GB và được sử dụng cho RAID 1/boot.

Cái thứ hai sẽ được sử dụng cho RAID 6 và sẽ chiếm toàn bộ dung lượng trống còn lại ngoại trừ một vùng nhỏ chưa được phân bổ ở cuối ổ đĩa.

Khu vực không được đánh dấu này là gì?Theo các nguồn trên mạng, ổ SSD SATA của chúng tôi có bộ đệm SLC có thể mở rộng linh hoạt với kích thước từ 6 đến 78 gigabyte. Chúng tôi nhận được 6 gigabyte “miễn phí” do sự khác biệt giữa “gigabyte” và “gibibytes” trong bảng dữ liệu của ổ đĩa. 72 gigabyte còn lại được phân bổ từ không gian chưa sử dụng.

Ở đây cần lưu ý rằng chúng tôi có bộ đệm SLC và dung lượng bị chiếm ở chế độ MLC 4 bit. Điều này đối với chúng tôi có nghĩa là cứ 4 gigabyte dung lượng trống, chúng tôi sẽ chỉ nhận được 1 gigabyte bộ nhớ đệm SLC.

Nhân 72 gigabyte với 4 và nhận được 288 gigabyte. Đây là dung lượng trống mà chúng tôi sẽ không đánh dấu để cho phép các ổ đĩa tận dụng tối đa bộ đệm SLC.

Do đó, chúng tôi sẽ nhận được tới 312 gigabyte bộ nhớ đệm SLC từ tổng số sáu ổ đĩa một cách hiệu quả. Trong số tất cả các ổ đĩa, 2 ổ sẽ được sử dụng trong RAID để dự phòng.

Lượng bộ đệm này sẽ cho phép chúng ta cực kỳ hiếm khi gặp phải tình huống ghi không vào bộ đệm trong đời thực. Điều này bù đắp cực kỳ tốt cho nhược điểm đáng buồn nhất của bộ nhớ QLC - tốc độ ghi cực thấp khi dữ liệu được ghi bỏ qua bộ đệm. Nếu tải của bạn không tương ứng với mức tải này, thì tôi khuyên bạn nên suy nghĩ kỹ xem SSD của bạn sẽ tồn tại được bao lâu dưới mức tải như vậy, có tính đến TBW từ bảng dữ liệu.

#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

Tạo mảng

Đầu tiên chúng ta cần đổi tên máy. Điều này là cần thiết vì tên máy chủ là một phần của tên mảng ở đâu đó bên trong mdadm và ảnh hưởng đến thứ gì đó ở đâu đó. Tất nhiên, mảng có thể được đổi tên sau này, nhưng đây là bước không cần thiết.

#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

Tại sao -giả sử-sạch...?Để tránh khởi tạo mảng. Đối với cả cấp độ RAID 1 và 6, điều này hợp lệ. Mọi thứ có thể hoạt động mà không cần khởi tạo nếu đó là một mảng mới. Hơn nữa, việc khởi tạo mảng SSD khi tạo là một sự lãng phí tài nguyên TBW. Chúng tôi sử dụng TRIM/DISCARD nếu có thể trên các mảng SSD đã lắp ráp để “khởi tạo” chúng.

Đối với mảng SSD, RAID 1 DISCARD được hỗ trợ ngay lập tức.

Đối với mảng SSD RAID 6 DISCARD, bạn phải kích hoạt nó trong thông số mô-đun hạt nhân.

Điều này chỉ nên được thực hiện nếu tất cả các ổ SSD được sử dụng trong mảng cấp 4/5/6 trong hệ thống này đều có hỗ trợ hoạt động cho loại bỏ_zeroes_data. Đôi khi bạn gặp các ổ đĩa lạ báo cho kernel biết rằng chức năng này được hỗ trợ, nhưng thực tế là nó không có ở đó hoặc chức năng này không phải lúc nào cũng hoạt động. Hiện tại, hầu hết mọi nơi đều có hỗ trợ, tuy nhiên, có những ổ đĩa và chương trình cơ sở cũ bị lỗi. Vì lý do này, hỗ trợ DISCARD bị tắt theo mặc định đối với RAID 6.

Chú ý, lệnh sau sẽ hủy tất cả dữ liệu trên ổ NVMe bằng cách “khởi tạo” mảng bằng “số XNUMX”.

#blkdiscard /dev/md0

Nếu có sự cố xảy ra, hãy thử chỉ định một bước.

#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

Tại sao lại lớn như vậy...?Việc tăng kích thước khối có tác động tích cực đến tốc độ đọc ngẫu nhiên trong các khối bao gồm cả kích thước khối. Điều này xảy ra vì một thao tác có kích thước phù hợp hoặc nhỏ hơn có thể được hoàn thành hoàn toàn trên một thiết bị. Do đó, IOPS từ tất cả các thiết bị được tổng hợp. Theo thống kê, 99% IO không vượt quá 512K.

RAID 6 IOPS mỗi lần ghi luôn luôn nhỏ hơn hoặc bằng IOPS của một ổ đĩa. Khi đọc ngẫu nhiên, IOPS có thể lớn hơn vài lần so với một ổ đĩa và ở đây kích thước khối có tầm quan trọng then chốt.
Tác giả không thấy có ích gì khi cố gắng tối ưu hóa một tham số kém trong thiết kế phụ của RAID 6 và thay vào đó hãy tối ưu hóa những gì RAID 6 làm tốt.
Chúng tôi sẽ bù đắp cho khả năng ghi ngẫu nhiên kém của RAID 6 bằng bộ nhớ đệm NVMe và các thủ thuật cung cấp dung lượng mỏng.

Chúng tôi chưa kích hoạt DISCARD cho RAID 6. Vì vậy, bây giờ chúng tôi sẽ không “khởi tạo” mảng này. Chúng ta sẽ thực hiện việc này sau, sau khi cài đặt hệ điều hành.

Ổ cứng SATA

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

LVM trên NVMe RAID

Để có tốc độ, chúng tôi muốn đặt hệ thống tệp gốc trên NVMe RAID 1 là /dev/md0.
Tuy nhiên, chúng tôi vẫn sẽ cần mảng nhanh này cho các nhu cầu khác, chẳng hạn như trao đổi, siêu dữ liệu và siêu dữ liệu LVM-cache và LVM-thin, vì vậy chúng tôi sẽ tạo LVM VG trên mảng này.

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

Hãy tạo một phân vùng cho hệ thống tập tin gốc.

#lvcreate -L 128G --name root root

Hãy tạo một phân vùng để trao đổi theo kích thước của RAM.

#lvcreate -L 32G --name swap root

Cài đặt hệ điều hành

Tổng cộng, chúng tôi có mọi thứ cần thiết để cài đặt hệ thống.

Khởi chạy trình hướng dẫn cài đặt hệ thống từ môi trường Ubuntu Live. Cài đặt bình thường. Chỉ ở giai đoạn chọn đĩa để cài đặt, bạn cần chỉ định những điều sau:

  • /dev/md1, - điểm gắn kết /boot, FS - BTRFS
  • /dev/root/root (còn gọi là /dev/mapper/root-root), - điểm gắn kết / (root), FS - BTRFS
  • /dev/root/swap (còn gọi là /dev/mapper/root-swap), - sử dụng làm phân vùng trao đổi
  • Cài đặt bộ nạp khởi động trên/dev/sda

Khi bạn chọn BTRFS làm hệ thống tập tin gốc, trình cài đặt sẽ tự động tạo hai tập BTRFS có tên là "@" cho / (root) và "@home" cho /home.

Hãy bắt đầu cài đặt...

Quá trình cài đặt sẽ kết thúc bằng một hộp thoại phương thức cho biết có lỗi khi cài đặt bộ nạp khởi động. Thật không may, bạn sẽ không thể thoát khỏi hộp thoại này bằng các phương tiện tiêu chuẩn và tiếp tục cài đặt. Chúng tôi đăng xuất khỏi hệ thống và đăng nhập lại, kết thúc bằng một máy tính để bàn Ubuntu Live sạch sẽ. Mở terminal và một lần nữa:

#sudo bash

Tạo môi trường chroot để tiếp tục cài đặt:

#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

Hãy cấu hình mạng và tên máy chủ trong chroot:

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

Hãy đi vào môi trường chroot:

#chroot /mnt/chroot

Trước hết, chúng tôi sẽ giao các gói hàng:

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

Hãy kiểm tra và sửa chữa tất cả các gói được cài đặt quanh co do cài đặt hệ thống chưa đầy đủ:

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

Nếu có gì đó không ổn, trước tiên bạn có thể cần chỉnh sửa /etc/apt/sources.list

Hãy điều chỉnh các thông số cho mô-đun RAID 6 để kích hoạt TRIM/DISCARD:

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

Hãy điều chỉnh mảng của chúng ta một chút:

#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

Nó là cái gì vậy..?Chúng tôi đã tạo một bộ quy tắc udev sẽ thực hiện những việc sau:

  • Đặt kích thước bộ đệm khối cho RAID 2020 là đủ cho năm 6. Có vẻ như giá trị mặc định đã không thay đổi kể từ khi Linux được tạo ra và đã không còn đủ trong một thời gian dài.
  • Dự trữ tối thiểu IO trong suốt thời gian kiểm tra/đồng bộ hóa mảng. Điều này nhằm ngăn mảng của bạn bị kẹt trong trạng thái đồng bộ hóa vĩnh viễn khi tải.
  • Giới hạn IO tối đa trong quá trình kiểm tra/đồng bộ hóa mảng. Điều này là cần thiết để việc đồng bộ hóa/kiểm tra RAID SSD không làm ổ đĩa của bạn bị hỏng. Điều này đặc biệt đúng với NVMe. (Bạn có nhớ về bộ tản nhiệt không? Tôi không nói đùa đâu.)
  • Cấm các đĩa dừng quay trục chính (HDD) qua APM và đặt thời gian chờ cho bộ điều khiển đĩa là 7 giờ. Bạn hoàn toàn có thể tắt APM nếu ổ đĩa của bạn có thể làm được điều đó (-B 255). Với giá trị mặc định, các ổ đĩa sẽ dừng sau năm giây. Sau đó, hệ điều hành muốn thiết lập lại bộ nhớ đệm của ổ đĩa, các ổ đĩa sẽ quay trở lại và mọi thứ sẽ bắt đầu lại từ đầu. Đĩa có số vòng quay trục chính tối đa hạn chế. Chu kỳ mặc định đơn giản như vậy có thể dễ dàng làm hỏng ổ đĩa của bạn sau vài năm. Không phải tất cả các ổ đĩa đều gặp phải vấn đề này, nhưng ổ đĩa của chúng tôi là ổ đĩa "máy tính xách tay", với các cài đặt mặc định thích hợp, khiến RAID trông giống như một MAID mini.
  • Cài đặt readahead trên đĩa (xoay) 1 megabyte - hai khối/đoạn liên tiếp RAID 6
  • Vô hiệu hóa việc đọc trước trên các mảng.

Hãy chỉnh sửa /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

Tại sao vậy..?Chúng ta sẽ tìm kiếm phân vùng /boot bằng UUID. Về mặt lý thuyết, việc đặt tên mảng có thể thay đổi.

Chúng tôi sẽ tìm kiếm các phần còn lại theo tên LVM trong ký hiệu /dev/mapper/vg-lv, bởi vì họ xác định các phân vùng khá độc đáo.

Chúng tôi không sử dụng UUID cho LVM vì UUID của khối LVM và ảnh chụp nhanh của chúng có thể giống nhau.Gắn kết /dev/mapper/root-root.. hai lần?Đúng. Chính xác. Tính năng của BTRFS. Hệ thống tập tin này có thể được gắn kết nhiều lần với các subvol khác nhau.

Do tính năng tương tự này, tôi khuyên bạn không bao giờ tạo ảnh chụp nhanh LVM của các khối BTRFS đang hoạt động. Bạn có thể nhận được một bất ngờ khi khởi động lại.

Hãy tạo lại cấu hình mdadm:

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

Hãy điều chỉnh cài đặt 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

Nó là cái gì vậy..?Chúng tôi đã cho phép tự động mở rộng nhóm mỏng LVM khi đạt 90% không gian chiếm dụng bằng 5% thể tích.

Chúng tôi đã tăng số lượng khối bộ đệm tối đa cho bộ đệm LVM.

Chúng tôi đã ngăn LVM tìm kiếm các tập LVM (PV) trên:

  • thiết bị chứa bộ đệm LVM (cdata)
  • các thiết bị được lưu vào bộ đệm bằng bộ đệm LVM, bỏ qua bộ đệm ( _corig). Trong trường hợp này, bản thân thiết bị được lưu trong bộ nhớ đệm sẽ vẫn được quét qua bộ nhớ đệm (chỉ ).
  • thiết bị chứa siêu dữ liệu bộ đệm LVM (cmeta)
  • tất cả các thiết bị trong VG có hình ảnh tên. Ở đây chúng tôi sẽ có hình ảnh đĩa của máy ảo và chúng tôi không muốn LVM trên máy chủ kích hoạt các ổ đĩa thuộc hệ điều hành khách.
  • tất cả các thiết bị trong VG có tên dự phòng. Ở đây chúng ta sẽ có bản sao lưu image của máy ảo.
  • tất cả các thiết bị có tên kết thúc bằng “gpv” (ổ đĩa vật lý của khách)

Chúng tôi đã bật hỗ trợ DISCARD khi giải phóng dung lượng trống trên LVM VG. Hãy cẩn thận. Điều này sẽ khiến việc xóa LV trên SSD khá tốn thời gian. Điều này đặc biệt áp dụng cho SSD RAID 6. Tuy nhiên, theo kế hoạch, chúng tôi sẽ sử dụng khả năng cung cấp mỏng nên điều này sẽ không gây trở ngại gì cho chúng tôi.

Hãy cập nhật hình ảnh initramfs:

#update-initramfs -u -k all

Cài đặt và cấu hình grub:

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

Bạn nên chọn những đĩa nào?Tất cả những ai là sd*. Hệ thống phải có khả năng khởi động từ bất kỳ ổ đĩa SATA hoặc SSD nào đang hoạt động.

Tại sao họ thêm os-prober..?Để có được sự độc lập quá mức và đôi bàn tay vui tươi.

Nó không hoạt động chính xác nếu một trong các RAID ở trạng thái xuống cấp. Nó cố gắng tìm kiếm HĐH trên các phân vùng được sử dụng trong các máy ảo chạy trên phần cứng này.

Nếu cần, bạn có thể để lại nhưng hãy ghi nhớ tất cả những điều trên. Tôi khuyên bạn nên tìm kiếm các công thức để thoát khỏi bàn tay nghịch ngợm trên mạng.

Với điều này, chúng tôi đã hoàn thành việc cài đặt ban đầu. Đã đến lúc khởi động lại vào hệ điều hành mới được cài đặt. Đừng quên tháo Live CD/USB có khả năng khởi động.

#exit
#reboot

Chọn bất kỳ ổ SSD SATA nào làm thiết bị khởi động.

LVM trên SSD SATA

Tại thời điểm này, chúng tôi đã khởi động vào hệ điều hành mới, định cấu hình mạng, apt, mở trình mô phỏng thiết bị đầu cuối và chạy:

#sudo bash

Tiếp tục đi.

“Khởi tạo” mảng từ SSD SATA:

#blkdiscard /dev/md2

Nếu nó không hoạt động, hãy thử:

#blkdiscard --step 65536 /dev/md2
Tạo LVM VG trên SSD SATA:

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

Tại sao lại là một VG khác..?Trên thực tế, chúng ta đã có một root tên là VG. Tại sao không thêm mọi thứ vào một VG?

Nếu có một số PV trong một VG thì để VG được kích hoạt chính xác, tất cả các PV phải có mặt (trực tuyến). Ngoại lệ là LVM RAID mà chúng tôi cố tình không sử dụng.

Chúng tôi thực sự muốn rằng nếu xảy ra lỗi (mất dữ liệu đọc) trên bất kỳ mảng RAID 6 nào, hệ điều hành sẽ khởi động bình thường và cho chúng tôi cơ hội giải quyết vấn đề.

Để làm điều này, ở mức độ trừu tượng đầu tiên, chúng tôi sẽ tách từng loại “phương tiện” vật lý thành một VG riêng biệt.

Nói một cách khoa học, các mảng RAID khác nhau thuộc về các “miền đáng tin cậy” khác nhau. Bạn không nên tạo thêm một điểm thất bại chung cho họ bằng cách nhồi nhét họ vào một VG.

Sự hiện diện của LVM ở cấp độ “phần cứng” sẽ cho phép chúng ta tùy ý cắt các phần của mảng RAID khác nhau bằng cách kết hợp chúng theo những cách khác nhau. Ví dụ - chạy cùng một lúc bcache + LVM mỏng, bcache + BTRFS, LVM cache + LVM mỏng, một cấu hình ZFS phức tạp với bộ nhớ đệm hoặc bất kỳ hỗn hợp khủng khiếp nào khác để thử và so sánh tất cả.

Ở cấp độ “phần cứng”, chúng tôi sẽ không sử dụng bất cứ thứ gì ngoài các khối LVM “dày” cũ tốt. Ngoại lệ cho quy tắc này có thể là phân vùng sao lưu.

Tôi nghĩ vào thời điểm này, nhiều độc giả đã bắt đầu nghi ngờ điều gì đó về con búp bê làm tổ.

LVM trên ổ cứng SATA

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

VG mới nữa à..?Chúng tôi thực sự muốn rằng nếu mảng đĩa mà chúng tôi sẽ sử dụng để sao lưu dữ liệu bị lỗi, hệ điều hành của chúng tôi sẽ tiếp tục hoạt động bình thường trong khi vẫn duy trì quyền truy cập vào dữ liệu không sao lưu như bình thường. Do đó, để tránh sự cố kích hoạt VG, chúng tôi tạo một VG riêng.

Thiết lập bộ đệm LVM

Hãy tạo LV trên NVMe RAID 1 để sử dụng nó làm thiết bị lưu trữ.

#lvcreate -L 70871154688B --name cache root

Tại sao lại có ít như vậy...?Thực tế là SSD NVMe của chúng tôi cũng có bộ đệm SLC. 4 gigabyte “miễn phí” và 18 gigabyte động do không gian trống bị chiếm trong MLC 3 bit. Khi bộ đệm này hết, SSD NVMe sẽ không nhanh hơn nhiều so với SSD SATA có bộ đệm của chúng tôi. Trên thực tế, vì lý do này, việc chúng tôi tạo phân vùng bộ đệm LVM lớn hơn gấp đôi kích thước bộ đệm SLC của ổ NVMe là vô nghĩa. Đối với các ổ NVMe được sử dụng, tác giả cho rằng việc tạo bộ đệm 32-64 gigabyte là hợp lý.

Cần có kích thước phân vùng nhất định để sắp xếp 64 gigabyte bộ đệm, siêu dữ liệu bộ đệm và sao lưu siêu dữ liệu.

Ngoài ra, tôi lưu ý rằng sau khi tắt hệ thống do lỗi bẩn, LVM sẽ đánh dấu toàn bộ bộ đệm là bẩn và sẽ đồng bộ hóa lại. Hơn nữa, điều này sẽ được lặp lại mỗi lần sử dụng lvchange trên thiết bị này cho đến khi hệ thống được khởi động lại. Do đó, tôi khuyên bạn nên tạo lại bộ đệm ngay lập tức bằng tập lệnh thích hợp.

Hãy tạo LV trên SATA RAID 6 để sử dụng nó làm thiết bị lưu trữ.

#lvcreate -L 3298543271936B --name cache data

Tại sao chỉ có ba terabyte..?Vì vậy, nếu cần, bạn có thể sử dụng SATA SSD RAID 6 cho một số nhu cầu khác. Kích thước của không gian lưu trữ có thể được tăng lên một cách linh hoạt, nhanh chóng mà không cần dừng hệ thống. Để thực hiện việc này, bạn cần tạm thời dừng và kích hoạt lại bộ đệm, nhưng ưu điểm đặc biệt của bộ đệm LVM so với bcache là việc này có thể được thực hiện nhanh chóng.

Hãy tạo một VG mới cho bộ nhớ đệm.

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

Hãy tạo LV trên thiết bị được lưu trong bộ nhớ đệm.

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

Ở đây, chúng tôi ngay lập tức chiếm toàn bộ dung lượng trống trên /dev/data/cache để tất cả các phân vùng cần thiết khác được tạo ngay trên /dev/root/cache. Nếu bạn tạo nội dung nào đó không đúng chỗ, bạn có thể di chuyển nội dung đó bằng pvmove.

Hãy tạo và kích hoạt bộ đệm:

#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

Tại sao lại có kích thước lớn như vậy ..?Qua thử nghiệm thực tế, tác giả có thể phát hiện ra rằng đạt được kết quả tốt nhất nếu kích thước của khối bộ đệm LVM trùng với kích thước của khối mỏng LVM. Hơn nữa, kích thước càng nhỏ thì cấu hình càng hoạt động tốt hơn trong quá trình ghi ngẫu nhiên.

64k là kích thước khối tối thiểu được phép cho LVM mỏng.

Hãy cẩn thận viết lại ..!Đúng. Loại bộ đệm này trì hoãn việc đồng bộ hóa ghi vào thiết bị được lưu trong bộ nhớ đệm. Điều này có nghĩa là nếu mất bộ đệm, bạn có thể mất dữ liệu trên thiết bị được lưu trong bộ nhớ đệm. Sau này, tác giả sẽ cho bạn biết những biện pháp nào, ngoài NVMe RAID 1, có thể được thực hiện để bù đắp cho rủi ro này.

Loại bộ đệm này được chọn có chủ ý để bù đắp cho hiệu suất ghi ngẫu nhiên kém của RAID 6.

Hãy kiểm tra những gì chúng ta có:

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

Chỉ nên đặt [cachedata_corig] trên/dev/data/cache. Nếu có gì sai thì hãy sử dụng pvmove.

Bạn có thể tắt bộ đệm nếu cần bằng một lệnh:

#lvconvert -y --uncache cache/cachedata

Việc này được thực hiện trực tuyến. LVM sẽ chỉ đồng bộ hóa bộ nhớ đệm vào đĩa, xóa nó và đổi tên cachedata_corig trở lại cachedata.

Thiết lập LVM mỏng

Hãy ước tính đại khái lượng dung lượng chúng tôi cần cho siêu dữ liệu mỏng 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"

Làm tròn lên tới 4 gigabyte: 4294967296B

Nhân với hai và thêm 4194304B cho siêu dữ liệu LVM PV: 8594128896B
Hãy tạo một phân vùng riêng trên NVMe RAID 1 để đặt siêu dữ liệu mỏng LVM và bản sao lưu của chúng vào đó:

#lvcreate -L 8594128896B --name images root

Để làm gì..?Ở đây có thể đặt ra câu hỏi: tại sao lại đặt siêu dữ liệu mỏng LVM riêng biệt nếu nó vẫn được lưu vào bộ nhớ đệm trên NVMe và sẽ hoạt động nhanh chóng.

Mặc dù tốc độ rất quan trọng ở đây nhưng nó lại không phải là lý do chính. Vấn đề là bộ đệm là một điểm bị lỗi. Điều gì đó có thể xảy ra với nó và nếu siêu dữ liệu mỏng LVM được lưu vào bộ đệm, nó sẽ khiến mọi thứ bị mất hoàn toàn. Nếu không có siêu dữ liệu hoàn chỉnh thì gần như không thể tập hợp được các tập sách mỏng.

Bằng cách di chuyển siêu dữ liệu sang một ổ đĩa riêng biệt không được lưu vào bộ nhớ đệm nhưng nhanh chóng, chúng tôi đảm bảo sự an toàn của siêu dữ liệu trong trường hợp mất hoặc hỏng bộ nhớ đệm. Trong trường hợp này, tất cả thiệt hại do mất bộ nhớ đệm sẽ được tập trung vào các ổ đĩa mỏng, điều này sẽ đơn giản hóa quy trình khôi phục theo mức độ lớn. Với khả năng cao, những thiệt hại này sẽ được khôi phục bằng nhật ký FS.

Hơn nữa, nếu ảnh chụp nhanh của ổ đĩa mỏng đã được chụp trước đó và sau đó bộ nhớ đệm đã được đồng bộ hóa hoàn toàn ít nhất một lần, thì do thiết kế bên trong của LVM slim, tính toàn vẹn của ảnh chụp nhanh sẽ được đảm bảo trong trường hợp mất bộ nhớ đệm .

Hãy tạo một VG mới chịu trách nhiệm cung cấp mỏng:

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

Hãy tạo một nhóm:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
Tại sao -Z yNgoài mục đích thực sự của chế độ này - để ngăn dữ liệu từ một máy ảo bị rò rỉ sang máy ảo khác khi phân phối lại không gian - việc tạo số 64 còn được sử dụng để tăng tốc độ ghi ngẫu nhiên trong các khối nhỏ hơn 64k. Bất kỳ thao tác ghi nào nhỏ hơn 64k vào vùng chưa được phân bổ trước đó của ổ đĩa mỏng sẽ được căn chỉnh theo cạnh XNUMXK trong bộ đệm. Điều này sẽ cho phép thao tác được thực hiện hoàn toàn thông qua bộ đệm, bỏ qua thiết bị được lưu trong bộ nhớ đệm.

Hãy di chuyển LV sang các PV tương ứng:

#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

Hãy kiểm tra:

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

Hãy tạo một khối lượng mỏng để kiểm tra:

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

Chúng tôi sẽ cài đặt các gói để kiểm tra và giám sát:

#apt-get install sysstat fio

Đây là cách bạn có thể quan sát hành vi cấu hình lưu trữ của chúng tôi trong thời gian thực:

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

Đây là cách chúng tôi có thể kiểm tra cấu hình của mình:

#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

Cẩn thận! Nguồn!Mã này sẽ chạy 36 bài kiểm tra khác nhau, mỗi bài chạy trong 4 giây. Một nửa số bài kiểm tra là để ghi lại. Bạn có thể ghi rất nhiều thứ trên NVMe trong 4 giây. Lên đến 3 gigabyte mỗi giây. Vì vậy, mỗi lần chạy bài kiểm tra viết có thể ngốn tới 216 gigabyte tài nguyên SSD của bạn.

Đọc và viết trộn lẫn?Đúng. Sẽ rất hợp lý khi chạy các bài kiểm tra đọc và viết riêng biệt. Hơn nữa, điều hợp lý là đảm bảo rằng tất cả các bộ đệm được đồng bộ hóa để việc ghi được thực hiện trước đó không ảnh hưởng đến việc đọc.

Kết quả sẽ khác nhau rất nhiều trong lần khởi chạy đầu tiên và những lần tiếp theo khi bộ đệm và ổ đĩa mỏng đầy lên, đồng thời cũng tùy thuộc vào việc hệ thống có quản lý để đồng bộ hóa bộ đệm được lấp đầy trong lần khởi chạy gần đây nhất hay không.

Trong số những thứ khác, tôi khuyên bạn nên đo tốc độ trên một ổ đĩa mỏng vốn đã đầy mà từ đó ảnh chụp nhanh vừa được chụp. Tác giả đã có cơ hội quan sát cách ghi ngẫu nhiên tăng tốc mạnh mẽ ngay sau khi tạo ảnh chụp nhanh đầu tiên, đặc biệt là khi bộ nhớ đệm chưa đầy hoàn toàn. Điều này xảy ra do ngữ nghĩa ghi sao chép khi ghi, căn chỉnh bộ đệm và khối ổ đĩa mỏng, đồng thời thực tế là việc ghi ngẫu nhiên vào RAID 6 chuyển thành đọc ngẫu nhiên từ RAID 6, sau đó là ghi vào bộ nhớ đệm. Trong cấu hình của chúng tôi, việc đọc ngẫu nhiên từ RAID 6 nhanh hơn tới 6 lần (số lượng ổ SSD SATA trong mảng) so với ghi. Bởi vì các khối dành cho CoW được phân bổ tuần tự từ một nhóm mỏng, sau đó phần lớn quá trình ghi cũng chuyển sang tuần tự.

Cả hai tính năng này đều có thể được sử dụng để có lợi cho bạn.

Ảnh chụp nhanh “mạch lạc” của bộ nhớ đệm

Để giảm nguy cơ mất dữ liệu trong trường hợp hỏng/mất bộ đệm, tác giả đề xuất giới thiệu phương pháp xoay ảnh chụp nhanh để đảm bảo tính toàn vẹn của chúng trong trường hợp này.

Đầu tiên, vì siêu dữ liệu dung lượng nhỏ nằm trên một thiết bị không được lưu vào bộ nhớ đệm nên siêu dữ liệu sẽ nhất quán và các tổn thất có thể xảy ra sẽ được cách ly trong các khối dữ liệu.

Chu kỳ xoay ảnh chụp nhanh sau đây đảm bảo tính toàn vẹn của dữ liệu bên trong ảnh chụp nhanh trong trường hợp mất bộ đệm:

  1. Đối với mỗi ổ đĩa mỏng có tên <name>, hãy tạo một ảnh chụp nhanh có tên <name>.cached
  2. Hãy đặt ngưỡng di chuyển thành giá trị cao hợp lý: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Trong vòng lặp, chúng tôi kiểm tra số lượng khối bẩn trong bộ đệm: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' cho đến khi chúng ta nhận được số không. Nếu số 100 bị thiếu quá lâu, nó có thể được tạo bằng cách tạm thời chuyển bộ đệm sang chế độ ghi. Tuy nhiên, khi tính đến đặc điểm tốc độ của mảng SSD SATA và NVMe của chúng tôi, cũng như tài nguyên TBW của chúng, bạn sẽ có thể nhanh chóng nắm bắt được khoảnh khắc mà không cần thay đổi chế độ bộ nhớ đệm hoặc phần cứng của bạn sẽ ngốn hoàn toàn toàn bộ tài nguyên trong một vài ngày. Do những hạn chế về tài nguyên, về nguyên tắc, hệ thống không thể luôn luôn ghi dưới 100%. SSD NVMe của chúng tôi có tải ghi dưới XNUMX% sẽ cạn kiệt hoàn toàn tài nguyên trong ngày 3-4. SSD SATA sẽ chỉ có tuổi thọ gấp đôi. Do đó, chúng tôi sẽ giả định rằng phần lớn tải dành cho việc đọc và chúng tôi có các đợt hoạt động cực cao tương đối ngắn hạn kết hợp với tải trung bình thấp để viết.
  4. Ngay sau khi chúng tôi bắt được (hoặc tạo) số XNUMX, chúng tôi đổi tên <name>.cached thành <name>.commit. <name>.commit cũ đã bị xóa.
  5. Theo tùy chọn, nếu bộ đệm đã đầy 100%, nó có thể được tạo lại bằng tập lệnh, do đó sẽ xóa nó. Với bộ nhớ đệm trống một nửa, hệ thống sẽ hoạt động nhanh hơn nhiều khi ghi.
  6. Đặt ngưỡng di chuyển thành XNUMX: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Điều này sẽ tạm thời ngăn bộ đệm đồng bộ hóa với phương tiện chính.
  7. Chúng tôi đợi cho đến khi có khá nhiều thay đổi tích lũy trong bộ đệm #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' hoặc đồng hồ hẹn giờ sẽ tắt.
  8. Chúng tôi lặp lại một lần nữa.

Tại sao lại gặp khó khăn với ngưỡng di chuyển...?Vấn đề là trong thực tế, việc ghi "ngẫu nhiên" thực ra không hoàn toàn ngẫu nhiên. Nếu chúng ta viết thứ gì đó vào một khu vực có kích thước 4 kilobyte, thì khả năng cao là trong vài phút tới, một bản ghi sẽ được tạo cho khu vực tương tự hoặc một trong các khu vực lân cận (+- 32K).

Bằng cách đặt ngưỡng di chuyển thành 64, chúng tôi trì hoãn việc đồng bộ hóa ghi trên SSD SATA và tổng hợp một số thay đổi đối với một khối XNUMXK trong bộ đệm. Điều này giúp tiết kiệm đáng kể tài nguyên của SSD SATA.

Mã ở đâu..?Thật không may, tác giả cho rằng mình không đủ năng lực trong việc phát triển các tập lệnh bash vì anh ấy tự học 100% và thực hành phát triển theo hướng “google”, do đó anh ấy tin rằng không nên sử dụng đoạn mã khủng khiếp đó từ tay anh ấy. khác.

Tôi nghĩ rằng các chuyên gia trong lĩnh vực này sẽ có thể mô tả một cách độc lập tất cả logic được mô tả ở trên, nếu cần, và thậm chí có thể thiết kế đẹp mắt nó như một dịch vụ systemd, như tác giả đã cố gắng làm.

Sơ đồ xoay ảnh chụp nhanh đơn giản như vậy sẽ cho phép chúng tôi không chỉ liên tục có một ảnh chụp nhanh được đồng bộ hóa hoàn toàn trên SSD SATA mà còn cho phép chúng tôi, bằng cách sử dụng tiện ích Thin_delta, tìm ra khối nào đã được thay đổi sau khi tạo và do đó xác định được hư hỏng trên các khối lượng chính, đơn giản hóa rất nhiều việc phục hồi.

TRIM/BỎ BỎ trong libvirt/KVM

Bởi vì bộ lưu trữ dữ liệu sẽ được sử dụng cho KVM chạy libvirt, khi đó sẽ là một ý tưởng hay nếu hướng dẫn các máy ảo của chúng ta không chỉ cách chiếm dung lượng trống mà còn giải phóng những thứ không còn cần thiết.

Điều này được thực hiện bằng cách mô phỏng hỗ trợ TRIM/DISCARD trên đĩa ảo. Để thực hiện việc này, bạn cần thay đổi loại bộ điều khiển thành virtio-scsi và chỉnh sửa 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>

Các DISCARD như vậy khỏi hệ điều hành khách được LVM xử lý chính xác và các khối được giải phóng chính xác cả trong bộ đệm và trong nhóm mỏng. Trong trường hợp của chúng tôi, điều này chủ yếu xảy ra một cách chậm trễ khi xóa ảnh chụp nhanh tiếp theo.

Sao lưu BTRFS

Sử dụng các tập lệnh được tạo sẵn với cực thận trọng và tự chịu rủi ro. Tác giả đã tự viết mã này và dành riêng cho chính mình. Tôi chắc chắn rằng nhiều người dùng Linux có kinh nghiệm cũng có các công cụ tương tự và không cần phải sao chép công cụ của người khác.

Hãy tạo một ổ đĩa trên thiết bị sao lưu:

#lvcreate -L 256G --name backup backup

Hãy định dạng nó trong BTRFS:

#mkfs.btrfs /dev/backup/backup

Hãy tạo các điểm gắn kết và gắn kết các phần phụ gốc của hệ thống tệp:

#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

Hãy tạo thư mục để sao lưu:

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

Hãy tạo một thư mục cho các tập lệnh sao lưu:

#mkdir /root/btrfs-backup

Hãy sao chép tập lệnh:

Rất nhiều mã bash đáng sợ. Sử dụng có nguy cơ của riêng bạn. Đừng viết thư giận dữ cho tác giả...#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

Nó thậm chí còn làm gì ..?Chứa một tập hợp các lệnh đơn giản để tạo ảnh chụp nhanh BTRFS và sao chép chúng sang một FS khác bằng cách gửi/nhận BTRFS.

Lần ra mắt đầu tiên có thể tương đối dài, bởi vì... Lúc đầu, tất cả dữ liệu sẽ được sao chép. Các lần ra mắt tiếp theo sẽ rất nhanh, bởi vì... Chỉ những thay đổi sẽ được sao chép.

Một tập lệnh khác mà chúng tôi sẽ đưa vào cron:

Một số mã bash khác#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

Nó làm gì..?Tạo và đồng bộ hóa các ảnh chụp nhanh gia tăng của các ổ BTRFS được liệt kê trên FS dự phòng. Sau đó, nó sẽ xóa tất cả các ảnh được tạo cách đây 60 ngày. Sau khi khởi chạy, ảnh chụp nhanh ngày của các tập được liệt kê sẽ xuất hiện trong thư mục con /backup/btrfs/back/remote/.

Hãy cấp quyền thực thi mã:

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

Hãy kiểm tra nó và đặt nó vào 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

Sao lưu mỏng LVM

Hãy tạo một nhóm mỏng trên thiết bị sao lưu:

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

Hãy cài đặt ddrescue, bởi vì... các tập lệnh sẽ sử dụng công cụ này:

#apt-get install gddrescue

Hãy tạo một thư mục cho các tập lệnh:

#mkdir /root/lvm-thin-backup

Hãy sao chép các tập lệnh:

Bên trong có rất nhiều phiền toái...#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

Nó làm gì...?Chứa một tập hợp các lệnh để thao tác các ảnh chụp nhanh mỏng và đồng bộ hóa sự khác biệt giữa hai ảnh chụp nhanh mỏng nhận được qua Thin_delta với một thiết bị khối khác bằng ddrescue và blkdiscard.

Một tập lệnh khác mà chúng tôi sẽ đưa vào cron:

Thêm một chút bash#cat >/root/lvm-thin-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

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

BACKUP_SCRIPT="$SCRIPT_DIR/lvm-thin-backup.sh"
RETENTION="-60 days"

$BACKUP_SCRIPT backup images linux-dev
$BACKUP_SCRIPT backup images win8
$BACKUP_SCRIPT backup images win8-data
#etc

$BACKUP_SCRIPT removeall images linux-dev "$RETENTION"
$BACKUP_SCRIPT removeall images win8 "$RETENTION"
$BACKUP_SCRIPT removeall images win8-data "$RETENTION"
#etc

EOF

Nó làm gì...?Sử dụng tập lệnh trước để tạo và đồng bộ hóa các bản sao lưu của các ổ đĩa mỏng được liệt kê. Tập lệnh sẽ để lại các ảnh chụp nhanh không hoạt động của các ổ đĩa được liệt kê, những ảnh chụp này cần thiết để theo dõi các thay đổi kể từ lần đồng bộ hóa cuối cùng.

Tập lệnh này phải được chỉnh sửa, chỉ định danh sách các tập đĩa mỏng cần tạo bản sao lưu. Những cái tên được đưa ra chỉ nhằm mục đích minh họa. Nếu muốn, bạn có thể viết một tập lệnh sẽ đồng bộ hóa tất cả các tập.

Hãy trao quyền:

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

Hãy kiểm tra nó và đặt nó vào 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

Lần ra mắt đầu tiên sẽ kéo dài, bởi vì... khối lượng mỏng sẽ được đồng bộ hóa hoàn toàn bằng cách sao chép tất cả dung lượng đã sử dụng. Nhờ siêu dữ liệu mỏng LVM, chúng tôi biết khối nào thực sự đang được sử dụng, do đó, chỉ các khối âm lượng mỏng được sử dụng thực tế mới được sao chép.

Các lần chạy tiếp theo sẽ sao chép dữ liệu tăng dần nhờ theo dõi thay đổi thông qua siêu dữ liệu mỏng LVM.

Hãy xem những gì đã xảy ra:

#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

Điều này có liên quan gì đến việc làm tổ của búp bê?

Rất có thể, do khối lượng logic LVM LV có thể là khối lượng vật lý LVM PV cho các VG khác. LVM có thể đệ quy, giống như những con búp bê lồng nhau. Điều này mang lại cho LVM sự linh hoạt cực độ.

PS

Trong bài viết tiếp theo, chúng tôi sẽ cố gắng sử dụng một số hệ thống lưu trữ di động/KVM tương tự làm cơ sở để tạo cụm lưu trữ/vm phân tán theo địa lý với khả năng dự phòng trên một số châu lục bằng cách sử dụng máy tính để bàn gia đình, Internet gia đình và mạng P2P.

Nguồn: www.habr.com

Thêm một lời nhận xét