Mise en place du RAID 5 Logiciel sous Linux 2.6

Afin de garantir la disponibilité de mes données sur mon serveur perso, j'ai décidé de me lancer dans la mise en place d'un volume de taille conséquente (1 tera octets) réparti sur 3 disques durs en RAID 5. Il est possible, pour ce type de volume, d'utiliser des cartes controlleurs parfaitement supportées sous Linux, mais faute de budget, et aussi car le RAID logiciel de Linux est tout à fait fiable, je n'ai pas retenu cette solution.

Un peu de théorie

Le RAID 5 associe le striping et un système à parité répartie, il permet une bonne disponibilité (même en cas de défaillance d'un des périphériques de stockage. Exemple pratique : soit trois disques durs de taille identique A, B et C. Le système va enregistrer sur les disques A et B les données (Strip) comme en mode RAID 0 et, sur le disque C, le résultat de l'opération ou-exclusif entre A et B (A xor B).

Fonction XOR

Ainsi, en cas de défaillance du disque A, les données qui y étaient accessibles le sont toujours avec les disques B et C, par l'opération B xor C (B xor C = A). Il en va de même pour le disque B. Et si le disque C tombe en panne, les informations sont toutes sur A et B.

Important : les disques doivent être de même taille. On ne stocke que sur les deux tiers de la place totale des disques (le dernier tiers étant la parité). .

L'architecture est simple : un serveur sous Debian avec un noyau 2.6.26-1-686 SMP, 2 disques durs Western Digital 640GB et un disque dur Western Digital 500GB.

Sur les 3 disques, je vais créer des partitions de tailles égales : 255 heads, 63 sectors/track (512 bytes per sector), 60801 cylinders qui vont êtres reliées entre elles par mdadm pour obtenir un volume logique, sur lequel le système de fichier sera créé.

Formatage des partitions

fdisk permet de créer des partitions de tailles égales. Sur chacun des disques, il faut effacer les partitions existantes et en créer une nouvelle de taille voulue, disons 500GB ou 60801 cylindres dans mon cas.

Pour info : un disque est généralement constitué de secteurs de 
512 octets. Dans mon cas, un disque possède 255 têtes (heads), 
63 secteurs (sectors) de 512 octets et 60801 cylindres. Lorsque 
l'on multiplie le tout, on obtiens la taille du disque en octets :
255*63*512*60801 = 500105249280 octets, soit 465 gigaoctets.

Donc, sur les disques, ont crée des partitions de 60801 cylindres (commande « n ») auquelles on donne le type « fd » (commande « t ») qui correspond à Linux Raid Autodetect. Enfin, on écris cela sur le disque et on quitte (commande « w »)

Disk /dev/sdc: 640.1 GB, 640135028736 bytes
255 heads, 63 sectors/track, 77825 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x5956f77c

   Device Boot      Start         End      Blocks   Id  System

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-77825, default 1): 1
Last cylinder or +size or +sizeM or +sizeK (1-77825, default 77825): 60801

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): fd
Changed system type of partition 1 to fd (Linux raid autodetect)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

Création du RAID

mdadm doit être présent sur le système pour réaliser les opérations suivantes. Les partitions fraîchement formattées sont reliées dans un volume virtuel de type /dev/mdX (ou X varie de 0 à n selon le nombre de devices sur votre système).

On demande a mdadm de créer (–create) un device nommé /dev/md2 de niveau 5 (–level=5) qui contiendra 3 disques (–raid-devices). On précise également une taille de bloc (–chunk)par défaut de 64Ko et on donne un petit nom à notre volume, ce sera « teradata ». Enfin, on précise les noms des partitions, à savoir /dev/hda1, /dev/sdc1 et /dev/sdd1.

Un petit mot sur la Chunk Size : cela correspond a la taille des blocs que l'on va ventiler sur les disques. Dans notre cas, il y a 3 disques D1, D2 et D3. Si l'on considère une chunk size de 64Ko et que l'on souhaite écrire 256Ko de données, on va avoir :

--> bloc #1 de 128Ko 
découpage en 2 blocs de 64 Ko
stockage du bloc 1 sur D1, stockage du bloc 2 sur D2, stockage du XOR de bloc 1 et bloc 2 sur D3
--> bloc #2 de 128Ko 
découpage en 2 blocs de 64 Ko
stockage du bloc 1 sur D2, stockage du bloc 2 sur D3, stockage du XOR de bloc 1 et bloc 2 sur D1

Par contre, si l'on souhaite écrire moins de 64 Ko de données, on se retrouve quand même à devoir utiliser cette espace sur les 3 disques. Il faut donc bien évaluer la chunk size en fonction de l'utilisation du volume RAID. Ici, je souhaite stocker des fichiers de grandes tailles (photos, videos, …) donc une taille de 64Ko est un bon compromis.

C'est parti pour la création :

# mdadm --create --verbose /dev/md2 --level=5 --raid-devices=3 --chunk=64 --name="teradata" /dev/hda1 /dev/sd[cd]1
mdadm: layout defaults to left-symmetric
mdadm: size set to 488383936K
mdadm: array /dev/md2 started.

On peut vérifier l'état du volume nouvellement créé :

# cat /proc/mdstat

md2 : active (auto-read-only) raid5 sdd1[3](S) sdc1[1] hda1[0]
      976767872 blocks level 5, 64k chunk, algorithm 2 [3/2] [UU_]

Ou en détail :

# mdadm --detail /dev/md2
/dev/md2:
        Version : 00.90
  Creation Time : Sat Feb  7 22:03:34 2009
     Raid Level : raid5
     Array Size : 976767872 (931.52 GiB 1000.21 GB)
  Used Dev Size : 488383936 (465.76 GiB 500.11 GB)
   Raid Devices : 3
  Total Devices : 3
Preferred Minor : 2
    Persistence : Superblock is persistent

    Update Time : Sat Feb  7 22:03:34 2009
          State : clean, degraded
 Active Devices : 2
Working Devices : 3
 Failed Devices : 0
  Spare Devices : 1

         Layout : left-symmetric
     Chunk Size : 64K

           UUID : ba111286:ca1a6ce5:f890ba8d:d38797f9 (local to host zerhuel)
         Events : 0.1

    Number   Major   Minor   RaidDevice State
       0       3        1        0      active sync   /dev/hda1
       1       8       33        1      active sync   /dev/sdc1
       2       0        0        2      removed

       3       8       49        -      spare   /dev/sdd1

Apparemment, /dev/sdd1 est reconnu en spare. C'est relativement étrange, et je n'ai pas trouvé de raison à ce problème… Par contre, je l'ai corrigé assez facilement en enlevant puis en remettant la partition dans le volume :

# mdadm /dev/md2 -r /dev/sdd1
mdadm: hot removed /dev/sdd1

# cat /proc/mdstat

md2 : active raid5 sdc1[1] hda1[0]
      976767872 blocks level 5, 64k chunk, algorithm 2 [3/2] [UU_]

# mdadm /dev/md2 -a /dev/sdd1
mdadm: re-added /dev/sdd1

# cat /proc/mdstat

md2 : active raid5 sdd1[3] sdc1[1] hda1[0]
      976767872 blocks level 5, 64k chunk, algorithm 2 [3/2] [UU_]
      [>....................]  recovery =  0.0% (115968/488383936) finish=70.1min speed=115968K/sec

Une fois la construction démarrée, on peut suivre son évolution dans /proc/mdstat ou via mdadm :

# mdadm --detail /dev/md2
/dev/md2:
        Version : 00.90
  Creation Time : Sat Feb  7 22:03:34 2009
     Raid Level : raid5
     Array Size : 976767872 (931.52 GiB 1000.21 GB)
  Used Dev Size : 488383936 (465.76 GiB 500.11 GB)
   Raid Devices : 3
  Total Devices : 3
Preferred Minor : 2
    Persistence : Superblock is persistent

    Update Time : Sat Feb  7 22:14:24 2009
          State : clean, degraded, recovering
 Active Devices : 2
Working Devices : 3
 Failed Devices : 0
  Spare Devices : 1

         Layout : left-symmetric
     Chunk Size : 64K

 Rebuild Status : 1% complete

           UUID : ba111286:ca1a6ce5:f890ba8d:d38797f9 (local to host zerhuel)
         Events : 0.4

    Number   Major   Minor   RaidDevice State
       0       3        1        0      active sync   /dev/hda1
       1       8       33        1      active sync   /dev/sdc1
       3       8       49        2      spare rebuilding   /dev/sdd1

Ca prend du temps…..

Le File System

Question existencielle : Que choisir ???? Du reiserfs ? Non, je vais plutôt y mettre de gros fichiers. JFS alors ? Pas confiance, je sais pas pourquoi, une mauvaise expérience par le passé… Reste XFS, ext3 et le très tentant mais jeune ext4… Je ne retiendrais pas ext4 pour deux raisons : la première c'est que le noyau de ma distrib est 2.6.26 et que ext4 a été intégré comme stable dans la 2.6.28, et la seconde c'est que je préfère ne pas trop jouer sur un serveur censé être fiable. Ext3 étant trop ancien, ce sera donc XFS, qui une fois optimisé devrait donner de bons résultats.

La lecture de [Optimisation XFS] donne quelques options de montages intéressantes. Pour plus d'infos, se reporter à la [XFS kernel doc].

La création et le montage de la partition se font de la façon suivante (il faut disposer des « xfsprogs »):

# mkfs.xfs -f -d su=64k,sw=2 -l lazy-count=1,version=2 -i attr=2 /dev/md2
meta-data=/dev/md2               isize=256    agcount=32, agsize=7630992 blks
         =                       sectsz=4096  attr=2
data     =                       bsize=4096   blocks=244191744, imaxpct=25
         =                       sunit=16     swidth=32 blks
naming   =version 2              bsize=4096
log      =internal log           bsize=4096   blocks=32768, version=2
         =                       sectsz=4096  sunit=1 blks, lazy-count=1
realtime =none                   extsz=131072 blocks=0, rtextents=0

Les options sont détaillées dans le man mkfs.xfs. On précise ici la chunk size et le nombre de volumes actifs (2) dans les options « su » et « sw ». Le lazy-count et la version concernent la journalisation, et l'on précise également la version des attr que l'on souhaite.

Parmi les options de montage XFS, on a :

95   logbsize=value
96         Set the size of each in-memory log buffer.
97         Size may be specified in bytes, or in kilobytes with a "k" suffix.
98         Valid sizes for version 1 and version 2 logs are 16384 (16k) and
99         32768 (32k).  Valid sizes for version 2 logs also include
100         65536 (64k), 131072 (128k) and 262144 (256k).
101         The default value for machines with more than 32MiB of memory
102         is 32768, machines with less memory use 16384 by default.

Celui la est positionné a la valeur la plus haute, la consommation mémoire n'est pas un problème.

119   noatime
120         Access timestamps are not updated when a file is read.

On gagne du temps lors de l'accès à un fichier.

84   logbufs=value
85         Set the number of in-memory log buffers.  Valid numbers range
86         from 2-8 inclusive.
87         The default value is 8 buffers for filesystems with a
88         blocksize of 64KiB, 4 buffers for filesystems with a blocksize
89         of 32KiB, 3 buffers for filesystems with a blocksize of 16KiB
90         and 2 buffers for all other configurations.  Increasing the
91         number of buffers may increase performance on some workloads
92         at the cost of the memory used for the additional log buffers
93         and their associated control structures.

On a un chunk size à 64Ko, on positionne donc 8 buffers de log.

157   sunit=value and swidth=value
158         Used to specify the stripe unit and width for a RAID device or
159         a stripe volume.  "value" must be specified in 512-byte block
160         units.
161         If this option is not specified and the filesystem was made on
162         a stripe volume or the stripe width or unit were specified for
163         the RAID device at mkfs time, then the mount system call will
164         restore the value from the superblock.  For filesystems that
165         are made directly on RAID devices, these options can be used
166         to override the information in the superblock if the underlying
167         disk layout changes after the filesystem has been created.
168         The "swidth" option is required if the "sunit" option has been
169         specified, and must be a multiple of the "sunit" value.

Il n'est pas vraiment nécessaire de renseigner ces valeurs, car XFS peut aller les chercher tout seul dans les superblocks des membres du RAID… Pour l'aspect pédagogique, ils sont ici renseignés afin de coller a la chunk size.

134   osyncisosync
135         Make O_SYNC writes implement true O_SYNC.  WITHOUT this option,
136         Linux XFS behaves as if an "osyncisdsync" option is used,
137         which will make writes to files opened with the O_SYNC flag set
138         behave as if the O_DSYNC flag had been used instead.
139         This can result in better performance without compromising
140         data safety.
141         However if this option is not in effect, timestamp updates from
142         O_SYNC writes can be lost if the system crashes.
143         If timestamp updates are critical, use the osyncisosync option.

Améliore le comportement synchrone/asynchrone de XFS pour améliorer les performances globales.

Au final, la ligne dans /etc/fstab est la suivante :

# grep xfs /etc/fstab
/dev/md2        /data/teradata  xfs     noatime,nodiratime,logbufs=8,logbsize=262144,osyncisdsync       0       0

Quelques tests

hdparm permet de faire des tests de base. Tout d'abord, sur les disques membres du RAID :

# hdparm -tT /dev/sdc1

/dev/sdc1:
 Timing cached reads:   1758 MB in  2.00 seconds = 879.86 MB/sec
 Timing buffered disk reads:  310 MB in  3.02 seconds = 102.71 MB/sec

# hdparm -tT /dev/sdd1

/dev/sdd1:
 Timing cached reads:   1766 MB in  2.00 seconds = 883.56 MB/sec
 Timing buffered disk reads:  314 MB in  3.00 seconds = 104.54 MB/sec

# hdparm -tT /dev/hda1

/dev/hda1:
 Timing cached reads:   1734 MB in  2.00 seconds = 867.99 MB/sec
 Timing buffered disk reads:  228 MB in  3.00 seconds =  75.88 MB/sec

On a des perfs de cache similaires mais des différences entre les disques SATA plus récents (les 640GB) et le disque IDE de 500GB. Ca reste tout de même honorable, entre 75Mo/s pour l'IDE et 104Mo/s pour le SATA.

Maintenant concernant le volume :

# hdparm -tT /dev/md2

/dev/md2:
 Timing cached reads:   1728 MB in  2.00 seconds = 864.53 MB/sec
 Timing buffered disk reads:  452 MB in  3.00 seconds = 150.57 MB/sec

150Mo/s en lecture ! + 50% de gain grace au RAID5, c'est plutôt une bonne affaire.

Un petit test brutal pour regarder la vitesse d'écriture :

$ dd if=/dev/zero of=bigfile count=512K bs=64K
524288+0 enregistrements lus
524288+0 enregistrements écrits
34359738368 bytes (34 GB) copied, 310,462 s, 111 MB/s

111Mo/s… je suis satisfait !

Après, il faut regarder du coté de bonnie++ :

Bonnie++ benchmarks three things: data read and write speed, number of seeks 
that can be performed per second, and number of file metadata operations that 
can be performed per second. Metadata operations include file creation and 
deletion as well as getting metadata such as the file size or owner (the result 
of a fstat(2) call).
$ /usr/sbin/bonnie++ -d /data/teradata/foo/ -s 6G
Writing with putc()...done
Writing intelligently...done
Rewriting...done
Reading with getc()...done
Reading intelligently...done
start 'em...done...done...done...
Create files in sequential order...done.
Stat files in sequential order...done.
Delete files in sequential order...done.
Create files in random order...done.
Stat files in random order...done.
Delete files in random order...done.
Version 1.03d       ------Sequential Output------ --Sequential Input- --Random-
                    -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
zerhuel          6G 40584  94 120436  25 47101  14 47423  95 156913  22 400.2   1
                    ------Sequential Create------ --------Random Create--------
                    -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                 16  5959  31 +++++ +++  2927  15  5905  32 +++++ +++  3074  18
zerhuel,6G,40584,94,120436,25,47101,14,47423,95,156913,22,400.2,1,16,5959,31,+++++,+++,2927,15,5905,32,+++++,+++,3074,18

Pour interpréter les résultats, se reporter à cet article.

Misc

Sur mes 3 disques, j'en ai 2 de 640GB. Il me reste donc un peu de place à utiliser. Cette place va servir à un gros volume RAID 0 de 240GB pour stocker des données non importantes. Pour créer ce volume, il faut stopper /dev/md2, modifier les partitions avec fdisk, créer le RAID0 dans /dev/md3 et créer le système de fichiers. Puis, on redémarre /dev/md2.

Let's go:

# mdadm --stop /dev/md2
mdadm: stopped /dev/md2                          

# fdisk /dev/sdc       

[...]

   Device Boot      Start         End      Blocks   Id  System
/dev/sdc1               1       60801   488384001   fd  Linux raid autodetect
/dev/sdc2           60802       77825   136745280   fd  Linux raid autodetect

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.                             
root@zerhuel:/home/julien/# fdisk /dev/sdd

[...]

   Device Boot      Start         End      Blocks   Id  System
/dev/sdd1               1       60801   488384001   fd  Linux raid autodetect
/dev/sdd2           60802       77825   136745280   fd  Linux raid autodetect

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.                             

# mdadm --create --verbose /dev/md3 --level=0 --raid-devices=2 --chunk=64 /dev/sd[cd]2
mdadm: array /dev/md3 started.   

# cat /proc/mdstat
Personalities : [raid1] [raid6] [raid5] [raid4] [raid0]
md3 : active raid0 sdd2[1] sdc2[0]
      273490432 blocks 64k chunks

md1 : active raid1 sda3[0] sdb3[1]
      97683136 blocks [2/2] [UU]

md0 : active raid1 sda1[0] sdb1[1]
      18554944 blocks [2/2] [UU]

unused devices: <none>
root@zerhuel:/home/julien/# mdadm --detail /dev/md3
/dev/md3:
        Version : 00.90
  Creation Time : Sun Feb  8 10:54:50 2009
     Raid Level : raid0
     Array Size : 273490432 (260.82 GiB 280.05 GB)
   Raid Devices : 2
  Total Devices : 2
Preferred Minor : 3
    Persistence : Superblock is persistent

    Update Time : Sun Feb  8 10:54:50 2009
          State : clean
 Active Devices : 2
Working Devices : 2
 Failed Devices : 0
  Spare Devices : 0

     Chunk Size : 64K

           UUID : 774ba314:72323e5b:f890ba8d:d38797f9 (local to host zerhuel)
         Events : 0.1

    Number   Major   Minor   RaidDevice State
       0       8       34        0      active sync   /dev/sdc2
       1       8       50        1      active sync   /dev/sdd2

# mkfs.xfs -f -d su=64k,sw=2 -l lazy-count=1,version=2 -i attr=2 /dev/md3
meta-data=/dev/md3               isize=256    agcount=16, agsize=4273296 blks                      
         =                       sectsz=512   attr=2                                               
data     =                       bsize=4096   blocks=68372608, imaxpct=25                          
         =                       sunit=16     swidth=32 blks                                       
naming   =version 2              bsize=4096                                                        
log      =internal log           bsize=4096   blocks=32768, version=2                              
         =                       sectsz=512   sunit=16 blks, lazy-count=1                          
realtime =none                   extsz=131072 blocks=0, rtextents=0   

Un rapide test :

# hdparm -tT /dev/md3

/dev/md3:
 Timing cached reads:   1776 MB in  2.00 seconds = 888.17 MB/sec
 Timing buffered disk reads:  440 MB in  3.01 seconds = 146.29 MB/sec

Pas mal ! Reste plus qu'a redémarrer /dev/md2 et remonter les partitions. L'avantage des superblocks, c'est qu'il permettent à mdadm de retrouver les partitions tout seul en faisant un scan. Il suffit donc de lui dire :

# mdadm --assemble --scan
mdadm: /dev/md2 has been started with 3 drives.

Et on retrouve notre /dev/md2 :

# cat /proc/mdstat

[...]

md2 : active (auto-read-only) raid5 hda1[0] sdd1[2] sdc1[1]
      976767872 blocks level 5, 64k chunk, algorithm 2 [3/3] [UUU]

References :

Howto : http://tldp.org/HOWTO/Software-RAID-HOWTO-5.html

Benchmark : http://home.comcast.net/~jpiszcz/20080607/raid-benchmarks-decimal-fix-and-right-justified/disks.html

Chunk size : http://forums.storagereview.net/index.php?showtopic=26857

XFS kernel doc : http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs.txt;hb=HEAD

Optimisation XFS : http://www.mail-archive.com/linux-raid@vger.kernel.org/msg09204.html

Bonnie++ : http://www.linux.com/feature/139742

~~DISCUSSION~~

fr/ressources/dossiers/raid5_logiciel.txt · Last modified: 2011/03/16 01:41 (external edit)
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0