Τι κοινό έχουν το LVM και το Matryoshka;

Καλημέρα.
Θα ήθελα να μοιραστώ με την κοινότητα την πρακτική μου εμπειρία από την κατασκευή ενός συστήματος αποθήκευσης δεδομένων για KVM χρησιμοποιώντας md RAID + LVM.

Το πρόγραμμα θα περιλαμβάνει:

  • Κατασκευή md RAID 1 από NVMe SSD.
  • Συναρμολόγηση md RAID 6 από SATA SSD και κανονικούς δίσκους.
  • Χαρακτηριστικά λειτουργίας TRIM/DISCARD σε SSD RAID 1/6.
  • Δημιουργία πίνακα εκκίνησης md RAID 1/6 σε ένα κοινό σύνολο δίσκων.
  • Εγκατάσταση του συστήματος στο NVMe RAID 1 όταν δεν υπάρχει υποστήριξη NVMe στο BIOS.
  • Χρησιμοποιώντας LVM cache και LVM thin.
  • Χρήση στιγμιότυπων BTRFS και αποστολή/λήψη για δημιουργία αντιγράφων ασφαλείας.
  • Χρησιμοποιώντας LVM thin snapshots και thin_delta για αντίγραφα ασφαλείας σε στυλ BTRFS.

Αν ενδιαφέρεστε, δείτε το cat.

Δήλωση

Ο συγγραφέας δεν φέρει καμία ευθύνη για τις συνέπειες της χρήσης ή μη χρήσης υλικών/παραδειγμάτων/κώδικα/συμβουλών/δεδομένων από αυτό το άρθρο. Διαβάζοντας ή χρησιμοποιώντας αυτό το υλικό με οποιονδήποτε τρόπο, αναλαμβάνετε την ευθύνη για όλες τις συνέπειες αυτών των ενεργειών. Οι πιθανές συνέπειες περιλαμβάνουν:

  • Τηγανισμένοι NVMe SSD.
  • Εξαντλημένος πόρος εγγραφής και αποτυχία μονάδων SSD.
  • Πλήρης απώλεια όλων των δεδομένων σε όλες τις μονάδες δίσκου, συμπεριλαμβανομένων των αντιγράφων ασφαλείας.
  • Ελαττωματικό υλικό υπολογιστή.
  • Χαμένος χρόνος, νεύρα και χρήματα.
  • Οποιεσδήποτε άλλες συνέπειες που δεν αναφέρονται παραπάνω.

Σίδερο

Διαθέσιμα ήταν:

Μητρική πλακέτα από το 2013 περίπου με chipset Z87, πλήρης με Intel Core i7 / Haswell.

  • Επεξεργαστής 4 πυρήνων, 8 νημάτων
  • 32 GB DDR3 RAM
  • 1 x 16 ή 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • Υποδοχές SATA 6 6 x 3 GBps

Ο προσαρμογέας SAS LSI SAS9211-8I αναβοσβήνει σε λειτουργία IT / HBA. Το υλικολογισμικό με δυνατότητα RAID έχει αντικατασταθεί σκόπιμα με υλικολογισμικό HBA για:

  1. Μπορείτε να πετάξετε αυτόν τον προσαρμογέα ανά πάσα στιγμή και να τον αντικαταστήσετε με οποιονδήποτε άλλο συναντήσετε.
  2. Το TRIM/Discard λειτούργησε κανονικά σε δίσκους, επειδή... στο υλικολογισμικό RAID αυτές οι εντολές δεν υποστηρίζονται καθόλου, και το HBA, γενικά, δεν ενδιαφέρεται ποιες εντολές μεταδίδονται μέσω του διαύλου.

Σκληροί δίσκοι - 8 τεμάχια HGST Travelstar 7K1000 χωρητικότητας 1 TB σε παράγοντα μορφής 2.5, όπως για φορητούς υπολογιστές. Αυτές οι μονάδες δίσκου ήταν προηγουμένως σε συστοιχία RAID 6. Θα έχουν επίσης χρήση στο νέο σύστημα. Για αποθήκευση τοπικών αντιγράφων ασφαλείας.

Προστέθηκε επιπλέον:

6 τεμαχίων SATA SSD μοντέλο Samsung 860 QVO 2TB. Αυτοί οι SSD απαιτούσαν μεγάλο όγκο, ήταν επιθυμητή η παρουσία κρυφής μνήμης SLC, αξιοπιστία και χαμηλή τιμή. Απαιτήθηκε υποστήριξη για απόρριψη/μηδέν, η οποία ελέγχεται από τη γραμμή στο dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 κομμάτια NVMe SSD μοντέλο Samsung SSD 970 EVO 500GB.

Για αυτούς τους SSD, η τυχαία ταχύτητα ανάγνωσης/εγγραφής και η χωρητικότητα πόρων για τις ανάγκες σας είναι σημαντικά. Καλοριφέρ για αυτούς. Αναγκαίως. Απολύτως. Διαφορετικά, τηγανίστε τα μέχρι να γίνουν τραγανά κατά τον πρώτο συγχρονισμό RAID.

Προσαρμογέας StarTech PEX8M2E2 για 2 x NVMe SSD εγκατεστημένος στην υποδοχή PCIe 3.0 8x. Αυτό, πάλι, είναι απλώς ένα HBA, αλλά για το NVMe. Διαφέρει από τους φθηνούς προσαρμογείς στο ότι δεν απαιτεί υποστήριξη διχοτόμησης PCIe από τη μητρική πλακέτα λόγω της παρουσίας ενσωματωμένου διακόπτη PCIe. Θα λειτουργήσει ακόμη και στο πιο αρχαίο σύστημα με PCIe, ακόμα κι αν πρόκειται για υποδοχή x1 PCIe 1.0. Φυσικά, με την κατάλληλη ταχύτητα. Δεν υπάρχουν RAID εκεί. Δεν υπάρχει ενσωματωμένο BIOS επί του σκάφους. Έτσι, το σύστημά σας δεν θα μάθει ως δια μαγείας να εκκινεί με το NVMe, πολύ λιγότερο το NVMe RAID χάρη σε αυτήν τη συσκευή.

Αυτό το στοιχείο οφειλόταν αποκλειστικά στην παρουσία μόνο ενός δωρεάν 8x PCIe 3.0 στο σύστημα και, εάν υπάρχουν 2 δωρεάν υποδοχές, μπορεί εύκολα να αντικατασταθεί με δύο πένες PEX4M2E1 ή ανάλογα, τα οποία μπορούν να αγοραστούν οπουδήποτε στην τιμή των 600 ρούβλια.

Η απόρριψη κάθε είδους hardware ή ενσωματωμένο chipset/BIOS RAID έγινε σκόπιμα, για να μπορέσει να αντικατασταθεί πλήρως ολόκληρο το σύστημα, με εξαίρεση τους ίδιους τους SSD/HDD, διατηρώντας παράλληλα όλα τα δεδομένα. Ιδανικά, ώστε να μπορείτε να αποθηκεύσετε ακόμη και το εγκατεστημένο λειτουργικό σύστημα όταν μετακινείστε σε εντελώς νέο/διαφορετικό υλικό. Το κύριο πράγμα είναι ότι υπάρχουν θύρες SATA και PCIe. Είναι σαν ένα ζωντανό CD ή μια μονάδα flash με δυνατότητα εκκίνησης, μόνο πολύ γρήγορο και λίγο ογκώδες.

ЮморΔιαφορετικά, ξέρετε τι συμβαίνει - μερικές φορές χρειάζεται επειγόντως να πάρετε ολόκληρη τη συστοιχία μαζί σας για να την αφαιρέσετε. Αλλά δεν θέλω να χάσω δεδομένα. Για να γίνει αυτό, όλα τα αναφερόμενα μέσα βρίσκονται σε βολική τοποθεσία στις διαφάνειες στις 5.25 θέσεις της τυπικής θήκης.

Λοιπόν, και, φυσικά, για πειραματισμό με διαφορετικές μεθόδους αποθήκευσης SSD στο Linux.

Οι επιδρομές υλικού είναι βαρετές. Ενεργοποιήστε την. Είτε λειτουργεί είτε όχι. Και με το mdadm υπάρχουν πάντα επιλογές.

Λογισμικό

Προηγουμένως, το Debian 8 Jessie είχε εγκατασταθεί στο υλικό, το οποίο είναι κοντά στο EOL. Το RAID 6 συναρμολογήθηκε από τους παραπάνω αναφερόμενους σκληρούς δίσκους σε συνδυασμό με LVM. Έτρεχε εικονικές μηχανές σε kvm/libvirt.

Επειδή Ο συγγραφέας έχει την κατάλληλη εμπειρία στη δημιουργία φορητών εκκινήσιμων μονάδων flash SATA/NVMe και επίσης, για να μην σπάσει το συνηθισμένο πρότυπο, το Ubuntu 18.04 επιλέχθηκε ως σύστημα στόχος, το οποίο έχει ήδη σταθεροποιηθεί επαρκώς, αλλά έχει ακόμη 3 χρόνια υποστήριξη στο μέλλον.

Το αναφερόμενο σύστημα περιέχει όλα τα προγράμματα οδήγησης υλικού που χρειαζόμαστε εκτός συσκευασίας. Δεν χρειαζόμαστε λογισμικό ή προγράμματα οδήγησης τρίτων.

Προετοιμασία για εγκατάσταση

Για να εγκαταστήσουμε το σύστημα χρειαζόμαστε Ubuntu Desktop Image. Το σύστημα διακομιστή έχει κάποιο είδος δυναμικού προγράμματος εγκατάστασης, το οποίο δείχνει υπερβολική ανεξαρτησία που δεν μπορεί να απενεργοποιηθεί τοποθετώντας το διαμέρισμα του συστήματος UEFI σε έναν από τους δίσκους, καταστρέφοντας όλη την ομορφιά. Κατά συνέπεια, εγκαθίσταται μόνο σε λειτουργία UEFI. Δεν προσφέρει καμία επιλογή.

Δεν είμαστε ευχαριστημένοι με αυτό.

Γιατί;Δυστυχώς, η εκκίνηση του UEFI είναι εξαιρετικά ελάχιστα συμβατή με το λογισμικό εκκίνησης RAID, επειδή... Κανείς δεν μας προσφέρει κρατήσεις για το διαμέρισμα UEFI ESP. Υπάρχουν συνταγές στο διαδίκτυο που προτείνουν την τοποθέτηση του διαμερίσματος ESP σε μια μονάδα flash σε μια θύρα USB, αλλά αυτό είναι ένα σημείο αποτυχίας. Υπάρχουν συνταγές που χρησιμοποιούν λογισμικό mdadm RAID 1 με μεταδεδομένα έκδοση 0.9 που δεν εμποδίζουν το UEFI BIOS να δει αυτό το διαμέρισμα, αλλά αυτό ζει μέχρι την ευτυχισμένη στιγμή που το BIOS ή άλλο λειτουργικό σύστημα υλικού γράφει κάτι στο ESP και ξεχνάει να το συγχρονίσει με άλλο καθρέφτες.

Επιπλέον, η εκκίνηση του UEFI εξαρτάται από το NVRAM, το οποίο δεν θα μετακινηθεί μαζί με τους δίσκους στο νέο σύστημα, επειδή είναι μέρος της μητρικής πλακέτας.

Έτσι, δεν θα εφεύρουμε ξανά έναν νέο τροχό. Έχουμε ήδη ένα έτοιμο, δοκιμασμένο στο χρόνο ποδήλατο του παππού, που τώρα ονομάζεται μπότα Legacy/BIOS, που φέρει το περήφανο όνομα CSM σε συστήματα συμβατά με UEFI. Απλώς θα το βγάλουμε από το ράφι, θα το λιπάνουμε, θα αντλήσουμε τα ελαστικά και θα το σκουπίσουμε με ένα υγρό πανί.

Η επιτραπέζια έκδοση του Ubuntu επίσης δεν μπορεί να εγκατασταθεί σωστά με τον bootloader Legacy, αλλά εδώ, όπως λένε, τουλάχιστον υπάρχουν επιλογές.

Έτσι, συλλέγουμε το υλικό και φορτώνουμε το σύστημα από τη μονάδα flash εκκίνησης του Ubuntu Live. Θα χρειαστεί να κατεβάσουμε πακέτα, επομένως θα ρυθμίσουμε το δίκτυο που λειτουργεί για εσάς. Εάν δεν λειτουργεί, μπορείτε να φορτώσετε τα απαραίτητα πακέτα σε μια μονάδα flash εκ των προτέρων.

Μπαίνουμε στο περιβάλλον του Desktop, εκκινούμε τον εξομοιωτή τερματικού και ξεκινάμε:

#sudo bash

Πως…?Η παραπάνω γραμμή είναι το κανονικό έναυσμα για holiwars σχετικά με το sudo. Γ βоέρχονται μεγαλύτερες ευκαιρίες καιоμεγαλύτερη ευθύνη. Το ερώτημα είναι αν μπορείτε να το πάρετε μόνοι σας. Πολλοί άνθρωποι πιστεύουν ότι η χρήση του sudo με αυτόν τον τρόπο δεν είναι τουλάχιστον προσεκτική. Ωστόσο:

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

Γιατί όχι ZFS...;Όταν εγκαθιστούμε λογισμικό στον υπολογιστή μας, ουσιαστικά δανείζουμε το υλικό μας στους προγραμματιστές αυτού του λογισμικού για να οδηγήσουν.
Όταν εμπιστευόμαστε αυτό το λογισμικό για την ασφάλεια των δεδομένων μας, παίρνουμε ένα δάνειο ίσο με το κόστος της επαναφοράς αυτών των δεδομένων, το οποίο θα πρέπει να αποπληρώσουμε κάποια μέρα.

Από αυτή την άποψη, το ZFS είναι Ferrari και το mdadm+lvm μοιάζει περισσότερο με ποδήλατο.

Υποκειμενικά, ο συγγραφέας προτιμά να δανείσει ένα ποδήλατο με πίστωση σε άγνωστα άτομα αντί για μια Ferrari. Εκεί η τιμή του τεύχους δεν είναι υψηλή. Δεν χρειάζονται δικαιώματα. Πιο απλό από τους κανόνες κυκλοφορίας. Ο χώρος στάθμευσης είναι δωρεάν. Η ικανότητα μεταξύ χωρών είναι καλύτερη. Μπορείτε πάντα να στερεώσετε τα πόδια σε ένα ποδήλατο και μπορείτε να επισκευάσετε ένα ποδήλατο με τα χέρια σας.

Γιατί τότε BTRFS...;Για να εκκινήσουμε το λειτουργικό σύστημα, χρειαζόμαστε ένα σύστημα αρχείων που να υποστηρίζεται στο Legacy/BIOS GRUB out of the box, και ταυτόχρονα να υποστηρίζει ζωντανά στιγμιότυπα. Θα το χρησιμοποιήσουμε για το διαμέρισμα /boot. Επιπλέον, ο συγγραφέας προτιμά να χρησιμοποιεί αυτό το FS για / (root), χωρίς να ξεχνάει να σημειώσει ότι για οποιοδήποτε άλλο λογισμικό μπορείτε να δημιουργήσετε ξεχωριστά διαμερίσματα στο LVM και να τα προσαρτήσετε στους απαραίτητους καταλόγους.

Δεν θα αποθηκεύσουμε εικόνες εικονικών μηχανών ή βάσεων δεδομένων σε αυτό το FS.
Αυτό το FS θα χρησιμοποιηθεί μόνο για τη δημιουργία στιγμιότυπων του συστήματος χωρίς να το απενεργοποιήσετε και στη συνέχεια θα μεταφέρετε αυτά τα στιγμιότυπα σε έναν αντίγραφο ασφαλείας χρησιμοποιώντας την αποστολή/λήψη.

Επιπλέον, ο συγγραφέας προτιμά γενικά να διατηρεί ένα ελάχιστο λογισμικό απευθείας στο υλικό και να εκτελεί όλο το άλλο λογισμικό σε εικονικές μηχανές χρησιμοποιώντας πράγματα όπως η προώθηση GPU και ελεγκτές κεντρικού υπολογιστή PCI-USB στο KVM μέσω IOMMU.

Τα μόνα πράγματα που απομένουν στο υλικό είναι η αποθήκευση δεδομένων, η εικονικοποίηση και η δημιουργία αντιγράφων ασφαλείας.

Εάν εμπιστεύεστε περισσότερο τη ZFS, τότε, καταρχήν, για την καθορισμένη εφαρμογή είναι εναλλάξιμα.

Ωστόσο, ο συγγραφέας αγνοεί εσκεμμένα τις ενσωματωμένες δυνατότητες κατοπτρισμού/RAID και πλεονασμού που διαθέτουν τα ZFS, BRTFS και LVM.

Ως πρόσθετο επιχείρημα, το BTRFS έχει τη δυνατότητα να μετατρέπει τις τυχαίες εγγραφές σε διαδοχικές, κάτι που έχει εξαιρετικά θετική επίδραση στην ταχύτητα συγχρονισμού στιγμιότυπων/αντιγράφων ασφαλείας στον σκληρό δίσκο.

Ας σαρώσουμε ξανά όλες τις συσκευές:

#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

Διάταξη δίσκου

NVMe SSD

Αλλά δεν θα τα επισημάνουμε με κανέναν τρόπο. Παρόλα αυτά, το BIOS μας δεν βλέπει αυτούς τους δίσκους. Έτσι, θα πάνε εξ ολοκλήρου στο λογισμικό RAID. Δεν θα δημιουργήσουμε καν ενότητες εκεί. Εάν θέλετε να ακολουθήσετε το "canon" ή "κυρίως", δημιουργήστε ένα μεγάλο διαμέρισμα, όπως ένας σκληρός δίσκος.

SATA HDD

Δεν χρειάζεται να εφεύρουμε κάτι ιδιαίτερο εδώ. Θα δημιουργήσουμε ένα τμήμα για τα πάντα. Θα δημιουργήσουμε ένα διαμέρισμα επειδή το BIOS βλέπει αυτούς τους δίσκους και μπορεί ακόμη και να προσπαθήσει να κάνει εκκίνηση από αυτούς. Θα εγκαταστήσουμε ακόμη και το GRUB σε αυτούς τους δίσκους αργότερα, έτσι ώστε το σύστημα να μπορεί να το κάνει ξαφνικά.

#cat >hdd.part << EOF
label: dos
label-id: 0x00000000
device: /dev/sdg
unit: sectors

/dev/sdg1 : start= 2048, size= 1953523120, type=fd, bootable
EOF
#sfdisk /dev/sdg < hdd.part
#sfdisk /dev/sdh < hdd.part
#sfdisk /dev/sdi < hdd.part
#sfdisk /dev/sdj < hdd.part
#sfdisk /dev/sdk < hdd.part
#sfdisk /dev/sdl < hdd.part
#sfdisk /dev/sdm < hdd.part
#sfdisk /dev/sdn < hdd.part

SATA SSD

Εδώ είναι που τα πράγματα γίνονται ενδιαφέροντα για εμάς.

Πρώτον, οι μονάδες μας έχουν μέγεθος 2 TB. Αυτό είναι εντός του αποδεκτού εύρους για το MBR, το οποίο θα χρησιμοποιήσουμε. Εάν είναι απαραίτητο, μπορεί να αντικατασταθεί με GPT. Οι δίσκοι GPT έχουν ένα επίπεδο συμβατότητας που επιτρέπει στα συστήματα συμβατά με MBR να βλέπουν τα πρώτα 4 διαμερίσματα εάν βρίσκονται στα πρώτα 2 terabyte. Το κύριο πράγμα είναι ότι το διαμέρισμα εκκίνησης και το διαμέρισμα bios_grub σε αυτούς τους δίσκους πρέπει να βρίσκονται στην αρχή. Αυτό σας επιτρέπει ακόμη και να κάνετε εκκίνηση από μονάδες GPT Legacy/BIOS.

Αλλά αυτό δεν είναι η περίπτωσή μας.

Εδώ θα δημιουργήσουμε δύο ενότητες. Το πρώτο θα έχει μέγεθος 1 GB και θα χρησιμοποιηθεί για RAID 1 /boot.

Το δεύτερο θα χρησιμοποιηθεί για το RAID 6 και θα καταλαμβάνει όλο τον υπόλοιπο ελεύθερο χώρο εκτός από μια μικρή μη εκχωρημένη περιοχή στο τέλος της μονάδας.

Τι είναι αυτή η ασήμαντη περιοχή;Σύμφωνα με πηγές στο δίκτυο, οι SATA SSD μας διαθέτουν μια δυναμικά επεκτάσιμη κρυφή μνήμη SLC που κυμαίνεται σε μέγεθος από 6 έως 78 gigabyte. Λαμβάνουμε 6 gigabyte "δωρεάν" λόγω της διαφοράς μεταξύ "gigabytes" και "gibibytes" στο φύλλο δεδομένων της μονάδας δίσκου. Τα υπόλοιπα 72 gigabyte διατίθενται από αχρησιμοποίητο χώρο.

Εδώ πρέπει να σημειωθεί ότι έχουμε μια κρυφή μνήμη SLC, και ο χώρος καταλαμβάνεται σε λειτουργία MLC 4 bit. Πράγμα που για εμάς ουσιαστικά σημαίνει ότι για κάθε 4 gigabyte ελεύθερου χώρου θα λαμβάνουμε μόνο 1 gigabyte SLC cache.

Πολλαπλασιάστε 72 gigabyte με 4 και λάβετε 288 gigabyte. Αυτός είναι ο ελεύθερος χώρος που δεν θα επισημάνουμε για να επιτρέψουμε στους δίσκους να κάνουν πλήρη χρήση της κρυφής μνήμης SLC.

Έτσι, θα λάβουμε ουσιαστικά έως και 312 gigabyte μνήμης cache SLC από συνολικά έξι μονάδες δίσκου. Από όλους τους δίσκους, 2 θα χρησιμοποιηθούν στο RAID για πλεονασμό.

Αυτή η ποσότητα της κρυφής μνήμης θα μας επιτρέψει εξαιρετικά σπάνια στην πραγματική ζωή να αντιμετωπίσουμε μια κατάσταση όπου μια εγγραφή δεν πηγαίνει στην κρυφή μνήμη. Αυτό αντισταθμίζει εξαιρετικά καλά το πιο θλιβερό μειονέκτημα της μνήμης QLC - την εξαιρετικά χαμηλή ταχύτητα εγγραφής όταν τα δεδομένα εγγράφονται παρακάμπτοντας τη μνήμη cache. Εάν τα φορτία σας δεν αντιστοιχούν σε αυτό, τότε σας συνιστώ να σκεφτείτε σκληρά για το πόσο θα διαρκέσει ο 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

Δημιουργία Πίνακες

Πρώτα, πρέπει να μετονομάσουμε το μηχάνημα. Αυτό είναι απαραίτητο επειδή το όνομα του κεντρικού υπολογιστή είναι μέρος του ονόματος πίνακα κάπου μέσα στο mdadm και επηρεάζει κάτι κάπου. Φυσικά, οι πίνακες μπορούν να μετονομαστούν αργότερα, αλλά αυτό είναι ένα περιττό βήμα.

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

NVMe SSD

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

Γιατί -υποθέτω-καθαρό...;Για να αποφύγετε την προετοιμασία πινάκων. Και για τα δύο επίπεδα 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.

Προσοχή, η ακόλουθη εντολή θα καταστρέψει όλα τα δεδομένα στις μονάδες NVMe «αρχικοποιώντας» τον πίνακα με «μηδενικά».

#blkdiscard /dev/md0

Εάν κάτι πάει στραβά, δοκιμάστε να καθορίσετε ένα βήμα.

#blkdiscard --step 65536 /dev/md0

SATA SSD

#mdadm --create --verbose --assume-clean /dev/md1 --level=1 --raid-devices=6 /dev/sd[a-f]1
#blkdiscard /dev/md1
#mdadm --create --verbose --assume-clean /dev/md2 --chunk-size=512 --level=6 --raid-devices=6 /dev/sd[a-f]2

Γιατί τόσο μεγάλο...;Η αύξηση του μεγέθους του τεμαχίου έχει θετική επίδραση στην ταχύτητα της τυχαίας ανάγνωσης σε μπλοκ έως και μεγέθους τεμαχίου. Αυτό συμβαίνει επειδή μία λειτουργία του κατάλληλου μεγέθους ή μικρότερου μπορεί να ολοκληρωθεί εξ ολοκλήρου σε μία μόνο συσκευή. Επομένως, συνοψίζεται το IOPS από όλες τις συσκευές. Σύμφωνα με στατιστικά στοιχεία, το 99% του IO δεν υπερβαίνει τα 512K.

RAID 6 IOPS ανά εγγραφή πάντα μικρότερο ή ίσο με το IOPS μιας μονάδας δίσκου. Όταν, ως τυχαία ανάγνωση, το IOPS μπορεί να είναι αρκετές φορές μεγαλύτερο από αυτό μιας μονάδας δίσκου, και εδώ το μέγεθος του μπλοκ είναι καθοριστικής σημασίας.
Ο συγγραφέας δεν βλέπει το νόημα να προσπαθεί να βελτιστοποιήσει μια παράμετρο που είναι κακή στο RAID 6 by-design και αντ' αυτού βελτιστοποιεί σε τι είναι καλό το RAID 6.
Θα αντισταθμίσουμε την κακή τυχαία εγγραφή του RAID 6 με μια προσωρινή μνήμη NVMe και κόλπα λεπτής παροχής.

Δεν έχουμε ακόμη ενεργοποιήσει το DISCARD για το RAID 6. Επομένως, δεν θα "αρχικοποιήσουμε" αυτόν τον πίνακα προς το παρόν. Θα το κάνουμε αργότερα, αφού εγκαταστήσουμε το λειτουργικό σύστημα.

SATA HDD

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

LVM σε NVMe RAID

Για ταχύτητα, θέλουμε να τοποθετήσουμε το ριζικό σύστημα αρχείων στο NVMe RAID 1 που είναι /dev/md0.
Ωστόσο, θα συνεχίσουμε να χρειαζόμαστε αυτόν τον γρήγορο πίνακα για άλλες ανάγκες, όπως εναλλαγή, μεταδεδομένα και προσωρινή μνήμη LVM και μεταδεδομένα με λεπτότητα LVM, επομένως θα δημιουργήσουμε ένα LVM VG σε αυτόν τον πίνακα.

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

Ας δημιουργήσουμε ένα διαμέρισμα για το ριζικό σύστημα αρχείων.

#lvcreate -L 128G --name root root

Ας δημιουργήσουμε ένα διαμέρισμα για εναλλαγή ανάλογα με το μέγεθος της μνήμης RAM.

#lvcreate -L 32G --name swap root

εγκατάσταση ΛΣ

Συνολικά, έχουμε όλα τα απαραίτητα για την εγκατάσταση του συστήματος.

Εκκινήστε τον οδηγό εγκατάστασης συστήματος από το περιβάλλον Ubuntu Live. Κανονική εγκατάσταση. Μόνο στο στάδιο της επιλογής δίσκων για εγκατάσταση, πρέπει να καθορίσετε τα εξής:

  • /dev/md1, - σημείο προσάρτησης /boot, FS - BTRFS
  • /dev/root/root (γνωστός και ως /dev/mapper/root-root), - σημείο προσάρτησης / (root), FS - BTRFS
  • /dev/root/swap (γνωστός και ως /dev/mapper/root-swap), - χρήση ως διαμέρισμα ανταλλαγής
  • Εγκαταστήστε το bootloader στο /dev/sda

Όταν επιλέγετε το BTRFS ως ριζικό σύστημα αρχείων, το πρόγραμμα εγκατάστασης θα δημιουργήσει αυτόματα δύο τόμους BTRFS με το όνομα "@" για το / (root) και "@home" για το /home.

Ας ξεκινήσουμε την εγκατάσταση...

Η εγκατάσταση θα τελειώσει με ένα παράθυρο διαλόγου modal που υποδεικνύει ένα σφάλμα κατά την εγκατάσταση του bootloader. Δυστυχώς, δεν θα μπορείτε να βγείτε από αυτό το παράθυρο διαλόγου χρησιμοποιώντας τυπικά μέσα και να συνεχίσετε την εγκατάσταση. Αποσυνδεόμαστε από το σύστημα και συνδεόμαστε ξανά, καταλήγοντας σε μια καθαρή επιφάνεια εργασίας Ubuntu Live. Ανοίξτε το τερματικό και ξανά:

#sudo bash

Δημιουργήστε ένα περιβάλλον chroot για να συνεχίσετε την εγκατάσταση:

#mkdir /mnt/chroot
#mount -o defaults,space_cache,noatime,nodiratime,discard,subvol=@ /dev/mapper/root-root /mnt/chroot
#mount -o defaults,space_cache,noatime,nodiratime,discard,subvol=@home /dev/mapper/root-root /mnt/chroot/home
#mount -o defaults,space_cache,noatime,nodiratime,discard /dev/md1 /mnt/chroot/boot
#mount --bind /proc /mnt/chroot/proc
#mount --bind /sys /mnt/chroot/sys
#mount --bind /dev /mnt/chroot/dev

Ας διαμορφώσουμε το δίκτυο και το όνομα κεντρικού υπολογιστή στο chroot:

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

Ας πάμε στο περιβάλλον chroot:

#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

Εάν κάτι δεν λειτουργεί, ίσως χρειαστεί να επεξεργαστείτε πρώτα το /etc/apt/sources.list

Ας προσαρμόσουμε τις παραμέτρους για τη μονάδα RAID 6 για να ενεργοποιήσουμε το TRIM/DISCARD:

#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=="md*", RUN+="/sbin/blockdev --setra 0 /dev/%k"
EOF

Τι ήταν αυτό..?Έχουμε δημιουργήσει ένα σύνολο κανόνων udev που θα κάνει τα εξής:

  • Ρυθμίστε το μέγεθος της προσωρινής μνήμης μπλοκ για το RAID 2020 ώστε να είναι επαρκές για το 6. Η προεπιλεγμένη τιμή, φαίνεται, δεν έχει αλλάξει από τη δημιουργία του Linux και δεν είναι επαρκής για μεγάλο χρονικό διάστημα.
  • Κρατήστε ένα ελάχιστο IO για τη διάρκεια των ελέγχων/συγχρονισμών συστοιχιών. Αυτό γίνεται για να αποτρέψετε τις συστοιχίες σας από το να κολλήσουν σε κατάσταση αιώνιου συγχρονισμού υπό φορτίο.
  • Περιορίστε τη μέγιστη IO κατά τους ελέγχους/συγχρονισμό πινάκων. Αυτό είναι απαραίτητο ώστε ο συγχρονισμός/έλεγχος των SSD RAID να μην τραγανίζει τις μονάδες δίσκου σας. Αυτό ισχύει ιδιαίτερα για το NVMe. (Θυμάστε για το καλοριφέρ; Δεν έκανα πλάκα.)
  • Απαγορέψτε στους δίσκους τη διακοπή της περιστροφής του άξονα (HDD) μέσω APM και ορίστε το χρονικό όριο αδράνειας για τους ελεγκτές δίσκου σε 7 ώρες. Μπορείτε να απενεργοποιήσετε πλήρως το APM εάν το κάνουν οι μονάδες δίσκου σας (-B 255). Με την προεπιλεγμένη τιμή, οι μονάδες δίσκου θα σταματήσουν μετά από πέντε δευτερόλεπτα. Στη συνέχεια, το λειτουργικό σύστημα θέλει να επαναφέρει τη μνήμη cache του δίσκου, οι δίσκοι θα περιστραφούν ξανά και όλα θα ξεκινήσουν από την αρχή. Οι δίσκοι έχουν περιορισμένο μέγιστο αριθμό περιστροφών ατράκτου. Ένας τόσο απλός προεπιλεγμένος κύκλος μπορεί εύκολα να σκοτώσει τους δίσκους σας σε μερικά χρόνια. Δεν πάσχουν όλοι οι δίσκοι από αυτό, αλλά οι δικοί μας είναι "laptop", με τις κατάλληλες προεπιλεγμένες ρυθμίσεις, που κάνουν το RAID να μοιάζει με mini-MAID.
  • Εγκατάσταση ανάγνωσης σε δίσκους (περιστρεφόμενοι) 1 megabyte - δύο συνεχόμενα μπλοκ/τεμάχιο RAID 6
  • Απενεργοποιήστε την ανάγνωση μπροστά στους ίδιους τους πίνακες.

Ας επεξεργαστούμε το /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

Γιατί αυτό..?Θα αναζητήσουμε το διαμέρισμα /boot από το UUID. Η ονομασία του πίνακα θα μπορούσε θεωρητικά να αλλάξει.

Θα αναζητήσουμε τις υπόλοιπες ενότητες με ονόματα LVM στη σημείωση /dev/mapper/vg-lv, επειδή αναγνωρίζουν τις κατατμήσεις αρκετά μοναδικά.

Δεν χρησιμοποιούμε UUID για LVM γιατί Το UUID των τόμων LVM και τα στιγμιότυπά τους μπορεί να είναι το ίδιο.Προσάρτηση /dev/mapper/root-root.. δύο φορές;Ναί. Ακριβώς. Χαρακτηριστικό του BTRFS. Αυτό το σύστημα αρχείων μπορεί να προσαρτηθεί πολλές φορές με διαφορετικούς υποτόχους.

Λόγω αυτής της ίδιας λειτουργίας, συνιστώ να μην δημιουργείτε ποτέ στιγμιότυπα LVM ενεργών τόμων BTRFS. Μπορεί να έχετε μια έκπληξη όταν κάνετε επανεκκίνηση.

Ας αναδημιουργήσουμε τη διαμόρφωση mdadm:

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

Ας προσαρμόσουμε τις ρυθμίσεις 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

Τι ήταν αυτό..?Έχουμε ενεργοποιήσει την αυτόματη επέκταση των λεπτών πισινών LVM με την επίτευξη του 90% του καταλαμβανόμενου χώρου κατά 5% του όγκου.

Αυξήσαμε τον μέγιστο αριθμό μπλοκ κρυφής μνήμης για την προσωρινή μνήμη LVM.

Αποτρέψαμε την αναζήτηση τόμων LVM (PV) της LVM σε:

  • συσκευές που περιέχουν προσωρινή μνήμη LVM (cdata)
  • συσκευές που αποθηκεύτηκαν στην κρυφή μνήμη χρησιμοποιώντας την προσωρινή μνήμη LVM, παρακάμπτοντας την κρυφή μνήμη ( _corig). Σε αυτήν την περίπτωση, η ίδια η αποθηκευμένη συσκευή θα εξακολουθήσει να σαρώνεται μέσω της προσωρινής μνήμης (απλώς ).
  • συσκευές που περιέχουν μεταδεδομένα κρυφής μνήμης LVM (cmeta)
  • όλες οι συσκευές σε VG με τις εικόνες ονόματος. Εδώ θα έχουμε εικόνες δίσκου εικονικών μηχανών και δεν θέλουμε το LVM στον κεντρικό υπολογιστή να ενεργοποιεί τόμους που ανήκουν στο λειτουργικό σύστημα επισκέπτη.
  • όλες οι συσκευές σε VG με το όνομα αντιγράφου ασφαλείας. Εδώ θα έχουμε αντίγραφα ασφαλείας των εικόνων εικονικής μηχανής.
  • όλες οι συσκευές των οποίων το όνομα τελειώνει σε "gpv" (φυσικός τόμος επισκέπτη)

Έχουμε ενεργοποιήσει την υποστήριξη DISCARD κατά την απελευθέρωση ελεύθερου χώρου στο LVM VG. Πρόσεχε. Αυτό θα κάνει τη διαγραφή LV στο SSD αρκετά χρονοβόρα. Αυτό ισχύει ιδιαίτερα για το SSD RAID 6. Ωστόσο, σύμφωνα με το σχέδιο, θα χρησιμοποιήσουμε thin provisioning, οπότε αυτό δεν θα μας εμποδίσει καθόλου.

Ας ενημερώσουμε την εικόνα του initramfs:

#update-initramfs -u -k all

Εγκαταστήστε και ρυθμίστε το grub:

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

Ποιους δίσκους να επιλέξω;Όλοι όσοι είναι sd*. Το σύστημα πρέπει να μπορεί να εκκινεί από οποιαδήποτε μονάδα SATA ή SSD που λειτουργεί.

Γιατί πρόσθεσαν το os-prober..;Για υπερβολική ανεξαρτησία και παιχνιδιάρικα χέρια.

Δεν λειτουργεί σωστά εάν ένα από τα RAID είναι σε υποβαθμισμένη κατάσταση. Προσπαθεί να αναζητήσει το λειτουργικό σύστημα σε διαμερίσματα που χρησιμοποιούνται σε εικονικές μηχανές που εκτελούνται σε αυτό το υλικό.

Εάν το χρειάζεστε, μπορείτε να το αφήσετε, αλλά να έχετε υπόψη σας όλα τα παραπάνω. Συνιστώ να αναζητήσετε συνταγές για να απαλλαγείτε από τα άτακτα χέρια στο διαδίκτυο.

Με αυτό έχουμε ολοκληρώσει την αρχική εγκατάσταση. Ήρθε η ώρα να κάνετε επανεκκίνηση στο πρόσφατα εγκατεστημένο λειτουργικό σύστημα. Μην ξεχάσετε να αφαιρέσετε το εκκινήσιμο Live CD/USB.

#exit
#reboot

Επιλέξτε οποιοδήποτε από τα SATA SSD ως συσκευή εκκίνησης.

LVM σε SATA SSD

Σε αυτό το σημείο, έχουμε ήδη εκκινήσει στο νέο λειτουργικό σύστημα, διαμορφώσαμε το δίκτυο, apt, ανοίξαμε τον εξομοιωτή τερματικού και τρέξαμε:

#sudo bash

Ας συνεχίσουμε.

"Εκκίνηση" της συστοιχίας από SATA SSD:

#blkdiscard /dev/md2

Εάν δεν λειτουργεί, δοκιμάστε:

#blkdiscard --step 65536 /dev/md2
Δημιουργήστε LVM VG σε SATA SSD:

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

Γιατί άλλο VG..;Στην πραγματικότητα, έχουμε ήδη ένα VG με το όνομα root. Γιατί να μην προσθέσετε τα πάντα σε ένα VG;

Εάν υπάρχουν πολλά Φ/Β σε ένα VG, τότε για να ενεργοποιηθεί σωστά το VG, πρέπει να υπάρχουν όλα τα Φ/Β (online). Η εξαίρεση είναι το LVM RAID, το οποίο σκόπιμα δεν χρησιμοποιούμε.

Θέλουμε πραγματικά ότι εάν υπάρξει αποτυχία (απώλεια ανάγνωσης δεδομένων) σε κάποια από τις συστοιχίες RAID 6, το λειτουργικό σύστημα να εκκινήσει κανονικά και να μας δώσει την ευκαιρία να λύσουμε το πρόβλημα.

Για να γίνει αυτό, στο πρώτο επίπεδο αφαίρεσης θα απομονώσουμε κάθε τύπο φυσικών «μέσου» σε ένα ξεχωριστό VG.

Επιστημονικά μιλώντας, διαφορετικές συστοιχίες RAID ανήκουν σε διαφορετικούς «τομείς αξιοπιστίας». Δεν θα πρέπει να δημιουργήσετε ένα επιπλέον κοινό σημείο αποτυχίας για αυτούς στριμώχνοντάς τους σε ένα VG.

Η παρουσία του LVM σε επίπεδο «υλισμικού» θα μας επιτρέψει να κόβουμε αυθαίρετα κομμάτια διαφορετικών συστοιχιών RAID συνδυάζοντάς τα με διαφορετικούς τρόπους. Για παράδειγμα - τρέξτε συγχρόνως bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, μια σύνθετη διαμόρφωση ZFS με κρυφές μνήμες ή οποιοδήποτε άλλο κολασμένο μείγμα για να δοκιμάσετε να τα συγκρίνετε όλα.

Σε επίπεδο «υλισμικού», δεν θα χρησιμοποιήσουμε τίποτα άλλο εκτός από παλιούς καλούς «χοντρούς» τόμους LVM. Η εξαίρεση σε αυτόν τον κανόνα μπορεί να είναι το διαμέρισμα δημιουργίας αντιγράφων ασφαλείας.

Νομίζω ότι αυτή τη στιγμή, πολλοί αναγνώστες είχαν ήδη αρχίσει να υποψιάζονται κάτι για την κούκλα που φωλιάζει.

LVM σε σκληρό δίσκο SATA

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

Καινούργιο VG πάλι..;Θέλουμε πραγματικά, εάν η συστοιχία δίσκων που θα χρησιμοποιήσουμε για τη δημιουργία αντιγράφων ασφαλείας δεδομένων αποτύχει, το λειτουργικό μας σύστημα να συνεχίσει να λειτουργεί κανονικά, διατηρώντας παράλληλα την πρόσβαση σε μη εφεδρικά δεδομένα ως συνήθως. Επομένως, για να αποφύγουμε προβλήματα ενεργοποίησης VG, δημιουργούμε ένα ξεχωριστό VG.

Ρύθμιση της προσωρινής μνήμης LVM

Ας δημιουργήσουμε ένα LV στο NVMe RAID 1 για να το χρησιμοποιήσουμε ως συσκευή προσωρινής αποθήκευσης.

#lvcreate -L 70871154688B --name cache root

Γιατί είναι τόσο λίγα...;Γεγονός είναι ότι οι NVMe SSD μας διαθέτουν επίσης κρυφή μνήμη SLC. 4 gigabyte "δωρεάν" και 18 gigabyte δυναμικής λόγω του ελεύθερου χώρου που καταλαμβάνεται στο 3-bit MLC. Μόλις εξαντληθεί αυτή η κρυφή μνήμη, οι NVMe SSD δεν θα είναι πολύ πιο γρήγοροι από τον SATA SSD μας με προσωρινή μνήμη. Στην πραγματικότητα, για αυτόν τον λόγο, δεν έχει νόημα να κάνουμε το διαμέρισμα προσωρινής μνήμης LVM πολύ μεγαλύτερο από το διπλάσιο του μεγέθους της κρυφής μνήμης SLC της μονάδας δίσκου NVMe. Για τις μονάδες NVMe που χρησιμοποιούνται, ο συγγραφέας θεωρεί λογικό να δημιουργήσει 32-64 gigabyte cache.

Το δεδομένο μέγεθος διαμερίσματος απαιτείται για την οργάνωση 64 gigabyte προσωρινής μνήμης, μεταδεδομένων κρυφής μνήμης και δημιουργίας αντιγράφων ασφαλείας μεταδεδομένων.

Επιπλέον, σημειώνω ότι μετά από έναν βρώμικο τερματισμό του συστήματος, το LVM θα επισημάνει ολόκληρη την προσωρινή μνήμη ως βρώμικη και θα συγχρονίσει ξανά. Επιπλέον, αυτό θα επαναλαμβάνεται κάθε φορά που χρησιμοποιείται το lvchange σε αυτήν τη συσκευή μέχρι να επανεκκινηθεί ξανά το σύστημα. Επομένως, συνιστώ να δημιουργήσετε αμέσως ξανά την προσωρινή μνήμη χρησιμοποιώντας το κατάλληλο σενάριο.

Ας δημιουργήσουμε ένα LV στο SATA RAID 6 για να το χρησιμοποιήσουμε ως συσκευή προσωρινής αποθήκευσης.

#lvcreate -L 3298543271936B --name cache data

Γιατί μόνο τρία terabyte..;Για να μπορείτε, αν χρειαστεί, να χρησιμοποιήσετε SATA SSD RAID 6 για κάποιες άλλες ανάγκες. Το μέγεθος του αποθηκευμένου χώρου μπορεί να αυξηθεί δυναμικά, εν κινήσει, χωρίς να σταματήσει το σύστημα. Για να το κάνετε αυτό, πρέπει να διακόψετε προσωρινά και να ενεργοποιήσετε ξανά τη μνήμη cache, αλλά το χαρακτηριστικό πλεονέκτημα της προσωρινής μνήμης LVM έναντι, για παράδειγμα, της bcache είναι ότι αυτό μπορεί να γίνει αμέσως.

Ας δημιουργήσουμε ένα νέο VG για προσωρινή αποθήκευση.

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

Ας δημιουργήσουμε ένα LV στην προσωρινά αποθηκευμένη συσκευή.

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

Εδώ καταλάβαμε αμέσως όλο τον ελεύθερο χώρο στο /dev/data/cache, έτσι ώστε όλα τα άλλα απαραίτητα διαμερίσματα να δημιουργηθούν αμέσως στο /dev/root/cache. Εάν δημιουργήσατε κάτι σε λάθος μέρος, μπορείτε να το μετακινήσετε χρησιμοποιώντας το pvmove.

Ας δημιουργήσουμε και ενεργοποιήσουμε την προσωρινή μνήμη:

#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

Γιατί τόσο χοντρά..;Μέσω πρακτικών πειραμάτων, ο συγγραφέας μπόρεσε να ανακαλύψει ότι το καλύτερο αποτέλεσμα επιτυγχάνεται εάν το μέγεθος του μπλοκ κρυφής μνήμης LVM συμπίπτει με το μέγεθος του λεπτού μπλοκ LVM. Επιπλέον, όσο μικρότερο είναι το μέγεθος, τόσο καλύτερα αποδίδει η διαμόρφωση σε μια τυχαία εγγραφή.

64k είναι το ελάχιστο μέγεθος μπλοκ που επιτρέπεται για LVM thin.

Προσοχή γράψτε..!Ναί. Αυτός ο τύπος κρυφής μνήμης αναβάλλει το συγχρονισμό εγγραφής στη συσκευή που έχει αποθηκευτεί στην κρυφή μνήμη. Αυτό σημαίνει ότι εάν χαθεί η προσωρινή μνήμη, ενδέχεται να χάσετε δεδομένα στη συσκευή που έχει αποθηκευτεί στην προσωρινή μνήμη. Αργότερα, ο συγγραφέας θα σας πει ποια μέτρα, εκτός από το NVMe RAID 1, μπορούν να ληφθούν για την αντιστάθμιση αυτού του κινδύνου.

Αυτός ο τύπος κρυφής μνήμης επιλέχθηκε σκόπιμα για να αντισταθμίσει την κακή απόδοση τυχαίας εγγραφής του RAID 6.

Ας ελέγξουμε τι έχουμε:

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

Μόνο το [cachedata_corig] θα πρέπει να βρίσκεται στο /dev/data/cache. Εάν κάτι δεν πάει καλά, χρησιμοποιήστε το pvmove.

Μπορείτε να απενεργοποιήσετε την προσωρινή μνήμη εάν είναι απαραίτητο με μία εντολή:

#lvconvert -y --uncache cache/cachedata

Αυτό γίνεται on-line. Το LVM απλώς θα συγχρονίσει τη μνήμη cache με το δίσκο, θα την αφαιρέσει και θα μετονομάσει cachedata_corig σε cachedata.

Ρύθμιση LVM thin

Ας υπολογίσουμε χονδρικά πόσο χώρο χρειαζόμαστε για τα λεπτά μεταδεδομένα 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"

Στρογγυλοποίηση έως 4 gigabyte: 4294967296B

Πολλαπλασιάστε επί δύο και προσθέστε 4194304B για μεταδεδομένα LVM PV: 8594128896B
Ας δημιουργήσουμε ένα ξεχωριστό διαμέρισμα στο NVMe RAID 1 για να τοποθετήσουμε τα λεπτά μεταδεδομένα LVM και το αντίγραφο ασφαλείας τους σε αυτό:

#lvcreate -L 8594128896B --name images root

Για τι..?Εδώ μπορεί να προκύψει το ερώτημα: γιατί να τοποθετήσετε τα λεπτά μεταδεδομένα LVM ξεχωριστά, εάν θα εξακολουθούν να είναι αποθηκευμένα στην κρυφή μνήμη στο NVMe και θα λειτουργούν γρήγορα.

Αν και η ταχύτητα είναι σημαντική εδώ, απέχει πολύ από τον κύριο λόγο. Το θέμα είναι ότι η κρυφή μνήμη είναι ένα σημείο αποτυχίας. Κάτι θα μπορούσε να συμβεί σε αυτό και εάν τα λεπτά μεταδεδομένα του LVM αποθηκευτούν προσωρινά, θα χαθούν εντελώς τα πάντα. Χωρίς πλήρη μεταδεδομένα, θα είναι σχεδόν αδύνατο να συγκεντρωθούν λεπτοί όγκοι.

Μετακινώντας τα μεταδεδομένα σε ξεχωριστό τόμο που δεν είναι αποθηκευμένο στην κρυφή μνήμη, αλλά γρήγορο, εγγυόμαστε την ασφάλεια των μεταδεδομένων σε περίπτωση απώλειας ή καταστροφής της κρυφής μνήμης. Σε αυτήν την περίπτωση, όλες οι ζημιές που προκαλούνται από την απώλεια της κρυφής μνήμης θα εντοπιστούν μέσα σε λεπτούς όγκους, γεγονός που θα απλοποιήσει τη διαδικασία ανάκτησης κατά τάξεις μεγέθους. Με μεγάλη πιθανότητα, αυτές οι ζημιές θα αποκατασταθούν χρησιμοποιώντας αρχεία καταγραφής FS.

Επιπλέον, εάν προηγουμένως λήφθηκε ένα στιγμιότυπο ενός μικρού τόμου και στη συνέχεια η κρυφή μνήμη συγχρονίστηκε πλήρως τουλάχιστον μία φορά, τότε, λόγω του εσωτερικού σχεδιασμού του LVM thin, η ακεραιότητα του στιγμιότυπου θα είναι εγγυημένη σε περίπτωση απώλειας της κρυφής μνήμης .

Ας δημιουργήσουμε ένα νέο VG που θα είναι υπεύθυνο για την λεπτή παροχή:

#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
Γιατί -Z yΕκτός από αυτό για το οποίο πραγματικά προορίζεται αυτή η λειτουργία - για να αποτρέψει τη διαρροή δεδομένων από μια εικονική μηχανή σε μια άλλη εικονική μηχανή κατά την ανακατανομή χώρου - ο μηδενισμός χρησιμοποιείται επιπλέον για την αύξηση της ταχύτητας τυχαίας εγγραφής σε μπλοκ μικρότερα από 64k. Οποιαδήποτε εγγραφή μικρότερη από 64 k σε μια προηγουμένως μη εκχωρημένη περιοχή του λεπτού τόμου θα γίνει 64K ευθυγραμμισμένη με τις άκρες στη μνήμη cache. Αυτό θα επιτρέψει την εκτέλεση της λειτουργίας εξ ολοκλήρου μέσω της κρυφής μνήμης, παρακάμπτοντας τη συσκευή που έχει αποθηκευτεί στην κρυφή μνήμη.

Ας μετακινήσουμε τα LV στα αντίστοιχα PV:

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

Προσεκτικά! Πόρος!Αυτός ο κωδικός θα εκτελέσει 36 διαφορετικές δοκιμές, καθεμία από τις οποίες εκτελείται για 4 δευτερόλεπτα. Τα μισά τεστ είναι για καταγραφή. Μπορείτε να εγγράψετε πολλά στο NVMe σε 4 δευτερόλεπτα. Έως 3 gigabyte ανά δευτερόλεπτο. Έτσι, κάθε εκτέλεση δοκιμών γραφής μπορεί να καταναλώσει έως και 216 gigabyte πόρου SSD από εσάς.

Ανάμειξη ανάγνωσης και γραφής;Ναί. Είναι λογικό να εκτελούνται τα τεστ ανάγνωσης και εγγραφής ξεχωριστά. Επιπλέον, είναι λογικό να διασφαλιστεί ότι όλες οι κρυφές μνήμες είναι συγχρονισμένες έτσι ώστε μια εγγραφή που έγινε προηγουμένως να μην επηρεάζει την ανάγνωση.

Τα αποτελέσματα θα διαφέρουν πολύ κατά την πρώτη εκκίνηση και τις επόμενες καθώς η κρυφή μνήμη και ο λεπτός όγκος γεμίζουν, και επίσης ανάλογα με το αν το σύστημα κατάφερε να συγχρονίσει τις κρυφές μνήμες που γεμίστηκαν κατά την τελευταία εκκίνηση.

Μεταξύ άλλων, προτείνω τη μέτρηση της ταχύτητας σε έναν ήδη γεμάτο λεπτό όγκο από τον οποίο μόλις τραβήχτηκε ένα στιγμιότυπο. Ο συγγραφέας είχε την ευκαιρία να παρατηρήσει πώς οι τυχαίες εγγραφές επιταχύνονται απότομα αμέσως μετά τη δημιουργία του πρώτου στιγμιότυπου, ειδικά όταν η κρυφή μνήμη δεν είναι ακόμη εντελώς πλήρης. Αυτό συμβαίνει λόγω της σημασιολογίας εγγραφής αντιγραφής σε εγγραφή, της ευθυγράμμισης της κρυφής μνήμης και των μπλοκ λεπτών τόμων και του γεγονότος ότι μια τυχαία εγγραφή στο RAID 6 μετατρέπεται σε τυχαία ανάγνωση από το RAID 6 ακολουθούμενη από εγγραφή στην κρυφή μνήμη. Στη διαμόρφωσή μας, η τυχαία ανάγνωση από το RAID 6 είναι έως και 6 φορές (ο αριθμός των SATA SSD στη συστοιχία) ταχύτερη από την εγγραφή. Επειδή Τα μπλοκ για το CoW κατανέμονται διαδοχικά από μια λεπτή δεξαμενή και στη συνέχεια η εγγραφή, ως επί το πλείστον, μετατρέπεται επίσης σε διαδοχική.

Και τα δύο αυτά χαρακτηριστικά μπορούν να χρησιμοποιηθούν προς όφελός σας.

Αποθηκεύστε προσωρινά "συνεκτικά" στιγμιότυπα

Για να μειωθεί ο κίνδυνος απώλειας δεδομένων σε περίπτωση βλάβης/απώλειας της κρυφής μνήμης, ο συγγραφέας προτείνει να εισαχθεί η πρακτική της περιστροφής στιγμιότυπων για να διασφαλιστεί η ακεραιότητά τους σε αυτήν την περίπτωση.

Πρώτον, επειδή τα μεταδεδομένα μικρού όγκου βρίσκονται σε μια συσκευή που δεν έχει αποθηκευτεί στην κρυφή μνήμη, τα μεταδεδομένα θα είναι συνεπή και οι πιθανές απώλειες θα απομονωθούν μέσα σε μπλοκ δεδομένων.

Ο ακόλουθος κύκλος περιστροφής στιγμιότυπου εγγυάται την ακεραιότητα των δεδομένων μέσα στα στιγμιότυπα σε περίπτωση απώλειας της προσωρινής μνήμης:

  1. Για κάθε λεπτό τόμο με το όνομα <όνομα>, δημιουργήστε ένα στιγμιότυπο με το όνομα <name>.cached
  2. Ας ορίσουμε το όριο μετεγκατάστασης σε μια λογική υψηλή τιμή: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. Στον βρόχο ελέγχουμε τον αριθμό των βρώμικων μπλοκ στην κρυφή μνήμη: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' μέχρι να πάρουμε το μηδέν. Εάν το μηδέν λείπει για πολύ μεγάλο χρονικό διάστημα, μπορεί να δημιουργηθεί με προσωρινή εναλλαγή της προσωρινής μνήμης στη λειτουργία εγγραφής. Ωστόσο, λαμβάνοντας υπόψη τα χαρακτηριστικά ταχύτητας των συστοιχιών SATA και NVMe SSD μας, καθώς και τον πόρο TBW τους, θα μπορείτε είτε να συλλάβετε γρήγορα τη στιγμή χωρίς να αλλάξετε τη λειτουργία προσωρινής αποθήκευσης ή το υλικό σας θα καταναλώσει εντελώς ολόκληρο τον πόρο του λίγες ημέρες. Λόγω περιορισμών πόρων, το σύστημα, καταρχήν, δεν μπορεί να είναι κάτω από το 100% φορτίο εγγραφής όλη την ώρα. Οι NVMe SSD μας κάτω από 100% φορτίο εγγραφής θα εξαντλήσουν πλήρως τον πόρο 3 4-ημέρες. Οι SATA SSD θα διαρκέσουν μόνο δύο φορές περισσότερο. Επομένως, θα υποθέσουμε ότι το μεγαλύτερο μέρος του φορτίου πηγαίνει στην ανάγνωση και έχουμε σχετικά βραχυπρόθεσμες εκρήξεις εξαιρετικά υψηλής δραστηριότητας σε συνδυασμό με χαμηλό φορτίο κατά μέσο όρο για τη γραφή.
  4. Μόλις πιάσαμε (ή φτιάξαμε) ένα μηδέν, μετονομάζουμε το <name>.cached σε <name>.committed. Το παλιό <name>.committed διαγράφεται.
  5. Προαιρετικά, εάν η κρυφή μνήμη είναι 100% γεμάτη, μπορεί να δημιουργηθεί εκ νέου από ένα σενάριο, διαγράφοντας έτσι. Με μισοάδειο cache, το σύστημα λειτουργεί πολύ πιο γρήγορα κατά την εγγραφή.
  6. Ορίστε το όριο μετεγκατάστασης στο μηδέν: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata Αυτό θα αποτρέψει προσωρινά το συγχρονισμό της κρυφής μνήμης με το κύριο μέσο.
  7. Περιμένουμε μέχρι να συγκεντρωθούν πολλές αλλαγές στην κρυφή μνήμη #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' ή το χρονόμετρο θα σβήσει.
  8. Επαναλαμβάνουμε ξανά.

Γιατί δυσκολίες με το κατώφλι μετανάστευσης...;Το θέμα είναι ότι στην πραγματική πράξη, μια «τυχαία» εγγραφή δεν είναι στην πραγματικότητα εντελώς τυχαία. Εάν γράψαμε κάτι σε έναν τομέα μεγέθους 4 kilobyte, υπάρχει μεγάλη πιθανότητα στα επόμενα δύο λεπτά να γίνει εγγραφή στον ίδιο ή σε έναν από τους γειτονικούς τομείς (+- 32K).

Ρυθμίζοντας το όριο μετεγκατάστασης στο μηδέν, αναβάλλουμε τον συγχρονισμό εγγραφής στον SATA SSD και συγκεντρώνουμε αρκετές αλλαγές σε ένα μπλοκ 64K στη μνήμη cache. Αυτό εξοικονομεί σημαντικά τον πόρο του SATA SSD.

Που είναι ο κωδικός..;Δυστυχώς, ο συγγραφέας θεωρεί τον εαυτό του ανεπαρκώς ικανό στην ανάπτυξη σεναρίων bash επειδή είναι 100% αυτοδίδακτος και εξασκεί την ανάπτυξη που βασίζεται στο «google», επομένως πιστεύει ότι ο τρομερός κώδικας που βγαίνει από τα χέρια του δεν πρέπει να χρησιμοποιηθεί από κανέναν αλλού.

Νομίζω ότι οι επαγγελματίες σε αυτόν τον τομέα θα μπορούν να απεικονίσουν ανεξάρτητα όλη τη λογική που περιγράφεται παραπάνω, εάν είναι απαραίτητο, και, ίσως, ακόμη και να την σχεδιάσουν όμορφα ως συστημική υπηρεσία, όπως προσπάθησε να κάνει ο συγγραφέας.

Ένα τέτοιο απλό σχήμα περιστροφής στιγμιότυπου θα μας επιτρέψει όχι μόνο να έχουμε συνεχώς ένα στιγμιότυπο πλήρως συγχρονισμένο στον SATA SSD, αλλά θα μας επιτρέψει επίσης, χρησιμοποιώντας το βοηθητικό πρόγραμμα thin_delta, να μάθουμε ποια μπλοκ άλλαξαν μετά τη δημιουργία του και, επομένως, να εντοπίσουμε τη ζημιά στο οι κύριοι όγκοι, απλοποιώντας σημαντικά την ανάκτηση.

TRIM/DISCARD σε libvirt/KVM

Επειδή η αποθήκευση δεδομένων θα χρησιμοποιηθεί για το KVM που εκτελεί το libvirt, τότε θα ήταν καλή ιδέα να διδάξουμε στα VM μας όχι μόνο να καταλαμβάνουν ελεύθερο χώρο, αλλά και να ελευθερώνουν ό,τι δεν χρειάζεται πλέον.

Αυτό γίνεται με εξομοίωση της υποστήριξης TRIM/DISCARD σε εικονικούς δίσκους. Για να το κάνετε αυτό, πρέπει να αλλάξετε τον τύπο του ελεγκτή σε virtio-scsi και να επεξεργαστείτε το 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>

Τέτοιες ΑΠΟΡΡΙΨΕΙΣ από φιλοξενούμενα λειτουργικά συστήματα επεξεργάζονται σωστά το LVM και τα μπλοκ απελευθερώνονται σωστά τόσο στην κρυφή μνήμη όσο και στη λεπτή πισίνα. Στην περίπτωσή μας, αυτό συμβαίνει κυρίως με καθυστερημένο τρόπο, κατά τη διαγραφή του επόμενου στιγμιότυπου.

Δημιουργία αντιγράφων ασφαλείας BTRFS

Χρησιμοποιήστε έτοιμα σενάρια με άκρο προσοχή και με δική του ευθύνη. Ο συγγραφέας έγραψε αυτόν τον κώδικα μόνος του και αποκλειστικά για τον εαυτό του. Είμαι βέβαιος ότι πολλοί έμπειροι χρήστες Linux έχουν παρόμοια εργαλεία και δεν χρειάζεται να αντιγράψετε τα εργαλεία κάποιου άλλου.

Ας δημιουργήσουμε έναν τόμο στη συσκευή δημιουργίας αντιγράφων ασφαλείας:

#lvcreate -L 256G --name backup backup

Ας το μορφοποιήσουμε σε BTRFS:

#mkfs.btrfs /dev/backup/backup

Ας δημιουργήσουμε σημεία προσάρτησης και ας προσαρτήσουμε τις ριζικές υποενότητες του συστήματος αρχείων:

#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

Ας αντιγράψουμε το σενάριο:

Πολλοί τρομακτικοί κώδικας bash. Χρησιμοποιήστε το με δική σας ευθύνη. Μην γράφετε θυμωμένα γράμματα στον συγγραφέα...#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

Τι κανει καν..?Περιέχει ένα σύνολο απλών εντολών για τη δημιουργία στιγμιότυπων BTRFS και την αντιγραφή τους σε άλλο FS χρησιμοποιώντας αποστολή/λήψη BTRFS.

Η πρώτη εκτόξευση μπορεί να είναι σχετικά μεγάλη, γιατί... Στην αρχή, όλα τα δεδομένα θα αντιγραφούν. Περαιτέρω εκτοξεύσεις θα είναι πολύ γρήγορες, γιατί... Μόνο οι αλλαγές θα αντιγραφούν.

Ένα άλλο σενάριο που θα βάλουμε στο cron:

Κάποιος ακόμη κωδικός bash#cat >/root/btrfs-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

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

BACKUP_SCRIPT="$SCRIPT_DIR/btrfs-backup.sh"
RETENTION="-60 day"
$BACKUP_SCRIPT backup root/@
$BACKUP_SCRIPT removeall root/@ "$RETENTION"
$BACKUP_SCRIPT backup root/@home
$BACKUP_SCRIPT removeall root/@home "$RETENTION"
$BACKUP_SCRIPT backup boot/
$BACKUP_SCRIPT removeall boot/ "$RETENTION"
EOF

Τι κάνει..?Δημιουργεί και συγχρονίζει σταδιακά στιγμιότυπα των αναφερόμενων τόμων BTRFS στο εφεδρικό FS. Μετά από αυτό, διαγράφει όλες τις εικόνες που δημιουργήθηκαν πριν από 60 ημέρες. Μετά την εκκίνηση, θα εμφανιστούν χρονολογημένα στιγμιότυπα των τόμων που αναφέρονται στους υποκαταλόγους /backup/btrfs/back/remote/.

Ας δώσουμε τα δικαιώματα εκτέλεσης κώδικα:

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

Ας το ελέγξουμε και ας το βάλουμε στο 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

Λεπτό αντίγραφο ασφαλείας LVM

Ας δημιουργήσουμε μια λεπτή πισίνα στη συσκευή δημιουργίας αντιγράφων ασφαλείας:

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

Ας εγκαταστήσουμε το ddrescue, γιατί... τα σενάρια θα χρησιμοποιήσουν αυτό το εργαλείο:

#apt-get install gddrescue

Ας δημιουργήσουμε έναν κατάλογο για σενάρια:

#mkdir /root/lvm-thin-backup

Ας αντιγράψουμε τα σενάρια:

Πολύ μπαμ μέσα...#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

Τι κάνει...?Περιέχει ένα σύνολο εντολών για τον χειρισμό λεπτών στιγμιότυπων και τον συγχρονισμό της διαφοράς μεταξύ δύο λεπτών στιγμιότυπων που λαμβάνονται μέσω thin_delta σε άλλη συσκευή μπλοκ χρησιμοποιώντας ddrescue και blkdiscard.

Ένα άλλο σενάριο που θα βάλουμε στο cron:

Λίγο ακόμα μπας#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

Τι κάνει...?Χρησιμοποιεί το προηγούμενο σενάριο για να δημιουργήσει και να συγχρονίσει αντίγραφα ασφαλείας των αναφερόμενων λεπτών τόμων. Το σενάριο θα αφήσει ανενεργά στιγμιότυπα των αναφερόμενων τόμων, τα οποία χρειάζονται για την παρακολούθηση των αλλαγών από τον τελευταίο συγχρονισμό.

Αυτό το σενάριο πρέπει να υποβληθεί σε επεξεργασία, προσδιορίζοντας τη λίστα των λεπτών τόμων για τους οποίους πρέπει να δημιουργηθούν αντίγραφα ασφαλείας. Τα ονόματα που δίνονται είναι μόνο για επεξηγηματικούς σκοπούς. Εάν θέλετε, μπορείτε να γράψετε ένα σενάριο που θα συγχρονίζει όλους τους τόμους.

Ας δώσουμε τα δικαιώματα:

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

Ας το ελέγξουμε και ας το βάλουμε στο 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

Η πρώτη εκτόξευση θα είναι μεγάλη, γιατί... Οι λεπτοί τόμοι θα συγχρονιστούν πλήρως αντιγράφοντας όλο τον χρησιμοποιημένο χώρο. Χάρη στα λεπτά μεταδεδομένα LVM, γνωρίζουμε ποια μπλοκ χρησιμοποιούνται πραγματικά, επομένως θα αντιγραφούν μόνο τα μπλοκ λεπτού όγκου που χρησιμοποιούνται πραγματικά.

Οι επόμενες εκτελέσεις θα αντιγράψουν τα δεδομένα σταδιακά χάρη στην παρακολούθηση αλλαγών μέσω των λεπτών μεταδεδομένων LVM.

Ας δούμε τι έγινε:

#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

Τι σχέση έχει αυτό με τις κούκλες που φωλιάζουν;

Πιθανότατα, δεδομένου ότι οι λογικοί όγκοι LVM LV μπορούν να είναι φυσικοί όγκοι LVM PV για άλλα VG. Το LVM μπορεί να είναι αναδρομικό, όπως οι κούκλες που φωλιάζουν. Αυτό δίνει στο LVM εξαιρετική ευελιξία.

PS

Στο επόμενο άρθρο, θα προσπαθήσουμε να χρησιμοποιήσουμε αρκετά παρόμοια συστήματα αποθήκευσης για φορητές συσκευές/KVM ως βάση για τη δημιουργία ενός συμπλέγματος γεωδιανεμημένης αποθήκευσης/vm με πλεονασμό σε πολλές ηπείρους χρησιμοποιώντας οικιακούς επιτραπέζιους υπολογιστές, το οικιακό Διαδίκτυο και δίκτυα P2P.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο