""" (0 0) ---oOO---(_)--------- | Software RAID 1 | | w Linuksie | --------------OOo---- |__|__| || || oOO OOo Poniższy artykuł ma na celu przedstawienie - krok po kroku - w jaki sposób skonfigurować i uruchomić prostą macierz dyskową w trybie RAID 1 na działającym już systemie operacyjnym Linux. Czym jest RAID 1? Jednym słowem: mirroring. W praktyce oznacza to równoległy zapis tych samych danych na dwóch oddzielnych dyskach. W przypadku awarii jednego z dysków system operacyjny może działać dalej korzystając z drugiego, sprawnego dysku. Dlaczego akurat Software RAID? O wyborze programowego rozwiązania decyduje przede wszystkim cena. Nie musimy inwestować pieniędzy w drogi, sprzętowy kontroler macierzy dyskowych. Ponadto większość "tanich i dobrych" kontrolerów często wymaga dodatkowych sterowników, które nie zawsze lubią współpracować z Linuksem. No i też nie jest to rozwiązanie w pełni sprzętowe. Platforma testowa: Na potrzeby tego artykułu uruchomiona została macierz składająca się z dwóch dysków 120 GB (Maxtor 6Y120P0), działająca pod kontrolą dystrybucji Slackware Linux (gałąź -current, jądro w wersji 2.6.26.3-grsec). Każdy z dysków podłączony jest do innego kanału ATA, co wpływa na większą wydajność macierzy. Co do wyboru dysków zazwyczaj zaleca się tworzenie macierzy na dwóch identycznych dyskach, jednak nie ma większych przeszkód przy stworzeniu takiej macierzy na dyskach różnej pojemności. Wpływa to nieco na wydajność z racji różniących się parametrów. W przypadku różnych dysków musimy zadbać o dwie rzeczy: 1. Dysk, na którym aktualnie działa system operacyjny musi być mniejszy od dysku, na którym będziemy konfigurować macierz. 2. Na obydwu dyskach musimy zadbać o taką samą adresację (dotyczy także identycznych dysków). Metodę adresacji wybiera się w BIOSie. W przypadku jakichkolwiek problemów można też użyć fdiska. # fdisk -l /dev/hda | grep heads 255 heads, 63 sectors/track, 14946 cylinders # fdisk -l /dev/hdc | grep heads 255 heads, 63 sectors/track, 14946 cylinders Jest to przykład dla dwóch identycznych dysków. W tym przypadku wszystkie wartości są te same. # fdisk -l /dev/hda | grep heads 255 heads, 63 sectors/track, 9729 cylinders # fdisk -l /dev/hdc | grep heads 255 heads, 63 sectors/track, 14946 cylinders A to przykład użycia dwóch różnych dysków. Wartości, które muszą być identyczne to liczba głowic (heads) oraz liczba sektorów na ścieżkę (sectors/track). Liczba cylindrów jest różna z powodu różnych pojemności (hda to 80 GB, hdc 120 GB). Adresacja jest o tyle ważna, gdyż przy tworzeniu partycji programy takie jak fdisk czy cfdisk zaokrąglają rozmiary partycji. W przypadku tej samej adresacji nie ma ryzyka, że np. partycja 20 GB na jednym dysku będzie o 500 kB mniejsza od tej na drugim. Przejdźmy więc do właściwej konfiguracji. Podstawowa kwestia to odpowiednie opcje wkompilowane w jądro, a więc wybieramy: Device Drivers ---> [*] Multiple devices driver support (RAID and LVM) ---> <*> RAID support <*> RAID-1 (mirroring) mode Nie będę opisywał samej rekompilacji jądra. Pomijam także zabawę z initrd, dlatego sterownik wkompilujemy w jądro. Dysk, na którym zainstalowany jest mój system ma taką strukturę: # fdisk -l /dev/hda Disk /dev/hda: 122.9 GB, 122942324736 bytes 255 heads, 63 sectors/track, 14946 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/hda1 1 524 4208998+ 83 Linux # / /dev/hda2 525 14946 115844715 5 Extended /dev/hda5 525 907 3076416 83 Linux # /tmp /dev/hda6 908 1290 3076416 83 Linux # /var /dev/hda7 1291 2183 7172991 83 Linux # /usr /dev/hda8 2184 14831 101595028+ 83 Linux # /home /dev/hda9 14832 14946 923706 82 Linux swap Pierwsze co musimy zrobić to stworzyć na drugim dysku takie same partycje, zmieniając ich typ na Linux raid autodetect. Efekt końcowy wygląda tak: # fdisk -l /dev/hdc Disk /dev/hdc: 122.9 GB, 122942324736 bytes 255 heads, 63 sectors/track, 14946 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/hdc1 1 524 4208998+ fd Linux raid autodetect /dev/hdc2 525 14946 115844715 5 Extended /dev/hdc5 525 907 3076416 fd Linux raid autodetect /dev/hdc6 908 1290 3076416 fd Linux raid autodetect /dev/hdc7 1291 2183 7172991 fd Linux raid autodetect /dev/hdc8 2184 14831 101595028+ fd Linux raid autodetect /dev/hdc9 14832 14946 923706 fd Linux raid autodetect Oznaczenia partycji Extended nie zmieniamy. Jest ona informacją o istnieniu dysków logicznych. Kolejny krok to stworzenie macierzy: # mdadm -C /dev/md0 -l 1 -n 2 missing /dev/hdc1 Tworzymy w ten sposób macierz /dev/md0 pierwszego poziomu (RAID 1), składającą się z dwóch dysków. Na początku konfigurujemy w niej tylko partycję nowego dysku (hdc1), ponieważ hda1 jest używana przez nas system (oznaczamy ją jako missing). Czynność powtarzamy dla pozostałych partycji: # mdadm -C /dev/md1 -l 1 -n 2 missing /dev/hdc5 # mdadm -C /dev/md2 -l 1 -n 2 missing /dev/hdc6 # mdadm -C /dev/md3 -l 1 -n 2 missing /dev/hdc7 # mdadm -C /dev/md4 -l 1 -n 2 missing /dev/hdc8 # mdadm -C /dev/md5 -l 1 -n 2 missing /dev/hdc9 Nowe partycje musimy sformatować (oczywiście wybór systemu plików wedle upodobań, ja używam ext3): # mkfs.ext3 /dev/md0 # mkfs.ext3 /dev/md1 # mkfs.ext3 /dev/md2 # mkfs.ext3 /dev/md3 # mkfs.ext3 /dev/md4 # mkswap /dev/md5 Tworzymy katalogi, pod które będziemy montować partycje oraz /dev, /proc, /sys: # mkdir -p /raid/{tmp,var,usr,home,dev,proc,sys} # chmod 555 /raid/proc Montujemy je: # mount /dev/md0 /raid # mount /dev/md1 /raid/tmp # mount /dev/md2 /raid/var # mount /dev/md3 /raid/usr # mount /dev/md4 /raid/home Czas na przekopiowanie naszego systemu na nowy dysk. Możemy użyć do tego celu rsync: # rsync -auH --progress --stats --exclude=/raid --exclude=/dev \ --exclude=/proc --exclude=/sys / /raid Na nowym dysku trzeba jeszcze przeprowadzić kilka modyfikacji. Pierwsza to dopisanie macierzy do pliku konfiguracyjnego mdadm. Edytujemy więc /raid/etc/mdadm.conf i dopisujemy do niego linię: DEVICE /dev/hda[156789] /dev/hdc[156789] Tajemnicze cyfry w nawiasach to oznaczenia kolejnych dysków (hda1, hda5, itd.). Musimy także umieścić informacje o poszczególnych partycjach macierzy. Dane te wygeneruje nam mdadm: # mdadm --detail --scan >> /raid/etc/mdadm.conf Kolejną modyfikacją jest zmiana wpisów w fstab. Edytujemy więc /raid/etc/fstab i zamieniamy oznaczenia starych partycji na nowe (hda1 na md0, hda5 na md1, itd.): /dev/md5 swap swap defaults 0 0 /dev/md0 / ext3 defaults 1 1 /dev/md1 /tmp ext3 defaults 1 2 /dev/md2 /var ext3 defaults 1 2 /dev/md3 /usr ext3 defaults 1 2 /dev/md4 /home ext3 defaults,usrquota 1 2 Ostatnia zmiana to LILO. Nowy wpis w /raid/etc/lilo.conf powinien wyglądać następująco: image = /boot/bzImage-2.6.26.3 root = /dev/md0 label = Linux-RAID read-only Można oczywiście zostawić także stary wpis na wypadek jakiegoś niepowodzenia: image = /boot/bzImage-2.6.26.3 root = /dev/hda1 label = Linux-Normal read-only Oczywiście w przypadku GRUB-a zmiany są analogiczne. Instalujemy nowe LILO: # lilo -C /raid/etc/lilo.conf Taka konfiguracja pozwoli nam na uruchomienie systemu z obsługą macierzy bez potrzeby zmiany kolejności bootowania dysków w BIOS-ie (LILO zainstaluje się w MBR dysku /dev/hda), a w razie problemów uruchomienie systemu bez RAIDa. Nadszedł więc czas zrestartowania systemu. Wybieramy oczywiście jądro Linux-RAID. Po uruchomieniu systemu sprawdźmy czy RAID rzeczywiście działa: # df -h Filesystem Size Used Avail Use% Mounted on /dev/root 4.0G 701M 3.1G 19% / /dev/md/1 2.9G 173M 2.6G 7% /tmp /dev/md/2 2.9G 297M 2.5G 11% /var /dev/md/3 6.8G 2.0G 4.5G 32% /usr /dev/md/4 96G 46G 45G 51% /home Wygląda w porządku. Jeszcze szybki rzut oka na status naszego RAID-a: # cat /proc/mdstat Personalities : [raid1] md0 : active raid1 hdc1[1] 4208896 blocks [2/1] [_U] md1 : active raid1 hdc5[1] 3076352 blocks [2/1] [_U] md2 : active raid1 hdc6[1] 3076352 blocks [2/1] [_U] md3 : active raid1 hdc7[1] 7172864 blocks [2/1] [_U] md4 : active raid1 hdc8[1] 101594944 blocks [2/1] [_U] md5 : active raid1 hdc9[1] 923584 blocks [2/1] [_U] Jak widać aktualnie w naszej macierzy działa jeden dysk. U (up) oznacza dysk działający. _ to dysk niepodłączony. Dodajmy więc pierwszy dysk do macierzy. Tu także musimy zmienić Id partycji na Linux raid autodetect: # fdisk -l /dev/hda Disk /dev/hda: 122.9 GB, 122942324736 bytes 255 heads, 63 sectors/track, 14946 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/hda1 1 524 4208998+ fd Linux raid autodetect /dev/hda2 525 14946 115844715 5 Extended /dev/hda5 525 907 3076416 fd Linux raid autodetect /dev/hda6 908 1290 3076416 fd Linux raid autodetect /dev/hda7 1291 2183 7172991 fd Linux raid autodetect /dev/hda8 2184 14831 101595028+ fd Linux raid autodetect /dev/hda9 14832 14946 923706 fd Linux raid autodetect Ostatni krok to dodanie nowych partycji do naszej macierzy. Wpisujemy więc kolejno: # mdadm /dev/md0 -a /dev/hda1 # mdadm /dev/md1 -a /dev/hda5 # mdadm /dev/md2 -a /dev/hda6 # mdadm /dev/md3 -a /dev/hda7 # mdadm /dev/md4 -a /dev/hda8 # mdadm /dev/md5 -a /dev/hda9 Po czym możemy obserwować jak RAID automatycznie kopiuje dane na nowy dysk: # watch -n 0.1 cat /proc/mdstat Every 0.1s: cat /proc/mdstat Wed Sep 3 18:35:46 2008 Personalities : [raid1] md0 : active raid1 hda1[0] hdc1[1] 4208896 blocks [2/2] [UU] md1 : active raid1 hda5[0] hdc5[1] 3076352 blocks [2/2] [UU] md2 : active raid1 hda6[0] hdc6[1] 3076352 blocks [2/2] [UU] md3 : active raid1 hda7[0] hdc7[1] 7172864 blocks [2/1] [_U] resync=DELAYED md4 : active raid1 hda8[0] hdc8[1] 101594944 blocks [2/1] [_U] [====>................] recovery = 20.2% (20581248/101594944) finish=69.4min speed=19430K/sec md5 : active raid1 hda9[0] hdc9[0] 923584 blocks [2/2] [UU] unused devices: Proces kopiowania danych może oczywiście zająć kilka godzin, w zależności od rozmiaru dysków. Po zakończeniu kopiowania warto zainstalować LILO na obydwu dyskach (możemy już skasować stary wpis dotyczący /dev/hda1) oraz ustawić ich bootowanie kolejno po sobie w BIOSie. W razie awarii któregoś z dysków, gdy będziemy restartować system, drugi dysk automatycznie podejmie pracę. Pozwoliłem sobie także napisać niewielki skrypt CGI, który w przejrzysty sposób wyświetla status naszej macierzy: --- cut here --- #!/bin/sh function print() { i=1 while [ $i -le `grep -o 'md[0-9]*' /proc/mdstat | wc -l` ]; do if [ `grep -o '\[..\]' /proc/mdstat | head -$i | tail -1 | \ head -c$1 | tail -c1` == "U" ]; then echo "[ up ]" else echo "[ down ]" fi ((i++)) done } echo -e "Content-type: text/html\n" echo "" echo "" echo -e "" echo "mdstat - RAID 1 - $HOSTNAME" echo -e "\n\n" if [ ! -e /proc/mdstat ]; then echo "
/proc/mdstat doesn't exist...
" else echo "" echo -e "\n\n\n\n" echo -e "" echo -e "" echo -e "" echo "\n\n
device#0#1status \ #0status #1
\n`grep -o 'md[0-9]*' /proc/mdstat`\n
\n`grep -o '[a-z0-9]*\[0\]' /proc/mdstat | \
sed 's/\[0\]//'`\n
\n`grep -o '[a-z0-9]*\[1\]' /proc/mdstat | \
sed 's/\[1\]//'`\n
"
  if [ `grep -o '\[[0-9]\]' /proc/mdstat | head -c3` == "[0]" ]; then
    print 2
  else
    print 3
  fi
  echo -e "
"
  if [ `grep -o '\[[0-9]\]' /proc/mdstat | head -c3` == "[1]" ]; then
    print 2
  else
    print 3
  fi
  echo -e "
\n
" fi echo -e "\n" --- cut here --- Tym oto akcentem temat Software RAID 1 można uznać za wyczerpany. Wszelkie sugestie i uwagi odnośnie tego artykułu będą mile widziane. W razie pytań proszę o kontakt e-mailowy. Adres e-mail podany jest na mojej stronie. -- 03.09.2008 Copyright 2008 Damian Pasternok http://www.pasternok.org/