Difficile de faire plus court en titre…
Je vous préviens tout de suite, ce billet risque d’être un peu long car après tout, j’ai passé du temps dessus, autant que vous en passiez, vous aussi, a me lire 🙂
Tous ceux qui ont déjà eu à mettre en oeuvre une quelconque solution de Haute-Disponibilité, se sont retrouvés un jour devant une problématique assez angoissante :
L’accès simultané (ou concurrent) à une ressource de données.
Si en lecture cela pose rarement des problèmes, en écriture, cela comment à devenir « légèrement » complexe.
Petit exemple.
Vous avez deux serveurs load-balancés (web ou autre), si vous écrivez une information sur le premier serveur, comment être sur qu’elle soit disponible sur le deuxième, et vice-versa.
Après tout, je peux aussi bien écrire sur le serveur A que sur le serveur B.
Retour en arrière donc pour vous expliquer la progression de mon raisonnement et la solution que j’ai mise en oeuvre.
Lorsque l’on désire avoir une synchronisation parfaite des données entre deux serveurs, la première méthode est d’utiliser un mode Actif/Passif (ou maître/esclave).
Le moyen le plus simple est de se baser sur DRBD dont j’avais déjà abordé le sujet ICI qui est une sorte de RAID Over IP.
La mise en place de drbd vous donne un nouveau périphérique de stockage (ou nouveau disque pour simplifier) de type /dev/drbdX.
En cas de panne du Maître, le service est basculé sur l’Esclave et les données accessibles par celui ci.
Le volume DRBD, appelé par exemple /dev/drbd0 est alors « monté » en système de fichier sur la machine passive qui devient alors, active.
Je parle bien entendu de synchronisation en mode « bloc », pas d’une synchronisation de fichiers comme le fait rsync ou autre.
Dans cet exemple, le système de fichier reste standard (ext2, ext3, reiser etc…).
Si maintenant vous avez décidé de mettre en oeuvre un loadbalancing suite à la lecture de cet excellent billet 😉 , les choses se compliquent.
En effet, nous nous trouvons dans un cas de figure où les deux serveurs sont Maîtres, donc Actif.
Heureusement, depuis la version 0.8 de DRBD, les deux noeuds peuvent être « Primary ».
(nb. : la version 0.9 devrait apporter le support de plus de 2 noeuds)
Par contre, pour pouvoir utiliser ses deux noeuds en mode Primaire, il faut un système de fichier « distribué » (vous trouverez souvent le terme « shared disk file system »).
Il en existe peu et les principaux sont GFS et OCFS2.
Le premier est issu de RedHat et le second d’Oracle. Sachez que le support de ses deux systèmes de fichiers est inclus dans les noyaux Linux récents.
J’ai testé les deux quelques temps et suite à mon retour personnel d’expérience et les discussions avec d’autres « geeks » ayant joué avec les deux, j’ai une nette préférence pour OCFS2. La suite de ce billet se basera donc sur ce système de fichier.
(je vous laisse bien sûr à vos propres expériences et recherches, si vous préférez GFS ou Lustre, je ne vous jetterai pas de pierres 😀 )
Une fois mise en place, nous nous retrouvons donc avec ce type d’architecture :
La, on commence à être « poilu » non ?
Oui, MAIS, cette architecture est valable uniquement si on utilise les ressources locales des 2 serveurs (i.e. leurs disques durs).
Si je ne veux pas utiliser les disques durs de mes serveurs mais les disques d’un autre groupe de serveurs dédiés a cela ? Comment je fais ? HEIN ! Comment ???
Du calme, jeune Padawan, tu sais bien que Guiguiabloc est… à bloc…
Nous allons utiliser un SAN pour connecter nos disques distants à nos serveurs.
Un SAN !?! Mais j’ai pas de sous moi !!!
Allons, jeune Youngling, tu n’auras nul besoin de casser ton petit cochon qui te sert de tirelire, nous allons utiliser le protocole Iscsi.
L’ISCSI est du SCSI sur TCP/IP, nous allons connecter via ce protocole nos disques distants sur nos serveurs qui les verront comme s’il s’agissait de disques locaux.
(j’avais déjà abordé le sujet dans ce billet)
De plus en plus « poilu »… Mais pas encore assez. Poussons le bouchon un peu plus loin (hein Maurice ?) , je veux bien sûr de la redondance sur mes connexions Iscsi.
Et comment je fais de la haute disponibilité sur des iniatiators Iscsi ???
En utilisant un Device Mapper Multipath.
Bien sûr là vous vous dites : Guiguiabloc est fou/malade/a bloc/allumé (rayez les mentions inutiles) , et je vous répondrais… oui.
Schématisons le bouzin :
C’est beau hein ? 🙂
Après la théorie, passons à la phase la plus dure, la pratique.
- DRBD
Récuperer les souces :
http://oss.linbit.com/drbd/8.3/drbd-8.3.0.tar.gz
tar xzvf drbd-8.3.0.tar.gz cd drbd-8.3.0 cd drbd make cd .. make tools make install make install-tools |
Edition du fichier /etc/drbd.conf (bien sur, remplacer les valeurs par les votres)
#/etc/drbd.conf global { usage-count yes; } resource r0 { protocol C; startup { become-primary-on both; } disk { on-io-error detach; } net { allow-two-primaries; after-sb-0pri discard-least-changes; after-sb-1pri violently-as0p; after-sb-2pri violently-as0p; rr-conflict violently; } syncer { rate 44M; } on DISK-GUIGUIABLOC-A { # nom du serveur 1 device /dev/drbd0; disk /dev/sda4; # partition a prendre en compte address 192.168.30.1:7788; # adresse ip et port d'écoute meta-disk internal; } on DISK-GUIGUIABLOC-B { # nom du serveur 2 device /dev/drbd0; disk /dev/sda3; # partition a prendre en compte address 192.168.30.2:7788; # adresse ip et port d'écoute meta-disk internal; } } |
Sur chacun des noeuds :
drbdadm create-md r0 modprobe drbd drbdadm attach r0 drbdadm connect r0 Puis sur le noeud1 par exemple drbdadm -- --overwrite-data-of-peer primary r0 /etc/init.d/drbd start |
Vous suivez la synchro via un cat /proc/drbd
Je ne m’étends pas la dessus, j’en avais déjà parlé dans un autre billet.
- ISCSI Target Entreprise
Sur les deux « serveurs disques », on va installer un Target ISCSI.
(en terminologie ISCSI, on parle de Target pour la cible (soit la machine qui « offre » son disque) et d’Initiator pour la machine qui va se connecter au Target).
Je vous invite cet excellent article :
http://www.unixgarden.com/index.php/administration-reseau/le-support-du-protocole-iscsi-dans-linux
Nous allons utiliser les sources du projet iSCSI Entreprise Target , ici en version 0.4.17.
wget http://kent.dl.sourceforge.net/sourceforge/iscsitarget/iscsitarget-0.4.17.tar.gz tar xzvf iscsitarget-0.4.17.tar.gz cd iscsitarget-0.4.17 make make install |
On prépare son /etc/ietd.conf (volontairement simplifié a l’extrème).
Vous remarquerez que j’exporte via ISCSI le volume DRBD0.
Target iqn.2009-02.fr.guiguiabloc:disk-a.disk Lun 0 Path=/dev/drbd0,Type=blockio Alias disk |
On configure le fichier d’autorisation d’accès (comme les hosts.allow des wrappers tcp)
DISK-GUIGUIABLOC-a# cat /etc/initiators.allow iqn.2009-02.fr.guiguiabloc:disk-a.disk ALL |
Même chose sur le deuxième serveur (changer juste le nom du target).
on démarre /etc/init.d/iscsi-target start, et on vérifie
DISK-GUIGUIABLOC-a:/etc/iscsi/ifaces# /etc/init.d/iscsi-target status iSCSI enterprise target is running at pid 7715 DISK-GUIGUIABLOC-a:/etc/iscsi/ifaces# cat /proc/net/iet/volume tid:2 name:iqn.2009-02.fr.guiguiabloc:disk-a.disk lun:0 state:0 iotype:blockio iomode:wt path:/dev/drbd0 |
- Open-ISCSI
Sur nos deux serveurs srv-guiguiabloc-a et srv-guiguiabloc-b, nous allons installer l’Initiator (le client ISCSI si vous préférez).
Récupérons des sources sur le site http://www.open-iscsi.org/
wget http://www.open-iscsi.org/bits/open-iscsi-2.0-870.2.tar.gz tar xzvf open-iscsi-2.0-870.2.tar.gz make make install |
On donne un nom explicite à notre Initiator, puis on démarre le service.
srv-guiguiabloc-a:/etc/iscsi# cat initiatorname.iscsi InitiatorName=iqn.2009-02.fr.guiguiabloc:srvA srv-guiguiabloc-a:/etc/iscsi# /etc/init.d/open-iscsi start Starting iSCSI initiator service: iscsid. Setting up iSCSI targets:iscsiadm: No records found! |
Lançons une découverte du service
srv-guiguiabloc-a:/etc/iscsi# iscsiadm -m discovery -t sendtargets -p 192.168.30.1:3260 192.168.30.1:3260,1 iqn.2009-02.fr.guiguiabloc:disk-a.disk srv-guiguiabloc-a:/etc/iscsi# iscsiadm -m discovery -t sendtargets -p 192.168.30.2:3260 192.168.30.2:3260,1 iqn.2009-02.fr.guiguiabloc:disk-b.disk |
Un succès 😀
(Bien sûr vous reproduisez tout cela sur srv-guiguiabloc-b)
Maintenant, montons les sessions ISCSI sur nos deux Targets, sur nos deux serveurs
srv-guiguiabloc-a:~# iscsiadm -m node -T iqn.2009-02.fr.guiguiabloc:disk-a.disk -p 192.168.30.1 -l Login session [iface: default, target: iqn.2009-02.fr.guiguiabloc:disk-a.disk, portal: 192.168.30.1,3260] srv-guiguiabloc-a:~# iscsiadm -m node -T iqn.2009-02.fr.guiguiabloc:disk-b.disk -p 192.168.30.2 -l Login session [iface: default, target: iqn.2009-02.fr.guiguiabloc:disk-b.disk, portal: 192.168.30.2,3260] srv-guiguiabloc-b:~# iscsiadm -m node -T iqn.2009-02.fr.guiguiabloc:disk-a.disk -p 192.168.30.1 -l Login session [iface: default, target: iqn.2009-02.fr.guiguiabloc:disk-a.disk, portal: 192.168.30.1,3260] srv-guiguiabloc-b:~# iscsiadm -m node -T iiqn.2009-02.fr.guiguiabloc:disk-b.disk -p 192.168.30.2 -l Login session [iface: default, target: iiqn.2009-02.fr.guiguiabloc:disk-b.disk, portal: 192.168.30.2,3260] Vous devriez voir vos disques en local désormais : srv-guiguiabloc-a:~# cat /proc/scsi/scsi Attached devices: Host: scsi1 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: VIRTUAL-DISK Rev: 0 Type: Direct-Access ANSI SCSI revision: 04 Host: scsi2 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: VIRTUAL-DISK Rev: 0 Type: Direct-Access ANSI SCSI revision: 04 |
Pour l’inclure en démarrage automatique :
iscsiadm -m node -T iqn.2009-02.fr.guiguiabloc:disk-a.disk -p 192.168.30.1 -o update -n « node.conn[0].startup » -v automatic
(je vous laisse lire la documentation et/ou l’article sur Unix Garden.)
- Device Mapper MULTIPATH I/O
Nous allons utiliser une des couches du système Linux, le Device Mapper.
Son rôle est tout simplement de mapper un ou plusieurs périphériques de blocs sur un autre périphérique.
En fait, vous l’utilisez souvent sans peut-être le savoir avec LVM.
Vous trouverez un excellent billet la dessus sur : http://linux-attitude.fr/post/La-carte-du-peripherique
Et l’une des fonctions offertes par DM et le ISCSI, c’est le Multipath.
C’est à dire accéder à un périphérique par plusieurs chemins différents 🙂
Vous voyez ou je veux en venir ?….
Si notre Target A tombe, pas de soucis, srv-guiguiabloc-x passera par l’autre chemin, en l’occurrence le Target B, tout cela grâce au Multipath (pas celui LA hein 😉 )
(hi hi hi, désolé, il fallait que je la fasse)
Sur Debian : apt-get install multipath-tools
Editer votre fichier /etc/multipath.conf
blacklist { devnode "sda" # ici le disque local que j'exclue } defaults { user_friendly_names yes } srv-guiguiabloc-a:# /etc/init.d/multipath-tools restart srv-guiguiabloc-a:/dev/mapper# ll total 0 crw-rw---- 1 root root 10, 63 2009-02-14 19:57 control brw-rw---- 1 root disk 254, 0 2009-02-16 15:16 mpath0 brw-rw---- 1 root disk 254, 1 2009-02-16 15:16 mpath1 |
Vous voyez vos périphériques de blocs que vous pouvez utiliser comme n’importe quel autre.
En cas de déconnexion d’un Target, Multipath retirera le périphérique de la liste automatiquement.
(bien sûr, même punition pour srv-guiguiabloc-b).
- OCFS2
On arrive « enfin » au système de fichier proprement dit.
Sur les 2 srv-guiguiabloc :
apt-get install ocfs2-tools
On créer le répertoire /etc/ocfs2
On édite un fichier cluster.conf (identique sur les deux noeuds)
node: ip_port = 7777 ip_address = 192.168.30.1 number = 0 name = srv-guiguiabloc-a cluster = ocfs2 node: ip_port = 7777 ip_address = 192.168.30.2 number = 1 name = srv-guiguiabloc-b cluster = ocfs2 cluster: node_count = 2 name = ocfs2 |
Changer la valeur « O2CB_ENABLED=false » en « O2CB_ENABLED=true » dans /etc/default/o2cb
Démarrer le cluster :
srv-guiguiabloc-a:/etc/ocfs2# /etc/init.d/o2cb start Loading module "configfs": OK Mounting configfs filesystem at /sys/kernel/config: OK Loading module "ocfs2_nodemanager": OK Loading module "ocfs2_dlm": OK Loading module "ocfs2_dlmfs": OK Creating directory '/dlm': OK Mounting ocfs2_dlmfs filesystem at /dlm: OK Starting Oracle cluster ocfs2: OK |
Et on formate 😀
srv-guiguiabloc-a:/etc/ocfs2# mkdir /data srv-guiguiabloc-a:/etc/ocfs2# mkfs -t ocfs2 -L GUIGUIABLOCFS /dev/mapper/mpath0 mkfs.ocfs2 1.2.1 Filesystem label=GUIGUIABLOCFS Block size=4096 (bits=12) Cluster size=4096 (bits=12) Volume size=1439338496 (351401 clusters) (351401 blocks) 11 cluster groups (tail covers 28841 clusters, rest cover 32256 clusters) Journal size=67108864 Initial number of node slots: 4 Creating bitmaps: done Initializing superblock: done Writing system files: done Writing superblock: done Formatting Journals: done Writing lost+found: done mkfs.ocfs2 successful |
Et c’est tout !
N’essayer pas de formater /dev/mapper/mpath1, ou /dev/mapper/mpath0 sur srv-guiguiabloc-b, vous aurez ce message :
srv-guiguiabloc-a:/etc/ocfs2# mkfs -t ocfs2 -L GUIGUIABLOCFS /dev/mapper/mpath1 mkfs.ocfs2 1.2.1 Overwriting existing ocfs2 partition. Proceed (y/N): n Aborting operation. srv-guiguiabloc-b:/etc/ocfs2# mkfs -t ocfs2 -L GUIGUIABLOCFS /dev/mapper/mpath0 mkfs.ocfs2 1.2.1 Overwriting existing ocfs2 partition. Proceed (y/N): n Aborting operation. |
Ce qui prouve bien que notre volume est bien vu de srv-guiguiabloc-b, par le chemin /dev/mapper/mpath0 ou /dev/mapper/mpath1 😀
C’est pas magnifique tout cela ?
Et maintenant, le test final :
srv-guiguiabloc-a:/etc/ocfs2# mount /dev/mapper/mpath1 /data srv-guiguiabloc-a:/etc/ocfs2# mount /dev/sda1 on / type ext3 (rw,errors=remount-ro) tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755) proc on /proc type proc (rw,noexec,nosuid,nodev) sysfs on /sys type sysfs (rw,noexec,nosuid,nodev) udev on /dev type tmpfs (rw,mode=0755) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev) devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620) configfs on /sys/kernel/config type configfs (rw) ocfs2_dlmfs on /dlm type ocfs2_dlmfs (rw) /dev/mapper/mpath1 on /data type ocfs2 (rw,_netdev,heartbeat=local) srv-guiguiabloc-b:/etc/ocfs2# mount /dev/mapper/mpath0 /data srv-guiguiabloc-b:/etc/ocfs2# mount /dev/sda1 on / type ext3 (rw,errors=remount-ro) tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755) proc on /proc type proc (rw,noexec,nosuid,nodev) sysfs on /sys type sysfs (rw,noexec,nosuid,nodev) udev on /dev type tmpfs (rw,mode=0755) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev) devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620) configfs on /sys/kernel/config type configfs (rw) ocfs2_dlmfs on /dlm type ocfs2_dlmfs (rw) /dev/mapper/mpath0 on /data type ocfs2 (rw,_netdev,heartbeat=local) srv-guiguiabloc-a:/data# touch test srv-guiguiabloc-b:/data# ls test lost+found |
Vous pouvez vous amuser à écrire des deux côtés, couper un Target, vautrer un disque etc…
Après plusieurs essais intensifs, je vous avoue que j’ai été bluffé par le fonctionnement, que, je l’avoue, j’ai poussé à l’extrême.
Ne reste qu’à le greffer sur votre architecture « Altéonisée » que vous avez montée après la lecture de :
Ce qui nous donne un joli résultat au final :
Très « poilu », non ? 😀
Comme dirais mon pote `g0rt :
[17:53] <`g0rt> ca c’est de la redondance vindiousse
Bon courage dans le peaufinage de votre cluster 😉
ce que je ne comprends pas, c’est qu’est ce que fait un partionnement dans tes confs iscsi ?…
ou tu colles un /dev/sda non partitionné, ou une partition /dev/sda1. Relis mon exemple d’iscsi :
disk /dev/sda3; # partition a prendre en compte
😉
c’est peut-être quelque chose que je n’ai pas bien compris, mais normalement, avec multipath, on ne devrait avoir qu’un seul dev dans dev/mapper non?
en l’occurrence, c’est ce que j’ai. Et en plus, si je coupe la session de DISK1, le montage marche toujours et réciproquement pour DISK2.
une idée?
merci
y’a pas de partitionnement dans mes conf iscsi. Juste que quand je fais le login avec iscsiadm, le dmesg m’affiche deux nouveaux devices, sdc et sdd.
Là ça marche, la seule différence avec ton billet, c’est que je n’ai qu’un device dans /dev/mapper sur chaque serveur client (mpath0 sur srvA et mpath1 sur srvb) et pas mpath0 et mpath1 sur chauqe client. Par contre, chacun continue de fonctionner si l’un des iscsi target tombe.
Il n’y a qu’un seul dev dans /dev/mapper, dans mes exemples j’ai plusieurs targets pour les tests (expliqué plus haut dans les commmentaires).
ok, donc j’ai mal lu et tout va bien
merci
Bonjour,
Etant en entreprise sans but lucratif, je me suis tourné sur ce bloc afin d’implémenter ce schéma de fonctionnement. cela fait de 2 semaine que j’ai essayé de faire fonctionner cette infrastructure mais sans résultat. Nous travaillons avec ubuntu 10.10 64bits. dans notre infrastructure.
Je passe toute la partie drdb et iscsi target qui fonctionnent très bien la partie configuration de openiscsi et ocfs2 fonctionne bien aussi à l’initialisation. (montage et écriture marche nickel). Lors de mon premier test, je décide de couper un des targets qui sur les serveur correspond /dev/mapper/mpath0 ou mpath1 monté sur /data. je constate qu’après un court moment que le contrôle m’est presque impossible et que les montages sur les serveurs ont disparus. J’essaie de remonte sur l’autre chemin ( ça devrait pas être transparent ??) et j’ai un beau message kernel et mes serveurs freeze.(j’ai plus la main, obligé de redémarrer).
Première question: j’ai installer tout par apt-get install faut-il tout compiler pour ne plus avoir se genre de bug ?
Seconde: Serait-il possible d’envoyer le descriptif et la configuration par mail et liste des commandes tapées afin de voir si il y a pas une erreur de ma part ?
Car je trouve que c’est une très bonne approche quand elle marche.
Sachez que c’est mon dernier recours après avoir surfer sur la vage page après page.
Merci d’avance
il n’existe pas de mpath1 en environnement dual serveur. voir les commentaires précédents.
Ubuntu n’est pas une distribution pour serveur, faut arreter avec ca (avis perso).
Si le serveur freeze il y a carrement un probleme systeme donc oui recompiler depuis les sources. Au pire le disque /data n’est pas dispo mais le systeme ne freeze pas…
Merci pour tes précieux conseils. Effectivement, il y a vraiment un gros problème au niveau du kernel et de la version d’OS. Je suis passé sur une version inférieure et tout marche comme dans ton blog. Je ferai attention aux mises à jour kernel.
Juste un avis personnel c’est vraiment robuste comme solution !!!.
Pingback: Installation DRBD sur Centos 5.5 ou redhat
Bonjour,
Merci pour ce billet emprunt d’humour et de haute technicité, j’ai bien avancé grâce à lui. Cependant, il me reste un gros souci : si je tue un des targets, le filesystem reste visible quelques secondes sur les noeuds puis ceux-ci rebootent sans autre forme de procès. Si je tue le « bon » target, tout se passe bien, y compris la reprise du drbd0 du target dans le multipath au redémarrage du target mort. J’ai un sérieux doute sur mon multipath. Est-ce que la sortie suivante de « multipath -ll » est bonne ? :
size=1023M features=’0′ hwhandler=’0′ wp=rw
|-+- policy=’round-robin 0′ prio=1 status=active
| `- 2:0:0:1 sdb 8:16 active ready running
`-+- policy=’round-robin 0′ prio=0 status=enabled
`- 4:0:0:1 sdc 8:32 failed faulty running
Ne devrait-il pas y avoir qu’une ligne « policy » ? Après 3 jours d’intenses recherches et de tests dans tous les sens, je ne sais plus à quel saint me vouer…
Bonsoir et merci pour les compliments 😀
Comme je suis passé depuis longtemps à d’autres sujets, ma mémoire sur ce sujet est un peu « légère ».
Je ne pourrais affirmer que policy ne contient qu’une ligne mais cela me parait étrange quand même.
Désolé de ne pas être d’une aide supplémentaire, mais depuis 2 ans j’ai vogué sur d’autres sujets :p