GuiguiAbloc

architecture

Réplication de serveurs Memcached

par guiguiabloc le 08 sept, 2009, sous architecture, linux

C’est la rentrée, j’espère que les vacances se sont bien passées pour tout le monde, et que, comme moi, vous avez énormément pris sur vous en croisant un panneau « Wi-Fi libre accès » sous les regards noirs et appuyés de Madame… :-p (le même regard qu’elle vous jettera d’ailleurs quand, sur la plage, refoulant le souvenir de cette borne Wi-Fi, vos yeux glisseront subrepticement sur le corps de la jeune demoiselle à quelques pas de vous, quand elle dégrafera son haut de maillot de bain…) BREF !!!

Fin de l’encart « vacances perverses » :-D et je vous souhaite une bonne reprise quand même :-)

Nul besoin de vous refaire une présentation de Memcached dont j’avais abordé le sujet précédemment.

Vous l’utilisez parce que vous avez une forte charge sur vos serveurs et vous avez été conquis par ses performances, et c’est bien :-D

Comme vous le savez, fidèles lecteurs (ou pas) de ce blog (et je vous en remercie, c’est toujours très agréable de savoir que le temps passé a tester et écrire des articles est au moins lu par quelques milliers dizaines de personnes :-) ), j’aborde assez souvent la notion de haute-disponibilité.

Outre l’incomparable avantage de permettre au Sysadmin de pouvoir terminer sa nuit tranquillement sans devoir se rendre a 4h du matin au Datacenter pour remettre en service un serveur capricieux, elle permet surtout de disposer d’une infrastructure solide et disponible de façon quasi-permanente qui feront les joies de votre DI/RSI/DRH/DAF etc. etc. (liste non exhaustive).

Dans cette architecture hautement disponible, vous avez greffé un serveur memcached (ou pour soulager vos serveurs de base de données, ou pour distribuer du contenu statique, ou gérer vos sessions utilisateurs, ou que sais-je encore…).

Oui mais voila, si le serveur Memcached tombe, et bien ca colle quand même un frein à vos performances en attendant qu’il reparte.

Nous aurions bien évidemment pu installer un deuxième serveur Memcached en secours et basculer une ip flottante type fail-over/carp sur l’esclave en cas de panne du Maître mais il faut repeupler le cache… Pas très sexy comme méthode (même si efficace).

Je vous propose donc une autre solution, une réplication Memcached entre X serveurs de ce type.

(et là vous pouvez faire « Oooohhh »)

  • REPCACHED

Pour cette solution, nous allons utiliser le projet REPCACHED qui ajoute a Memcached les fonctions de réplication dont vous trouverez les sources sur :

http://sourceforge.net/projects/repcached/files/

Parmi ses fonctionnalités :

  • multi master replication.
  • asynchronous data replication.
  • support all memcached command (set, add, delete, incr/decr, flush_all, cas)

Par contre, si l’on peut reprocher quelque chose à ce projet dans l’état actuel des choses, c’est son manque quasi total de documentation :-(

Deux types de sources sont disponibles :

- 1 patch version 2.2 pour Memcached (version 1.2.8 à l’heure où j’écris)

ou

- L’ensemble complet Repcached 2.2 + Memcached 1.2.8

Le seul pré-requis est d’avoir l’API libevent (un apt-get install libevent-dev sous Debian suffira)

L’installation en mode patch est la suivante :

$ wget http://memcached.googlecode.com/files/memcached-1.2.8.tar.gz
$ tar zxf memcached-1.2.8.tar.gz
$ cd memcached-1.2.8.tar.gz
$ wget http://downloads.sourceforge.net/project/repcached/repcached/2.2-1.2.8/repcached-2.2-1.2.8.patch.gz
$ gzip -cd repcached-2.2-1.2.8.patch.gz | patch -p1

Pour les deux modes (patch ou full sources) :

$ ./configure --enable-replication
$ make
$ make install

Désormais, vous avez des options supplémentaires pour le lancement du démon :

Guiguiabloc-a:/opt/memcached/bin$ ./memcached -h
memcached 1.2.8
repcached 2.2
...
-x   hostname or IP address of peer repcached
-X       TCP port number for replication (default: 11212)

Le fonctionnement est assez basique.

Vous démarrez le premier serveur en lui passant l’option -x adresse_ou_ip_partenaire

memcached@Guiguiabloc-a:~/bin$ ./memcached -d -x Guiguiabloc-b
memcached@Guiguiabloc-a:~/bin$

Le serveur Memcached utilise par défaut le port 11212 pour la réplication, pensez à ouvrir votre firewall.

Maintenant nous allons démarrer le deuxième serveur en lui passant l’option -x

memcached@Guiguiabloc-b:~/bin$ ./memcached -d -x Guiguiabloc-a
memcached@Guiguiabloc-b:~/bin$

Ne reste qu’à tester.

Injectons un couple clé/valeur sur le maître directement par telnet.

NB: Vous trouverez sur http://lzone.de/articles/memcached.htm un récapitulatif des commandes existantes (Merci a Fred (le seul geek que je connaisse qui écoute « Oh chéri chéri » de Karen Cheryl » en boucle sur son Ipod) pour le lien)

memcached@Guiguiabloc-a:~/bin$ telnet Guiguiabloc-a 11211
Trying 192.168.50.1...
Connected to guiguiabloc-a.
Escape character is '^]'.
get url
END
set url 1 0 19
blog.guiguiabloc.fr
STORED
get url
VALUE url 1 19
blog.guiguiabloc.fr
END

En détails, je vérifie s’il existe une valeur pour la clé « url » (get url).

La réponse est négative, je stocke donc la clé « url », 1 signifiant « arbitrary metadata », 0 « n’expire jamais », 19 bytes de longueur, et la valeur.

On redemande la clé « url », c’est bon.

Maintenant sur le deuxième serveur :

memcached@Guiguiabloc-b:~/bin$ telnet guiguiabloc-b 11211
Trying 192.168.50.2...
Connected to guiguiabloc-b.
Escape character is '^]'.
get url
VALUE url 1 19
blog.guiguiabloc.fr
END

Un succès ! :-D

Vous pouvez tester dans l’autre sens, en modifiant la valeur de la clé « url » sur le deuxième serveur, elle sera modifiée sur le premier.

En coupant brutalement l’un des deux et en le relancant, vous verrez que son cache se met a jour automatiquement via la réplication Memcached.

memcached@Guiguiabloc-a:/opt$ telnet guiguiabloc-a 11211
Trying 192.168.50.1...
Connected to Guiguiabloc-a.
Escape character is '^]'.
get url
VALUE url 1 19
blog.guiguiabloc.fr
END
quit
Connection closed by foreign host.
memcached@Guiguiabloc-a:/opt$ killall memcached
memcached@Guiguiabloc-a:/opt$ ps aux | grep memcached
1002      5927  0.0  0.2   4168  1068 pts/0    S    19:26   0:00 su - memcached
1002      5966  0.0  0.1   3344   744 pts/0    S+   19:39   0:00 grep memcached
memcached@Guiguiabloc-a:~/bin$ ./memcached -d -x guiguiabloc-b
memcached@Guiguiabloc-a:~/bin$ telnet guiguiabloc-a 11211
Trying 192.168.50.1...
Connected to guiguiabloc-a.
Escape character is '^]'.
get url
VALUE url 1 19
blog.guiguiabloc.fr
END

Bilan, un excellent outil de haute-disponibilité qui inclut enfin le double sens de réplication (dans les versions antérieures (1.0), il fallait définir le Maître en le démarrant sans paramètres et l’esclave en lui passant l’option -x. En cas de crash du Maître, l’esclave devenait Maître. Le failback se réglait en lancant l’ancien Maître avec l’option -x.

On peut juste regretter l’absence quasi totale de documentation et même si le projet a bientôt 2 ans, il semble particulièrement mature pour de la production. A suivre donc.

Amusez-vous bien :-D

5 Commentairess :, plus...

MogileFS, un système de fichier distribué différent

par guiguiabloc le 13 mai, 2009, sous architecture, linux

J’ai souvent abordé sur ce blog les différents moyens de disposer de données redondantes dans une architecture en Haute-disponibilité.

Aujourd’hui je vais vous présenter une solution un peu plus méconnue pour certains d’entre vous, mais qui mérite tout son intérêt.

MogileFS est un système de fichier distribué en mode user.

Philippe Nicolas, sur son blog, en donne une définition parfaite :

« MogileFS est une émanation de Danga Interactive, acquis par Six Apart, qui pour ses projets de développement Web a mis au point ses propres souches logicielles.
MogileFS est un système de fichiers distribué open source en mode user, attention non conforme au standard POSIX, complètement redondant offrant un mécanisme de réplication de fichiers,
sans contrainte de systèmes de fichiers locaux, dont l’esprit est un mode shared-nothing par simple agrégation de machines indépendantes.
L’approche est asymétrique avec la notion de noeuds de stockage, de machines dites « trackers » et de machines database sachant que certains de ces fonctions peuvent résider sur le même système.

L’évolutivité vient de ce « collage » de machines afin de constituer un ensemble de taille importante.
MogileFS est donc une solution simple, gratuite et facile à mettre en place sans risque de planter le système. »

Par les avantages de MogileFS :

  • il agit au niveau applicatif et ne dépend donc pas d’un module du noyau
  • Les trois composants de MogileFs peuvent fonctionner indépendamment et sur plusieurs serveurs
  • MogileFS gère la réplication automatisée
  • Il détient sa propre base d’identification des fichiers

etc…

(je vous laisse lire la présentation sur leur site http://www.danga.com/mogilefs/ et http://mogilefs.pbwiki.com/HighLevelOverview

Si vous doutez encore de ses capacités, sachez que son auteur n’est autre que Bradley Fitzpatrick qui, pour ceux qui ne le connaîtrait pas encore, fait partie de l’équipe Danga Interactive a qui l’on doit, entre autre, Memcached.

Sachez enfin que MogileFS est utilisé par Digg (220 millions de pages vues par mois…) ou la plateforme Skyrock (5 milliards de pages vues par mois), voila qui devrait piquer votre curiosité.

  • Présentation générale

MogileFS est constitué de 3 composants :

  1. une base de données MySQL
  2. le « Tracker » ou client de transfert (terme bien connu chez certains ;-) )
  3. le noeud de stockage (mogstored)

Chaque composant est indépendant, vous pouvez donc les mixer (2 serveurs tracker+stockage, 2 serveurs stockage + 3 serveurs trackers etc….)

Concernant la base Mysql, tout dépend de votre infrastructure. Si vous disposez déjà d’une ferme Mysql, autant l’utiliser, sinon vous pouvez installer une simple solution master/slave sur 2 machines.

MogileFS, vue d'ensemble

MogileFS, vue d'ensemble

  • Installation

Les prérequis sont assez importants, un serveur Mysql bien sûr et plusieurs modules Perl dont MogileFS a besoin.

Sous une Debian :
apt-get install libio-socket-ssl-perl libbsd-resource-perl libcompress-zlib-perl libnet-netmask-perl libio-stringy-perl libwww-perl

Création de l’utilisateur dédié :

useradd mogilefs
 
mkdir /etc/mogilefs

Je vous conseille de récupérer les dernières sources via Subversion

apt-get install subversion
cd /etc/mogilefs
svn checkout http://code.sixapart.com/svn/mogilefs/trunk/

Récupérons les modules Perl nécessaires :

perl -MCPAN -e shell

(si vous n’avez jamais utilisé le shell CPAN, laisser les choix par défaut, et sélectionnez Europe/France puis un site FTP)

cpan> install Danga::Socket
CPAN: Storable loaded ok
...
Writing Makefile for Danga::Socket
---- Unsatisfied dependencies detected during [B/BR/BRADFITZ/Danga-Socket-1.61.tar.gz] -----
Sys::Syscall
Shall I follow them and prepend them to the queue
of modules we are processing right now? [yes]
...
Running make install
Installing /usr/local/share/perl/5.8.8/Danga/Socket.pm
Installing /usr/local/man/man3/Danga::Socket.3pm
Writing /usr/local/lib/perl/5.8.8/auto/Danga/Socket/.packlist
Appending installation info to /usr/local/lib/perl/5.8.8/perllocal.pod
/usr/bin/make install  -- OK
 
cpan>

faites de même pour

install DBI
install IO::AIO
install Path::Class
install List::MoreUtils
install Perlbal
install Gearman::Client
install Gearman::Server
install Gearman::Client::Async

Installation de MogileFS (mogilefsd, mogstored) et des outils

cd /etc/mogilefs/trunk/server
perl Makefile.PL
make
make install
 
cd /etc/mogilefs/trunk/
 
Guiguiabloc-a:/etc/mogilefs/trunk# cd api/perl/MogileFS-Client
Guiguiabloc-a:/etc/mogilefs/trunk/api/perl/MogileFS-Client#perl Makefile.PL
make install
 
Guiguiabloc-a:/etc/mogilefs/trunk/server# cd ../utils/
Guiguiabloc-a:/etc/mogilefs/trunk/utils# perl Makefile.PL

Installation de la base de données

Guiguiabloc-a:~# mysql -u root -p -h guiguiabloc-mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.0.51 Guiguiabloc distribution
 
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
 
mysql> create database mogilefs ;
Query OK, 1 row affected (0.00 sec)
mysql> grant all on mogilefs.* TO 'mogile'@'%' identified by 'password' ;
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges ;
Query OK, 0 rows affected (0.00 sec)

On charge le schéma :

Guiguiabloc-a:~# mogdbsetup --dbhost=guiguiabloc-mysql --dbname=mogilefs --dbuser=mogile --dbpass=password
 
This will attempt to setup or upgrade your MogileFS database.
It won't destroy existing data.
Run with --help for more information.  Run with --yes to shut up these prompts.
 
Continue? [N/y]: y
Guiguiabloc-a:~#

Configuration de Mogstored (noeud de stockage)

Pour les noeuds de stockage, création du répertoire dédiée à cela :

Guiguiabloc-a:~# mkdir /data
Guiguiabloc-a:~# chown -R mogilefs /data

Puis création d »un « device » (un répertoire spécifique pour une application par exemple)

Attention, 1 device par noeud de stockage

Guiguiabloc-a:~# mkdir /data/dev1
Guiguiabloc-a:~# chown -R mogilefs /data/dev1

On prépare le fichier de configuration pour le démon de stockage :

/etc/mogilefs/mogstored.conf
 
httplisten=0.0.0.0:7500
 
mgmtlisten=0.0.0.0:7501
 
docroot=/data

Fichier de configuration de mogilfsd

cp /etc/mogilefs/trunk/server/conf/mogilefsd.conf /etc/mogilefs/mogilefsd.conf
 
#daemonize = 1
db_dsn = DBI:mysql:mogilefs:host=guiguiabloc-mysql
db_user = mogile
db_pass = password
listen = 192.168.0.1:7001
conf_port = 7001
listener_jobs = 10
delete_jobs = 1
replicate_jobs = 5
mog_root = /data
reaper_jobs = 1

Maintenant que tout cela est paramétré, lançons les services :

TRACKER :

su mogilefs -c ‘mogilefsd -c /etc/mogilefs/mogilefsd.conf –daemon’

STORAGE :

mogstored –daemon

Les commandes d’administration se font avec « mogadm ».

Vérifions les trackers (les miens écoutent sur le port 7001) :

mogadm --tracker=192.168.0.1:7001 check
Checking trackers...
192.168.0.1:7001 ... OK
 
Checking hosts...
No devices found on tracker(s).

Maintenant, peuplons la base de données en lui indiquant les noeuds de stockages

Guiguiabloc-a:/etc/mogilefs# mogadm --tracker=192.168.0.1:7001 host add Guiguiabloc-b --ip=192.168.0.2 --port=7500 --status=alive
Guiguiabloc-a:/etc/mogilefs# mogadm --tracker=192.168.0.2:7001 check
Checking trackers...
192.168.0.2:7001 ... OK
 
Checking hosts...
[ 1] Guiguiabloc-a ... OK
[ 2] Guiguiabloc-b ... OK
 
Checking devices...
host device         size(G)    used(G)    free(G)   use%   ob state   I/O%
---- ------------ ---------- ---------- ---------- ------ ---------- -----
---- ------------ ---------- ---------- ---------- ------
total:     0.000      0.000      0.000   0.00%

Il faut ajouter les « devices »:

Guiguiabloc-a:/etc/mogilefs# mogadm --tracker=192.168.0.1:7001 device add guiguiabloc-a 1
 
Guiguiabloc-a:/etc/mogilefs# mogadm --tracker=192.168.0.1:7001 device list
Guiguiabloc-a [1]: alive
used(G) free(G) total(G)
dev1: alive      0.767   2.897   3.664
 
Guiguiabloc-b [2]: alive
used(G) free(G) total(G)
dev2: alive      0.762   2.902   3.664

Vous pouvez maintenant faire vos premiers tests :

Création d’un « domaine » et d’une « class » de test

(lire http://mogilefs.pbworks.com/Definitions)

Guiguiabloc-a:/var# mogadm --tracker=192.168.0.2:7001 domain add testguiguiabloc
Guiguiabloc-a:/var# mogadm --tracker=192.168.0.2:7001 class  add testguiguiabloc classguiguiabloc

Faisons un petit test à la mano pour insérer un fichier

Guiguiabloc-a:/etc# mogtool --tracker=192.168.0.2:7001 --domain=testguiguiabloc --class=classguiguiabloc inject motd motd
file motd: a46d249bd6d5f650b29048b4a2e7d610, len = 357
Spawned child 9943 to deal with chunk number 1.
chunk 1 saved in 0.11 seconds.
Child 9943 successfully finished with chunk 1.
Replicating: 1

Une petite vérification sur nos deux noeuds de stockage nous montre que le fichier a bien était dupliqué :

Guiguiabloc-a:/etc# ls /data/dev1/0/000/000/
0000000003.fid
 
Guiguiabloc-b:/etc# ls /data/dev2/0/000/000/
0000000003.fid

Sympa, non ? :-)

Il ne vous reste plus qu’à utiliser la librairie cliente de votre choix (Ruby, Perl, Java, Python, Php etc…) dans votre application pour appeler vos trackers et vos fichiers stockés.

Amusez vous bien :-)

10 Commentairess : plus...

Interception des erreurs applicatives dans Nagios avec SEC et Prelude-lml

par guiguiabloc le 18 mar, 2009, sous architecture, linux

Ce billet est né d’une demande de mon ami « Poupinade » qui connaissant mon goût pour les challenges divers et variés, me demanda avec fourberie innocemment comment je ferais, moi, pour intercepter des erreurs applicatives dans Nagios.

Nagios est un outil de surveillance système et réseau. Largement éprouvé, il est déployé fréquemment pour monitorer les équipements, services etc…

Pour moi, il reste un outil d’alerte et doit être utilisé comme tel. Je ne pense pas que ce soit à lui de remonter des informations détaillées sur un problème quelconque, mais de permettre au « superviseur » de débrancher sur un autre outil s’il veut peaufiner la cause de la panne/alerte (ceux qui utilisent un Nagios avec plus de 1000 hôtes et une dizaine de services par machine me comprendront aisément ;-) ).

Je ne m’étendrais pas sur Nagios ici, encore moins sur son installation et son paramétrage.

Vous trouverez de nombreuses références et tutos sur le Nain Ternet pour vous aider à sa mise en place.

La problématique qui se pose ici est de permettre d’être informer rapidement en cas d’erreur dans les logs d’une application.

Car oui on peut surveiller le bon fonctionnement du serveur httpd, de la Base de Données, du lien réseau etc… , mais il peut arriver qu’un autre problème surgisse et que Nagios ne supervise pas.

Je simplifie à l’extrême le concept « application » et prenant comme exemple une application « web », libre à vous d’adapter ce billet à autre chose.

Dans les exemples qui suivront et pour la maquette d’architecture choisie, j’ai pris un simple site en php (en l’occurrence un FlySpray ) qui me sert au suivi de mes « travaux » (a la manière d’OVH).

Les erreurs rencontrées par une « application » sont dans la majorité des cas lisibles dans un fichier de log dédié.

Première chose, faire « tomber » les erreurs php dans le log d’erreur du Vhost d’apache :

Edition du php.ini :
 
error_reporting  =  E_ALL & ~E_NOTICE
display_errors = On
 
Configuration du vhost :
 
ServerName application.guiguiabloc.fr
DocumentRoot /var/www/application
ErrorLog /var/log/apache2/application-error.log
LogLevel warn
CustomLog /var/log/apache2/application-access.log combined

Toujours a des fins de test, je simule une erreur critique, la perte de liaison avec le serveur de base de données.
En l’occurrence, j’ajoute une entrée dans le /etc/hosts du serveur httpd avec une fausse adresse IP vers le serveur Mysql, ce qui génère l’erreur suivante :

[Sun Mar 15 17:27:09 2009] [error] [client 192.168.0.2] PHP Warning:  mysqli_real_connect():
(HY000/2003): Can't connect to MySQL server on 'mysql-serveur' (113) in /var/www/application/adodb/drivers/adodb-mysqli.inc.php on line 108

Erreur je l’avoue très sournoise, Nagios me disant que mon serveur Mysql répond très bien et que le réseau entre le serveur applicatif et le serveur de base de données est opérationnel.

Comment surveiller ce genre de fichier et alerter Nagios quand quelque chose se produit ?

  • SEC Simple Event Correlator

SEC est un programme écrit en Perl, extrêmement puissant et configurable à souhait, qui permet de scruter des fichiers de logs et d’y détecter des événements divers et variés.

Le site est ICI

Côté installation sur le serveur applicatif, pas de soucis :

srv-appli:/usr/local/src# wget http://prdownloads.sourceforge.net/simple-evcorr/sec-2.5.1.tar.gz
srv-appli:/usr/local/src# tar xzvf sec-2.5.1.tar.gz
srv-appli:/usr/local/src# cd sec-2.5.1
srv-appli:/usr/local/src/sec-2.5.1# mkdir /usr/local/bin/sec
srv-appli:/usr/local/src/sec-2.5.1# mkdir /usr/local/bin/sec/etc
srv-appli:/usr/local/src/sec-2.5.1# cp sec.pl /usr/local/bin/sec/

Une configuration toute simple :

srv-appli:/usr/local/bin/sec/etc# cat sec.conf
type=Single
ptype=RegExp
pattern=error
desc=$0
action=shellcmd  /opt/nagios/libexec/eventhandlers/submit_check_result_via_nsca srv-appli  'Application' 2 "$0"

Ici, nous demandons à SEC de réagir sur la chaîne « error » (bien évidemment, vous pouvez affiner vos expression régulières…) et en cas de détection, d’exécuter la commande « /opt/nagios/libexec/eventhandlers/submit_check_result_via_nsca  » avec en paramètre, le nom du host dans Nagios, le nom du service, le code retour Nagios et le message d’erreur.

Auparavant, vous avez ajouté une entrée de type « Passive » dans Nagios :

# NSCA
define service{
        use         passive_checkservice
        host_name    srv-appli
        service_description    Application
        # ici la commande check_smtp n'a aucune signification particuliere
        # c'est simplement que sans check_command cela ne marche pas !
        check_command                check_smtp
      }

Et oui, ce type de fonctionnement implique que vous utilisez NSCA sur le serveur d’application (surveillance passive de Nagios, c’est le serveur d’appli qui envoie l’alerte)

Vous devez sur votre Nagios, avoir une entrée de ce genre

Ne reste plus qu’à lancer le script SEC :

srv-appli:/# perl -w /usr/local/bin/sec/sec.pl -conf=/usr/local/bin/sec/etc/sec.conf -input=/var/log/apache2/application-error.log -log /var/log/sec.log
SEC (Simple Event Correlator) 2.5.1
Reading configuration from /usr/local/bin/sec/etc/sec.conf
1 rules loaded from /usr/local/bin/sec/etc/sec.conf
Stdin connected to terminal, SIGINT can't be used for changing the logging level

On provoque l’erreur

Executing shell command '/opt/nagios/libexec/eventhandlers/submit_check_result_via_nsca srv-appli  'Application' 2 "[Tue Mar 17 11:13:34 2009] [error] [client 192.168.99.14] PHP Warning:  mysqli_real_connect(): (HY000/2003): Can't connect to MySQL server on 'mysql-serveur' (113) in /var/www/application/adodb/drivers/adodb-mysqli.inc.php on line 108"'
Child 10131 created for command '/opt/nagios/libexec/eventhandlers/submit_check_result_via_nsca srv-appli  'Application' 2 "[Tue Mar 17 11:13:34 2009] [error] [client 192.168.99.14] PHP Warning:  mysqli_real_connect(): (HY000/2003): Can't connect to MySQL server on 'mysql-serveur' (113) in /var/www/application/adodb/drivers/adodb-mysqli.inc.php on line 108"'
1 data packet(s) sent to host successfully.

Et l’alerte remonte dans Nagios :

Alerte Nagios

Alerte Nagios

Cela fonctionne mais bon…

Premier point bloquant, cela signifie que l’on utilise la surveillance Passive de Nagios (NSCA) sur le srv-appli, ce qui n’est pas forcément le cas.

Deuxième point bloquant, si une deuxième erreur surgit à la suite (pas de chance hein :-p), c’est celle ci qui sera affichée dans Nagios.
Je peux très bien acquitter l’alarme et passer à côté d’un problème plus crucial…

Pour le test :

srv-appli:/# echo « [Mon Mar 17 14:25:42 2009] [error] Une autre erreur » >> /var/log/apache2/application-error.log

Donc, obligation d’aller sur le serveur, de vérifier le /var/log/Sec.log….

Autre solution ;-)

  • PRELUDE IDS

Prelude est un « Security Information Management » (SIM) Universel. Prelude collecte, normalise, catégorise, agrège, corrèle et présente tous les événements sécurité indépendamment de la marque ou de la licence du produit dont ces événements sont issus : il est « Agentless ».

Cela tombe très bien, j’avais déjà écrit un billet sur Prelude l’année dernière :-D

http://blog.guiguiabloc.fr/index.php/2008/01/27/installer-et-configurer-prelude/

Vous ne serez pas pas dépaysé.

Pour scruter nos logs, nous allons utiliser un des modules de Prelude : Prelude-lml

Ce n’est pas le rôle premier de ce logiciel (qui est surtout un centralisateur d’alertes IDS/NIDS), mais rien nous interdit de le détourner de sa voie.

Je vous passe l’installation du module sur le serveur d’application ainsi que son enregistrement dans le Prelude Manager, tout est expliqué dans le billet précité.

srv-appli:/# prelude-adduser register prelude-lml "idmef:w admin:r" IP_Prelude_Manager --uid 1000 --gid 1000
prelude-manager:/:# prelude-adduser registration-server prelude-manager
 
... - prelude-lml registration to IP_Prelude_Manager successful

Une configuration succincte pour nos tests :

prelude-lml.conf :
 
file = /var/log/apache2/application-error.log
 
/etc/prelude-lml/ruleset/pcre.rules :
 
regex=(\[error\]);              include = appli.rules;
include = single.rules;
 
/etc/prelude-lml/ruleset/appli.rules :
 
#LOG:[Sun Mar 15 17:27:09 2009] [error] [client 192.168.0.1] PHP Warning:  mysqli_real_connect(
):
 
regex=\[error\] \[client ([\d\.]+)\] ; \
 classification.text=server error; \
 id=44100; \
 revision=1; \
 analyzer(0).name=Appli; \
 analyzer(0).manufacturer=blog.guiguiabloc.fr; \
 analyzer(0).class=Service; \
 assessment.impact.severity=high; \
 assessment.impact.completion=failed; \
 assessment.impact.type=other; \
 assessment.impact.description=Erreur applicative; \
 source(0).node.address(0).category=ipv4-addr; \
 source(0).node.address(0).address=$1; \
 source(0).service.iana_protocol_name=tcp; \
 source(0).service.iana_protocol_number=6; \
 target(0).service.iana_protocol_name=tcp; \
 target(0).service.iana_protocol_number=6; \
 last;

Je ne m’étendrais pas sur les expressions régulières, ni sur les normes IDMEF utilisées (cela prendrait un billet complet) et je vous invite à consulter ses pages :

https://trac.prelude-ids.org/wiki/PreludeLml

http://www.rfc-editor.org/rfc/rfc4765.txt

http://www.gscore.org/blog/index.php/post/2007/08/13/IDMEF-for-dummies-part-1

On reproduit de nouveau l’erreur qui maintenant est interceptée par Prelude-lml et envoyée au Manager

Report Prelude

Report Prelude

Déjà plus classieux comme système de centralisations, non :-)

Et là vous me dites « Et comment je le sais tout cela dans Nagios ????? »

Grâce à la communauté Nagios :-D

http://www.nagiosexchange.org/cgi-bin/page.cgi?g=Detailed%2F2287.html;d=1

Vous y trouverez le check_prelude.pl , fonctionnant en NRPE, qui vous permet d’aller vérifier le nombre d’entrées HIGH ou MEDIUM dans la base Mysql Prelude :-)

Nagios remontera donc une alerte Critique ou Warning que vous acquitterez (ou pas :-p) avant d’aller vous connecter sur le Prelude Manager et vérifier la teneur exacte du message d’erreur applicatif et de le supprimer dès sa résolution.

Tout ceci est bien sûr un simple exercice de style, à prendre comme une piste de travail.
Je suis certain que vous trouverez d’autres solutions à mettre en oeuvre.

Amusez vous bien :-)

Laisser un commentaire :, , plus...

Mise en oeuvre d’un système de fichier distribué et accès concurrents en SAN avec DRBD, ISCSI ,OCFS2 et DM-Multipath

par guiguiabloc le 16 fév, 2009, sous architecture, linux

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.

Exemple DRBD

En cas de panne du Maître, le service est basculé sur l’Esclave et les données accessibles par celui ci.

Bascule DRBD

Bascule DRBD

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 :-D )

Une fois mise en place, nous nous retrouvons donc avec ce type d’architecture :

OCFS2

OCFS2

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 :

Schéma FS distribué

Schéma FS distribué

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 :-D

(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 :-D

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 :-D

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 :

http://blog.guiguiabloc.fr/index.php/2009/01/14/switch-applicatif-avec-openbsd-un-alteon-a-la-maison/

Ce qui nous donne un joli résultat au final :

La Haute Dispo vue par Guiguiabloc

La Haute Dispo vue par Guiguiabloc

Très « poilu », non ? :-D

Comme dirais mon pote `g0rt :

[17:53] <`g0rt> ca c’est de la redondance vindiousse

Bon courage dans le peaufinage de votre cluster ;-)

55 Commentairess :, , , , , , plus...

Vous cherchez quelque chose ?

Utilisez le formulaire ci-dessous:

Vous ne trouvez pas ce que vous voulez ? Laisser un Commentaire sur un Billet !

Special Copinage!

Quelques sites amis ou recommandés...