In questo articolo abiliteremo il RAID software su User Mode Linux. Compileremo il driver nel kernel della macchina virtuale, creeremo i file per alcuni dispositivi virtuali, installeremo il software per l’amministrazione degli array e testeremo varie tipologie RAID supportate. Utilizzeremo il root_fs di una virtual machine già creata con sufficiente spazio disco per l’installazione del software necessario ed il supporto di rete per eseguire apt
Ambiente di lavoro
Supponiamo di avere preparato il root_fs per la virtual machine di test nel file uml-ubda nella cartella ~/uml/uml-raid
Per la compilazione del kernel abbiamo bisogno di alcuni pacchetti
1 |
# apt install -y gcc make bc libncurses5-dev |
Supporto RAID
Il supporto multi device non è abilitato nella versione normalmente distribuita con il pacchetto debian di user mode linux, quindi lo compiliamo monoliticamente all’interno del file linux che usiamo per eseguire le virtual machine. Visualizziamo la versione di kernel utilizzata dall’ uml che abbiamo installato
1 2 |
# linux --version 4.9.25 |
Quindi scarichiamo da kernel.org l’archivio con lo stesso numero di versione salvandolo in una cartella di lavoro, decomprimiamo l’archivio ed entriamo nella cartella
1 2 3 4 5 6 7 8 9 |
# mkdir uml-src # cd uml-src/ # wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.9.25.tar.gz # tar -xzf linux-4.9.25.tar.gz # cd linux-4.9.25 |
Creiamo una configurazione di default
1 |
# make defconfig ARCH=um |
Ora modifichiamo la configurazione
1 |
# make menuconfig ARCH=um |
Ci troviamo nella root del menù di configurazione
Entriamo in “Device Drivers”, spostiamoci su “Multiple devices driver support (RAID and LVM)” ed abilitiamo il supporto con Y
Entriamo nel menù, abilitiamo con Y il menù “RAID support” e tutte le voci che si aprono sotto di esso, sempre con Y
Usciamo dando 3 volte Exit e salviamo la configurazione
Avviamo la compilazione
1 |
# make all ARCH=um |
Terminata la compilazione, copiamo l’eseguibile linux risultante nella cartella in cui abbiamo preparato la macchina virtuale da utilizzare per i test. Per avviare la virtual machine, dovremo lanciare questo eseguibile al posto di quello distribuito con il pacchetto uml. Copiamo quindi l’eseguibile rinominandolo in modo da distinguerlo da quello originale
1 |
# cp linux ~/uml/uml-raid/linux-raid |
Preparazione dei dischi
Prepariamo i file per i dischi virtuali che ci servono. Per i nostri test creiamo 4 file di cui uno da 100 MB e tre da 200 MB per mostrare le differenze tra i vari livelli di array
1 2 3 4 5 |
# dd if=/dev/zero of=disk0 bs=1M count=100 # dd if=/dev/zero of=disk1 bs=1M count=200 # dd if=/dev/zero of=disk2 bs=1M count=200 # dd if=/dev/zero of=disk3 bs=1M count=200 # dd if=/dev/zero of=disk4 bs=1M count=200 |
Avvio della Virtual Machine
Avviamo la nostra uml, assegnandole il nome uml-raid con il supporto di rete di navigazione tramite l’host sull’ interfaccia eth0 che avremo già opportunamente configurato al suo interno
1 2 3 4 5 6 7 8 9 |
# ./linux-raid \ umid=uml-raid \ ubda=uml-ubda \ root=/dev/ubda1 \ ubdb=disk0 ubdc=disk1 ubdd=disk2 ubde=disk3 ubdf=disk4 \ mem=128M \ con0=fd:0,fd:1 \ con=pts \ eth0=tuntap,,fe:fd:00:00:01:01,10.0.1.1 |
In un secondo terminale entriamo nella vm facendo login
1 |
# screen /dev/pts/4 |
Nella vm possiamo vedere che in /dev è presente il dispositivo multi device md0 ed i 5 dischi virtuali
1 2 3 4 5 |
# ls /dev/ubd? /dev/ubda /dev/ubdb /dev/ubdc /dev/ubdd /dev/ubde /dev/ubdf # ls /dev/md* /dev/md0 |
Creiamo altri due device md che ci serviranno per i test con alcune configurazioni ibride
1 2 3 4 5 6 |
# mknod -m 0660 /dev/md1 b 9 1 # mknod -m 0660 /dev/md2 b 9 2 # ls /dev/md* /dev/md0 /dev/md1 /dev/md2 |
Installiamo il software per l’amministrazione dei dispositivi raid
1 |
# apt install mdadm |
Creiamo una cartella in cui montare il raid
1 |
# mkdir -p /mnt/raid |
Test dei livelli RAID supportati
Eseguiamo alcune prove sui livelli di RAID supportati dal driver. Ogni volta che costruiremo un array, ripuliremo prima i dischi utilizzati dai meta-dati contenuti in questo modo
1 2 3 4 5 |
# mdadm --zero-superblock /dev/ubdb # mdadm --zero-superblock /dev/ubdc # mdadm --zero-superblock /dev/ubdd # mdadm --zero-superblock /dev/ubde # mdadm --zero-superblock /dev/ubdf |
Dopo aver costruito l’array, formatteremo il device /dev/md0 a cui è collegato in ext2 senza creare prima una partizione al suo interno. E’ un passaggio inutile ai fini dei test, servirebbe solo se volessimo montare quella partizione al boot della vm
1 |
# mke2fs /dev/md0 |
Monteremo il device sul mount point /mnt/raid
1 |
# mount /dev/md0 /mnt/raid |
Dopo aver eseguito i test lo smonteremo e lo fermeremo l’array in modo da liberare i dischi per il test successivo
1 2 |
# umount /dev/md0 # mdadm --stop /dev/md0 |
RAID 0 ( striping )
Questo livello di raid crea un dispositivo con una capienza che è la somma dello spazio disponibile ai dischi montati nell’ array. Non viene riservato spazio per la ridondanza, ed i blocchi vengono distribuiti tra tutti i nodi. Questo permette una lettura in parallelo tra tutti i nodi incrementando la velocità in lettura e scrittura, ma il guasto ad un solo nodo compromette la coerenza di tutto il raid
Utilizziamo i primi due dischi, quello da 100 MB e quello da 200 MB passando a mdadm rispettivamente /dev/ubdb e /dev/ubdc
1 2 3 4 5 6 7 8 |
# mdadm --create --verbose /dev/md0 \ --level=0 \ --raid-devices=2 \ /dev/ubdb /dev/ubdc mdadm: chunk size defaults to 512K mdadm: Defaulting to version 1.2 metadata mdadm: array /dev/md0 started. |
Il raid presenta queste caratteristiche
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# mdadm --detail /dev/md0 /dev/md0: Version : 1.2 Creation Time : Wed Mar 6 14:35:48 2019 Raid Level : raid0 Array Size : 305152 (298.00 MiB 312.48 MB) Raid Devices : 2 Total Devices : 2 Persistence : Superblock is persistent Update Time : Wed Mar 6 14:35:48 2019 State : clean Active Devices : 2 Working Devices : 2 Failed Devices : 0 Spare Devices : 0 Chunk Size : 512K Name : uml-base:0 (local to host uml-base) UUID : 4ec8d2d6:ecd2f855:eb8a0cf5:172fc080 Events : 0 Number Major Minor RaidDevice State 0 98 16 0 active sync /dev/ubdb 1 98 32 1 active sync /dev/ubdc |
Creiamo il filesystem in /dev/md0, montiamo il device su /mnt/raid e visualizziamo lo spazio disponibile
1 2 3 4 |
# df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 289M 2.1M 272M 1% /mnt/raid |
Nel raid ci sono circa 300 MB
Smontiamo il device, terminiamo l’array e ripuliamo i dischi, dopodiché ripetiamo le stesse operazioni con 2 dischi da 200MB, ad esempio ubdbc ed ubdd. Riformattiamo il device /dev/md0 e verifichiamo lo spazio disponibile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# mdadm --detail /dev/md0 /dev/md0: Version : 1.2 Creation Time : Wed Mar 6 14:39:50 2019 Raid Level : raid0 Array Size : 407552 (398.00 MiB 417.33 MB) Raid Devices : 2 Total Devices : 2 Persistence : Superblock is persistent Update Time : Wed Mar 6 14:39:50 2019 State : clean Active Devices : 2 Working Devices : 2 Failed Devices : 0 Spare Devices : 0 Chunk Size : 512K Name : uml-base:0 (local to host uml-base) UUID : e65c3076:0194e40e:55ccd945:c2006f47 Events : 0 Number Major Minor RaidDevice State 0 98 32 0 active sync /dev/ubdc 1 98 48 1 active sync /dev/ubdd # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 386M 2.3M 364M 1% /mnt/raid |
La capienza ora è di quasi 400 MB
Aggiungendo altri dischi, la capacità totale continua a crescere
1 2 3 4 5 6 7 8 9 10 |
# mdadm --create --verbose /dev/md0 \ --level=0 \ --raid-devices=4 \ /dev/ubdb /dev/ubdc /dev/ubdd /dev/ubde # ... # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 686M 712K 650M 1% /mnt/raid |
RAID 1 ( mirroring )
Questo livello di array è dotato di ridondanza. I nodi che partecipano all’ array, che possono essere dischi o array raid, sono uno lo specchio degli altri. Questo implica che la capacità totale dell’array è limitata dal nodo di dimensioni inferiori. Utilizziamo l’opzione –level=1 e montiamo i primi due dischi
1 2 3 4 |
# mdadm --create --verbose /dev/md0 \ --level=1 \ --raid-devices=2 \ /dev/ubdb /dev/ubdc |
Nella fase di creazione dell’ array il driver ci avverte che i due dischi sono di dimensioni molto diverse, cosa che con il raid 0 non succede.
1 2 |
mdadm: size set to 102272K mdadm: largest drive (/dev/ubdc) exceeds size (102272K) by more than 1% |
Dopo le operazioni viste prima, visualizziamo le caratteristiche del raid e lo spazio disponibile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# mdadm --detail /dev/md0 /dev/md0: Version : 1.2 Creation Time : Wed Mar 6 15:15:17 2019 Raid Level : raid1 Array Size : 102272 (99.88 MiB 104.73 MB) Used Dev Size : 102272 (99.88 MiB 104.73 MB) Raid Devices : 2 Total Devices : 2 Persistence : Superblock is persistent Update Time : Wed Mar 6 15:15:17 2019 State : clean, resyncing Active Devices : 2 Working Devices : 2 Failed Devices : 0 Spare Devices : 0 Resync Status : 35% complete Name : uml-base:0 (local to host uml-base) UUID : ab91e115:e4eba8d1:383cada0:0728f313 Events : 3 Number Major Minor RaidDevice State 0 98 16 0 active sync /dev/ubdb 1 98 32 1 active sync /dev/ubdc # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 97M 1.6M 91M 2% /mnt/raid |
Ora sono disponibili quasi 100MB limitati dal disco ubdb. Ripetiamo l’operazione utilizziamo due dischi da 200 MB
1 2 3 4 |
mdadm --create --verbose /dev/md0 \ --level=1 \ --raid-devices=2 \ /dev/ubdc /dev/ubdd |
Visualizziamo lo spazio disponibile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# mdadm --detail /dev/md0 /dev/md0: Version : 1.2 Creation Time : Wed Mar 6 15:19:52 2019 Raid Level : raid1 Array Size : 204608 (199.81 MiB 209.52 MB) Used Dev Size : 204608 (199.81 MiB 209.52 MB) Raid Devices : 2 Total Devices : 2 Persistence : Superblock is persistent Update Time : Wed Mar 6 15:19:52 2019 State : clean, resyncing Active Devices : 2 Working Devices : 2 Failed Devices : 0 Spare Devices : 0 Resync Status : 21% complete Name : uml-base:0 (local to host uml-base) UUID : 54ffdff2:cc8b09fb:4490eaf5:ac57f4cf Events : 1 Number Major Minor RaidDevice State 0 98 32 0 active sync /dev/ubdc 1 98 48 1 active sync /dev/ubdd # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 194M 1.6M 182M 1% /mnt/raid |
Ora ci sono quasi 200M
Ripetiamo l’operazione includendo tutti i 4 dischi, vediamo che ubdb limita lo spazio di tutto l’array poichè solo 100 MB possono essere replicati
1 2 3 4 5 6 7 8 9 10 |
# mdadm --create --verbose /dev/md0 \ --level=1 \ --raid-devices=4 \ /dev/ubdb /dev/ubdc /dev/ubdd /dev/ubde # ... # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 97M 1.6M 91M 2% /mnt/raid |
RAID 4
Il Raid 4 è molto simile al Raid 0 perchè distribuisce i blocchi tra i nodi sommando le capacità di ciascuno, la differenza è che utilizza l’ultimo dei rami per memorizzare i blocchi di parità.
Ogni blocco di parità viene calcolato tramite una XOR tra tutti i corrispondenti blocchi dati sugli altri rami, questo significa che detto N il numero di nodi, e D la dimensione del ramo più piccolo, la capacità dell’array sarà dell’ ordine di ( N – 1 ) * D
In questo modo nel caso in cui uno dei dischi si dovesse rompere è sempre possibile ricostruirne il contenuto grazie agli altri
E’ veloce in lettura perchè può sfruttare il parallelismo su rami diversi, però in scrittura è leggermente più lento perchè il driver oltre a scrivere il blocco, deve leggere i blocchi sugli altri rami, calcolare e poi scrivere la parità. La capacità viene limitata dal ramo di dimensione minore, invece se i sono tutti della stessa dimensione, vengono sommate le capacità di tutti i rami dedicati ai dati
Possiamo creare l’array con soli 2 dischi, come prima proviamo con due dischi di dimensioni diverse, utilizziamo quello da 100 MB per i dati e quello da 200MB per la parità
1 2 3 4 |
# mdadm --create --verbose /dev/md0 \ --level=4 \ --raid-devices=2 \ /dev/ubdb /dev/ubdc |
Lo spazio disponibile è di circa 100 MB
1 2 3 |
# df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 96M 1.6M 90M 2% /mnt/raid |
Aggiungiamo un terzo disco da 200 MB
1 2 3 4 |
# mdadm --create --verbose /dev/md0 \ --level=4 \ --raid-devices=3 \ /dev/ubdb /dev/ubdc /dev/ubdd |
Lo spazio disponibile è passato a 2 * 100 MB = 200 MB ( circa )
1 2 3 |
# df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 192M 1.6M 181M 1% /mnt/raid |
Aggiungiamo il quarto disco da 200MB
1 2 3 4 |
# mdadm --create --verbose /dev/md0 \ --level=4 \ --raid-devices=4 \ /dev/ubdb /dev/ubdc /dev/ubdd /dev/ubde |
Lo spazio disponibile è passato a 3 * 100 MB = 300 MB ( circa )
1 2 3 |
# df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 288M 2.1M 271M 1% /mnt/raid |
RAID 5
E’ molto simile al raid 4, solo che i blocchi di parità sono distribuiti tra tutti i nodi cosa che permette di sfruttare meglio il parallelismo in lettura ed in scrittura tra i rami. Eseguire questi test sul raid 5 darebbe gli stessi risultati
RAID 6
Questo livello è simile al 5, però utilizza 2 rami per la parità quindi permette il guasto simultaneo fino a 2 nodi
Come prima, detto N il numero di nodi, e D la dimensione del ramo più piccolo, la capacità dell’array sarà dell’ ordine di ( N – 2 ) * D
Se prendiamo l’esempio del livello 4 con 4 dischi e creiamo un array di livello 6, vediamo che la capacità totale scende a circa 200 MB, ma possiamo perdere fino a 2 dischi senza perdere i dati contenuti
1 2 3 4 |
# mdadm --create --verbose /dev/md0 \ --level=6 \ --raid-devices=4 \ /dev/ubdb /dev/ubdc /dev/ubdd /dev/ubde |
( 4 – 2 ) * 100MB = 200 MB ( circa )
1 2 3 |
# df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 192M 1.6M 181M 1% /mnt/raid |
RAID 10 ( mirrored striping )
Anche detto raid 1+0 è una combinazione dei due livelli, dove ogni blocco dati viene duplicato un certo numero di volte e distribuito sui diversi rami
Avendo i blocchi dati e di mirror distribuiti su tutti i nodi dell’array, questa configurazione è molto performante sia in lettura che in scrittura ed è particolarmente indicata nello storage dei database
1 2 3 4 |
# mdadm --create --verbose /dev/md0 \ --level=10 \ --raid-devices=4 \ /dev/ubdb /dev/ubdc /dev/ubdd /dev/ubde |
Dopo aver montato il raid con uno dei dischi da 100 MB vediamo come si presenta e lo spazio disponibile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# mdadm --detail /dev/md0 /dev/md0: Version : 1.2 Creation Time : Thu Mar 7 16:05:48 2019 Raid Level : raid10 Array Size : 202752 (198.00 MiB 207.62 MB) Used Dev Size : 101376 (99.00 MiB 103.81 MB) Raid Devices : 4 Total Devices : 4 Persistence : Superblock is persistent Update Time : Thu Mar 7 16:06:41 2019 State : clean Active Devices : 4 Working Devices : 4 Failed Devices : 0 Spare Devices : 0 Layout : near=2 Chunk Size : 512K Name : uml-base:0 (local to host uml-base) UUID : a32e357e:678256e9:0c517078:5a7cb46d Events : 17 Number Major Minor RaidDevice State 0 98 16 0 active sync set-A /dev/ubdb 1 98 32 1 active sync set-B /dev/ubdc 2 98 48 2 active sync set-A /dev/ubdd 3 98 64 3 active sync set-B /dev/ubde # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 192M 1.6M 181M 1% /mnt/raid |
Se invece utilizziamo i 4 dischi da 200MB
1 2 3 4 |
# mdadm --create --verbose /dev/md0 \ --level=10 \ --raid-devices=4 \ dev/ubdc /dev/ubdd /dev/ubde /dev/ubdf |
Dopo aver montato il raid con uno dei dischi da 100 MB vediamo come si presenta e lo spazio disponibile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# mdadm --detail /dev/md0 /dev/md0: Version : 1.2 Creation Time : Thu Mar 7 16:28:11 2019 Raid Level : raid10 Array Size : 407552 (398.00 MiB 417.33 MB) Used Dev Size : 203776 (199.00 MiB 208.67 MB) Raid Devices : 4 Total Devices : 4 Persistence : Superblock is persistent Update Time : Thu Mar 7 16:28:11 2019 State : clean, resyncing Active Devices : 4 Working Devices : 4 Failed Devices : 0 Spare Devices : 0 Layout : near=2 Chunk Size : 512K Resync Status : 8% complete Name : uml-base:0 (local to host uml-base) UUID : 96c71cf1:c8f779be:54de6776:1709799d Events : 1 Number Major Minor RaidDevice State 0 98 32 0 active sync set-A /dev/ubdc 1 98 48 1 active sync set-B /dev/ubdd 2 98 64 2 active sync set-A /dev/ubde 3 98 80 3 active sync set-B /dev/ubdf # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 386M 2.3M 364M 1% /mnt/raid |
Configurazioni ibride
Montando assieme raid diversi, possiamo creare diverse configurazioni in modo da sfruttare tutte le caratteristiche dei vari livelli raid. La più banale che si può implementare è il raid 10, combinando due raid 1 ed un raid 0. Per farlo utilizziamo i due device /dev/md1 e /dev/md2 creati all’inizio
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# mdadm --create --verbose /dev/md1 \ --level=1 \ --raid-devices=2 \ /dev/ubdc /dev/ubdd # mdadm --create --verbose /dev/md2 \ --level=1 \ --raid-devices=2 \ /dev/ubde /dev/ubdf # mdadm --create --verbose /dev/md0 \ --level=0 \ --raid-devices=2 \ /dev/md1 /dev/md2 |
La situazione è identica a quella mostrata per il raid 10, solo che l’array viene gestito con un totale di 3 raid, uno per lo striping e due per il mirroring in cui è contenuto un disco mirror per ciascun ramo
1 2 3 4 5 6 7 8 9 10 11 12 |
# mdadm /dev/md1 /dev/md1: 199.81MiB raid1 2 devices, 0 spares. Use mdadm --detail for more detail. /dev/md1: device 0 in 2 device active raid0 /dev/md0. Use mdadm --examine for more detail. # mdadm /dev/md2 /dev/md2: 199.81MiB raid1 2 devices, 0 spares. Use mdadm --detail for more detail. /dev/md2: device 1 in 2 device active raid0 /dev/md0. Use mdadm --examine for more detail. # mdadm /dev/md0 /dev/md0: 397.00MiB raid0 2 devices, 0 spares. Use mdadm --detail for more detail. # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 385M 2.3M 363M 1% /mnt/raid |
In questo modo possiamo anche creare configurazioni atipiche, ad esempio un raid 0 che fa striping su un raid 1 ed un raid 5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# mdadm --create --verbose /dev/md1 \ --level=1 \ --raid-devices=2 \ /dev/ubdb /dev/ubdc # mdadm --create --verbose /dev/md2 \ --level=5 \ --raid-devices=3 \ /dev/ubdd /dev/ubde /dev/ubdf # mdadm --create --verbose /dev/md0 \ --level=0 \ --raid-devices=2 \ /dev/md1 /dev/md2 |
Combina la capacità di 100 MB del raid 1 con un disco da 100 MB con quella da 400 MB del raid 5, i due rami hanno un disco di mirror ed un disco di parità
1 2 3 4 5 6 7 8 9 10 11 12 |
# mdadm /dev/md1 /dev/md1: 99.88MiB raid1 2 devices, 0 spares. Use mdadm --detail for more detail. /dev/md1: device 0 in 2 device active raid0 /dev/md0. Use mdadm --examine for more detail. # mdadm /dev/md2 /dev/md2: 398.00MiB raid5 3 devices, 0 spares. Use mdadm --detail for more detail. /dev/md2: device 1 in 2 device active raid0 /dev/md0. Use mdadm --examine for more detail. # mdadm /dev/md0 /dev/md0: 495.50MiB raid0 2 devices, 0 spares. Use mdadm --detail for more detail. # df -h /mnt/raid/ Filesystem Size Used Avail Use% Mounted on /dev/md0 480M 2.3M 453M 1% /mnt/raid |