Aller au contenu | Aller au menu

/var/log/greg.log

Ceph et CephFS

Ceph is a free software distributed file system initially created by Sage Weil. Ceph's main goals are to be
POSIX-compatible, and completely distributed without a single point of failure. The data is seamlessly replicated,
making it fault tolerant.

Architecture


Ceph est composé de 3 composants :

  • ceph-osd (Object Storage Device), qui s'appuie sur une partition XFS ou Btrfs de préférence. Pour cette première utilisation je choisis Btrfs. C'est ce process qui va stocker les données et attributs sur disque.
  • ceph-mds (Metadata Server), est le cache distribué de metadata. Mais ces metadatas sont stockés sur disque via ceph-osd. Ce process nécéssite donc beaucoup de mémoire.
  • ceph-mon (Monitor), est le process qui chapote un peu le tout, c'est sur ce process que les clients se connectent. Il ne nécéssite pas énormément de ressource, mais contrairement aux 2 précédents process, il en faut au moins 3. S'ils fonctinnent en binome, il faut que les 2 répondent, donc il suffit qu'un seul tombe pour que tout tombe !


Connaissant ces contraintes, je suis parti sur cette configuration :

  • 2 serveurs puissants, identiques, qui feront tourner ces 3 process.
  • 2 serveurs cheaps, qui ne feront tourner qu'une instance ceph-mon chacun.


Architecture Ceph

Installation



Ceph est une techno hyper récente, ça fait 3 ans qu'ils indiquent sur leur site qu'il ne faut absolument pas l'utiliser en production, je vais donc partir sur un environnement technique récent:

  • Debian Wheezy, elle est freezée et doit sortir prochainement en stable
  • kernel "maison" 3.5.3, qui est en faite un kernel Debian avec la config Debian, compilé avec make-kpkg, j'ai juste ajouté les modules suivants :
CONFIG_CEPH_LIB=m
# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set
CONFIG_CEPH_FS=m
  • - packages ceph provenant de ceph.com : ceux de wheezy sont en version 0.43, j'ai rencontré des problèmes qui ont été résolue, depuis la version 0.48 est grandement conseillée.
# cat /etc/apt/sources.list.d/ceph.list
deb http://ceph.com/debian/ wheezy main
# wget -q -O- https://raw.github.com/ceph/ceph/master/keys/release.asc | sudo apt-key add -
# apt-get install ceph

Configuration


Chaque process a besoin de son dossier :

Data-01:/var/local# mkdir mon mds osd


/var est une partition ext4, et on a besoin d'une partition btrfs pour le démon osd :

Data-01:~# grep btrfs /etc/fstab
/dev/sda9               /var/local/osd/osd.0 btrfs rw,noatime   0               0


Je vous passe les étapes de création d'un kernel, de formatage d'une partition, etc....

Tout est dans le fichier de configuration /etc/ceph/ceph.conf, prenez donc le temps de le faire correctement. Voici ma version, adapté à cette architecture :

[global]
        auth supported = cephx
        keyring = /etc/ceph/keyring.bin
        max open files = 131072
        log file = /var/log/ceph/$name.log
        pid file = /var/run/ceph/$name.pid

[mon]
        mon data = /var/local/mon/$name

[mon.Data-01]
        host = Data-01
        mon addr = 10.0.11.1:6789

[mon.Data-02]
        host = Data-02
        mon addr = 10.0.11.2:6789

[mon.Mon-01]
        host = Mon-01
        mon addr = 10.0.7.201:6789

[mon.Mon-02]
        host = Mon-02
        mon addr = 10.0.7.202:6789

[mds]
        keyring = /etc/ceph/keyring.$name

[mds.Data-01]
        host = Data-01

[mds.Data-02]
        host = Data-02

[osd]
        osd data = /var/local/osd/$name
        keyring = /etc/ceph/keyring.$name
        osd journal = /var/local/osd/$name/journal
        osd journal size = 1024 ; journal size, in megabytes

# le nom des instances OSD doivent être des ids :
[osd.0]
        host = Data-01
        osd data = /var/local/osd/$name
[osd.1]
        host = Data-02
        osd data = /var/local/osd/$name



La plupart des tutoriaux trouvés sur le net zappent la partie authentification, comme j'ai l'intention de m'en servir en production, voici la procédure :

Data-01:/var/local# ceph-authtool /etc/ceph/keyring.bin --create-keyring --name client.admin --gen-key --bin
creating /etc/ceph/keyring.bin
Data-01:/var/local# ceph-authtool --print-key /etc/ceph/keyring.bin > /etc/ceph/secret
Data-01:/var/local# chmod 600 /etc/ceph/secret
Data-01:/var/local# ceph-authtool /etc/ceph/keyring.bin --name client.admin --cap osd allow --cap mds allow --cap mon allow




Ensuite, il faut créer le filesystem, mais cette création va interroger tous les serveurs définis dans le fichier de configuration, il faut donc au préalable copier la config :

Data-01:~# for s in Mon-01 Mon-02 Data-02 ; do rsync -av /etc/ceph/ $s:/etc/ceph/; done


Enfin on peut créer le FS en spécifiant le keyring :

Data-01:~# mkcephfs -a -c /etc/ceph/ceph.conf -k /etc/ceph/keyring.bin --mkbtrfs



Si tout se passe bien, il est temps de démarrer l'ensemble des serveurs, on peut le faire en une seule commande, depuis n'importe quel des 4 serveurs :

Data-01:~# /etc/init.d/ceph -a start

Utilisation


Bien, ben on va maintenant monter la partition CephFS ! D'abord avec un test à la main :

Data-01:/var/local# mount -t ceph -o name=admin,secretfile=/etc/ceph/secret Data-01.local:/ /var/local/data/
mount: error writing /etc/mtab: Invalid argumentData-01:/etc/ceph#


Cette erreur est étrange, mais ne pose aucun problème, au contraire pour moi elle indique que le montage s'est bien passé :)

Par acquis de conscience, je vais ensuite démonter cette partition, puis tenter de la monter sur chaque serveur ceph-mon, et ne rencontrerais aucune difficulté.

Pour avoir un montage CephFS redondant, il est impératif de monter cette partition en spécifiant tous les ceph-mon dans l'instruction de montage, on peut le faire en séparant chaque ceph-mon par une virgule :

Data-01:~# grep ceph /etc/fstab
Mon-01,Mon-02,Data-01,Data-02:/ /var/data/ ceph noauto,name=admin,secretfile=/etc/ceph/secret 0 0


A ce moment, je me suis mis à faire tout un tas de tests: arrêter ceph sur un serveur monitor, puis sur un des serveurs de Data, puis juste un ceph-mon, juste un ceph-osd, juste un ceph-mds .... tant qu'il y en a un qui tourne, ça fonctionne, c'est formidable ! D'ailleurs, un truc à savoir, que je n'ai trouvé dans aucune doc, mais plutôt en lisant le script d'init, c'est comment faire pour arrêter un seul process sur un seul serveur :

Mon-02:~# /etc/init.d/ceph stop mon.Mon-02


L'état du cluster est visible avec la commande ceph -s :

Data-01:~# ceph -s
   health HEALTH_OK
   monmap e1: 4 mons at {Data-01=10.0.11.1:6789/0,Data-02=10.0.11.2:6789/0,Mon-01=10.0.7.201:6789/0,Mon-02=10.0.7.202:6789/0}, election epoch 40, quorum 0,1,2,3 Data-01,Data-02,Mon-01,Mon-02
   osdmap e59: 2 osds: 2 up, 2 in
    pgmap v1066: 384 pgs: 384 active+clean; 29904 bytes data, 2351 MB used, 440 GB / 462 GB avail
   mdsmap e68: 1/1/1 up {0=Data-01=up:active}



J'ai ensuite continuer ma config initiale, poser des données composés de 25k fichiers pour 2.3GB et depuis 2 semaines je ne rencontre aucun soucis. Dans ces conditions, voilà ce que donne un top :

3257 root      20   0  313m 164m 5112 S   0.0  0.3   1:11.94 /usr/bin/ceph-mds -i Data-01 --pid-file
 /var/run/ceph/mds.Data-01.pid -c /etc/ceph/ceph.conf
3354 root      20   0  459m 105m 5024 S   0.0  0.2   2:33.72 /usr/bin/ceph-osd -i 0 --pid-file /var/run/ceph/osd.0.pid
  -c /etc/ceph/ceph.conf
3103 root      20   0  139m  16m 3764 S   0.3  0.0   3:19.21 /usr/bin/ceph-mon -i Data-01 --pid-file
   /var/run/ceph/mon.Data-01.pid -c /etc/ceph/ceph.conf




A voir avec le temps, pour l'instant Ceph remplit les conditions que je m'étais imposées : pas de SPoF, stable.

FSCache pour un cache NFS

NFS est une super techno, quand elle fonctionne. 4 ans que mon architecture NFS est en production, sans pépin. Mais quand on a un pépin, les frontaux web ramassent fort, que ce soit des NGiNX ou des serveurs Apache2....

Que faire pour garder de la haute-dispo dans ces conditions, sans révolutionner l'ensemble, bref en peu de temps sans risquer de tout casser.... hé bien merci aux développeurs qui bossent sur le kernel Linux, parce que depuis peu (en terme de temps), ils ont intégrés le module FSCACHE qui permet d'ajouter une couche de cache au dessus d'un système de fichier réseau. Tip top ! Voyons voir....

Installation et configuration

Pas de mystère, il faut partir sur un kernel assez récent et avec les modules FSCACHE d'activés:

# grep FSCACHE /boot/config-3.3.1-ez
CONFIG_FSCACHE=m
CONFIG_FSCACHE_STATS=y
# CONFIG_FSCACHE_HISTOGRAM is not set
# CONFIG_FSCACHE_DEBUG is not set
# CONFIG_FSCACHE_OBJECT_LIST is not set
CONFIG_NFS_FSCACHE=y
# CONFIG_CIFS_FSCACHE is not set
CONFIG_AFS_FSCACHE=y
# CONFIG_9P_FSCACHE is not set

Je vous laisserais dans ce cas construire votre kernel à votre sauce...

Perso, je bosse sous Debian Squeeze, l'installation se fait en quelques commandes qui parlent d'elles memes :

kadoc-05:/data/cache1# mkdir fscache
kadoc-05:/data/cache1# apt-get install cachefilesd
kadoc-05:/data/cache1# sed -i 's/#RUN/RUN/' /etc/default/cachefilesd
kadoc-05:/data/cache1# modprobe fscache

Cette partition /data/cache1 doit être monté avec l'option user_xattr, si ce n'est pas le cas ajoutez là dans votre fstab et mount -o remount.

Démarrez cachefilesd

Le reste de la magie se passe dans les options de montage des partitions que vous voulez cacher, dans mon cas les partoches nfs4 : ajouter l'option fsc aux options de montages et ... c'est terminé !

Au bout de quelques secondes d'utilisations, on voit bien que le cache est utilisé :

kadoc-05:/etc/nginx# find /data/cache1/fscache/ -type f | wc -l
76129
kadoc-05:/etc/nginx# du -hs /data/cache1/fscache/
912M    /data/cache1/fscache/

J'ai quand même fais les tests basiques avec le serveur NGiNX qui se charge de lire les documents sur NFS, en le stoppant, démontant les partitions NFSv4, le démarrant... les documents sont bien servit comme si tout fonctionnait correctement !

Le serveur en question est en prod depuis un jour, on va voir comment se passe le week-end puis j'activerais FSCache sur tous les frontaux ! :)

Benchmark rapide comparant un disque dur, NFS et GlusterFS

Sur quelques serveurs j'ai la chance d'avoir un montage NFS ainsi qu'un montage GlusterFS 2.0-rc4.

  • un fichier de 17ko: cache_c21f969b5f03d33d43e04f8f136e7682_c57d91c82f2ed2e96c13765e33fcd5ae
  • un fichier de 50mo: 50.MB

J'ai copié ces 2 fichiers sur le disque dur dans /tmp, ainsi que sur les 2 montages réseaux, puis effectuer un simple cat (plusieurs fois), et voici les résultats :

php-14:~# for f in
/var/www/cache/cache_c/cache_cf/cache_cfb/cache_c21f969b5f03d33d43e04f8f136e7682_c57d91c82f2ed2e96c13765e33fcd5ae
/nfs/tmp/cache_c21f969b5f03d33d43e04f8f136e7682_c57d91c82f2ed2e96c13765e33fcd5ae
/tmp/cache_c21f969b5f03d33d43e04f8f136e7682_c57d91c82f2ed2e96c13765e33fcd5ae
/glusterfs/50.MB /nfs/tmp/50.MB /tmp/50.MB; do
echo $f; time cat $f >/dev/null; done
/var/www/cache/cache_c/cache_cf/cache_cfb/cache_c21f969b5f03d33d43e04f8f136e7682_c57d91c82f2ed2e96c13765e33fcd5ae

real    0m0.011s
user    0m0.000s
sys     0m0.000s
/nfs/tmp/cache_c21f969b5f03d33d43e04f8f136e7682_c57d91c82f2ed2e96c13765e33fcd5ae

real    0m0.002s
user    0m0.000s
sys     0m0.000s
/tmp/cache_c21f969b5f03d33d43e04f8f136e7682_c57d91c82f2ed2e96c13765e33fcd5ae

real    0m0.001s
user    0m0.000s
sys     0m0.000s
/glusterfs/50.MB

real    0m0.081s
user    0m0.000s
sys     0m0.068s
/nfs/tmp/50.MB

real    0m0.037s
user    0m0.000s
sys     0m0.036s
/tmp/50.MB

real    0m0.028s
user    0m0.000s
sys     0m0.028s

GlusterFS est donc plus lent que NFS pour les petits fichiers ET les "gros" fichiers, mais j'en ai pas finis avec le paramètrage ! Le serveur NFS est plutot bien optimisé, alors que je découvre seulement GlusterFS et que je commence seulement les tests...

Mettre à jour GlusterFS

Aujourd'hui, j'ai mis à jour GlusterFS sur les serveurs et les clients. Malgré que cette techno soit génial, on ne peut pas mettre à jour GlusterFS n'importe comment: il faut impérativement que les clients et les serveurs aient exactement la même version, même mineure ! Sinon, on obtient cette erreur, et le client ne se connecte pas :

SETVOLUME on remote-host failed: Version mismatch: client(2.0.0rc7) Vs server (2.0.0rc4)

Voici donc la procédure pour mettre à jour GlusterFS dans une architecture de type AFR client side, et en partant du principe que vous avez 2 serveurs.

1/ mettre à jour glusterfs sur le 1er serveur. Au restart, les clients ne pourront plus se connecter sur ce serveur. Vérifier dans les logs qu'il a bien démarré et qu'il n'y a pas eut de changement dans les paramètres.

2/ mettre à jour les clients, en arrêtant au préalable les services utilisant les montages glusterfs: il faut démonter puis remonter chaque partition pour avoir la dernière version du client. Les clients changent de serveurs au passage et se connecte au 1er serveur, qui a la même version.

3/ mettre à jour le 2ème serveur. Les clients vont automatiquement se connecter dessus.

4/ resynchroniser les données. Normalement la version 2.0 gère bien la synchro des données grâce à sa feature "self-healing". Dans le doute, on peut forcer, en faisant depuis un client connecté aux 2 nodes:

nice -20 find /glusterfs >/dev/null

That's all folks !

GlusterFS: création des packages Debian

Des packages existent déjà, merci à Leonardo Rodrigues de Mello. Mais ils sont en version 1.3.8, et depuis pas mal de bugs ont été corrigés, de nouvelles features sont apparues, il m'a parut nécessaire de construire mes propres packages.

Une version modifiée de FUSE est conseillée, et après l'installation et quelques mois d'utilisation non-intensive, je n'ai pas rencontré de problèmes.

  • Pour les packages fuse, je ne les ai pas recompilé, il existe déjà en version patchées.
gregbox:/usr/src/glusterfs# wget "http://lmello.virt-br.org/debian/fuse/libfuse2_2.7.2-glfs8-0_amd64.deb"
gregbox:/usr/src/glusterfs# wget http://lmello.virt-br.org/debian/fuse/libfuse-dev_2.7.2-glfs8-0_amd64.deb
gregbox:/usr/src/glusterfs# wget http://lmello.virt-br.org/debian/fuse/fuse-utils_2.7.2-glfs8-0_amd64.deb
  • l'installation :
gregbox:/usr/src/glusterfs# dpkg -i libfuse2_2.7.2-glfs8-0_amd64.deb libfuse-dev_2.7.2-glfs8-0_amd64.deb
Selecting previously deselected package libfuse2.
(Reading database ... 45253 files and directories currently installed.)
Unpacking libfuse2 (from libfuse2_2.7.2-glfs8-0_amd64.deb) ...
Selecting previously deselected package libfuse-dev.
Unpacking libfuse-dev (from libfuse-dev_2.7.2-glfs8-0_amd64.deb) ...
Setting up libfuse2 (2.7.2-glfs8-0) ...

Setting up libfuse-dev (2.7.2-glfs8-0) ...
  • pour les packages gluster, ceux de lmello datent un peu, je décide donc de construire la dernière version 1.3.12 à partir de ses sources.
# http://github.com/NeilW/deb-glusterfs/tree/master
gregbox:/usr/src/glusterfs# tar xzf NeilW-deb-glusterfs-5b5312670fa6c3a87c25df577cda8c0f8198cc06.tar.gz
gregbox:/usr/src/glusterfs# mv NeilW-deb-glusterfs-5b5312670fa6c3a87c25df577cda8c0f8198cc06 deb-glusterfs
  • on récupère les sources 1.3.12
# récupération des sources de gluster
gregbox:/usr/src/glusterfs# wget http://ftp.gluster.com/pub/gluster/glusterfs/1.3/glusterfs-CURRENT.tar.gz
gregbox:/usr/src/glusterfs# tar xzf glusterfs-CURRENT.tar.gz
# suppression de patchs inutiles avec cette version :
gregbox:/usr/src/glusterfs/deb-glusterfs# rm debian/patches/02patch-server-vol-spec.patch
# on édite le changelog pour changer la version
gregbox:/usr/src/glusterfs/deb-glusterfs# vim debian/changelog
gregbox:/usr/src/glusterfs/deb-glusterfs# aapt-get install cdbs debhelper bison flex libibverbs-dev  help2man libdb4.4-dev
  • enfin, la construction elle meme. Oui, ils sont construit sous root, c'est mal, pas bien, ne reproduisez pas ça chez vous :
gregbox:/usr/src/glusterfs/deb-glusterfs# dpkg-buildpackage
gregbox:/usr/src/glusterfs/deb-glusterfs# ls -altr .. | grep 1.3.12
drwxrwxrwx 10 mysql users    4096 2008-09-02 17:39 glusterfs-1.3.12
-rw-r--r--  1 root  src    783616 2008-09-18 15:16 glusterfs_1.3.12-0.tar.gz
-rw-r--r--  1 root  src       821 2008-09-18 15:16 glusterfs_1.3.12-0.dsc
-rw-r--r--  1 root  src     12790 2008-09-18 15:18 glusterfs-examples_1.3.12-0_all.deb
-rw-r--r--  1 root  src     17862 2008-09-18 15:18 glusterfs-client_1.3.12-0_amd64.deb
-rw-r--r--  1 root  src     10740 2008-09-18 15:18 glusterfs-server_1.3.12-0_amd64.deb
-rw-r--r--  1 root  src    363240 2008-09-18 15:18 libglusterfs0_1.3.12-0_amd64.deb
-rw-r--r--  1 root  src     84916 2008-09-18 15:18 libglusterfs-dev_1.3.12-0_amd64.deb
-rw-r--r--  1 root  src    971132 2008-09-18 15:18 glusterfs-dbg_1.3.12-0_amd64.deb
-rw-r--r--  1 root  src      1603 2008-09-18 15:18 glusterfs_1.3.12-0_amd64.changes
  • installation des packages :
gregbox:/usr/src/glusterfs/deb-glusterfs# dpkg -i ../*1.3.12*.deb
(Reading database ... 46297 files and directories currently installed.)
Preparing to replace glusterfs-client 1.3.10-1 (using .../glusterfs-client_1.3.12-0_amd64.deb) ...
Unpacking replacement glusterfs-client ...
Preparing to replace glusterfs-dbg 1.3.10-1 (using .../glusterfs-dbg_1.3.12-0_amd64.deb) ...
Unpacking replacement glusterfs-dbg ...
Preparing to replace glusterfs-examples 1.3.10-1 (using .../glusterfs-examples_1.3.12-0_all.deb) ...
Unpacking replacement glusterfs-examples ...
Preparing to replace glusterfs-server 1.3.10-1 (using .../glusterfs-server_1.3.12-0_amd64.deb) ...
Stopping GlusterFS server: glusterfsd.
Unpacking replacement glusterfs-server ...
Preparing to replace libglusterfs0 1.3.10-1 (using .../libglusterfs0_1.3.12-0_amd64.deb) ...
Unpacking replacement libglusterfs0 ...
Preparing to replace libglusterfs-dev 1.3.10-1 (using .../libglusterfs-dev_1.3.12-0_amd64.deb) ...
Unpacking replacement libglusterfs-dev ...
Setting up glusterfs-examples (1.3.12-0) ...
Setting up libglusterfs0 (1.3.12-0) ...

Setting up libglusterfs-dev (1.3.12-0) ...
Setting up glusterfs-client (1.3.12-0) ...
Setting up glusterfs-dbg (1.3.12-0) ...
Setting up glusterfs-server (1.3.12-0) ...
Installing new version of config file /etc/glusterfs/glusterfs-server.vol ...
Starting GlusterFS server: glusterfsd.

And voilà ! C'était facile, même si le package source de Leonardo m'a amplement simplifié la tâche. Une autre méthode possible aurait été d'utiliser les debhelpers (dh_make).

Présentation de GlusterFS

Présentation

  • Gluster.org
  • Création d'un cluster de fichiers à la fois serveur et client

logo glusterfs

Avantages

  • GlusterFS est comparable à NFS, en beaucoup plus performant, plus scalable et prévu pour la haute-dispo.
  • Le wiki est complet avec beaucoup de docs et de tutorials.
  • L'architecture du projet permet d'empiler les fonctionnalités, on peut donc mixer les fonctionnalités pour faire du mirroring, striping, unification, read-ahead, write-behind, encryption etc.
  • Automagic self-healing si un serveur tombe.
  • Roadmap importantes avec plein de fonctionnalités intéressantes comme le mod apache, hot-plug de brick, interface web, etc.

Inconvénients

  • Le projet est jeune.
  • pas vraiment de retour d'expériences en environnement de production.
  • Fonctionne en Userspace (FUSE) plutôt que dans un module kernel. Voir les implications sur les perfs.
  • la doc est uniquement dans le wiki, un trac serait mieux...
  • à vérifier: les données ne semble synchronisés qu'une fois lu, c'est à dire que si on écrit un fichier sur serveur B, les données sont tout de suite lisible, MAIS si on écrit d'autres fichiers sur serveur B, et qu'on ne les lit pas, ils ne sont pas synchronisés. Il faut donc forcer une lecture, par exemple:
find /mnt/rep -type f -exec head -n 1 {} \;
ou, plus efficace :
find /mnt/rep -type f -mtime -1 -exec head -c 1 {} > /dev/null \;

Dans le prochain billet: l'installation.

Session PHP: Le choix

Voilà, j'ai pu passer un peu de temps sur le gestionnaire de session mcache, enfin, surtout à compléter le peu de docs que j'avais sur ce sujet. J'ai rapidement écarté mcache de mes choix, ayant un sentiment moyen, de soft pas finit, un sentiment du genre je vais avoir des problèmes avec ce truc, je sais pas pourquoi.

Déjà, il ne fonctionne qu'en 32 bits, ce qui confirme mon sentiment de soft pas finit / plus maintenu. Ensuite, dans la doc, je suis tombé sur l'appendix B, je cite: Can mcache be set up to work across a cluster of computers? No puis; sur l'appendix C: Is mcache redundant? No J'ai du loupé un chapitre ! Exit mcache.

Passons à plus intéressant: sharedance. Trivial à installer, je l'ai d'abord mis en place sur notre serveur de développement, puis j'ai fais quelques scripts de tests: stockage d'objets énormes (24Mo), mesure des temps.... mmmh ça fonctionne bien ! Aller soyons fou, je développe un script PHP pour.... la prod. Afin de ne pas affecter le site de production en cas de plantage de sharedance, ou du serveur, je rajoute sur la page principale 2 appels AJAX sur mon script:

Le premier stocke une valeur envoyé par l'appel ajax en GET, puis sur le retour de l'ajax j'appel une 2ème fois le script avec un paramètre lui demandant de récupérer la valeur précédemment stockée et de comparer avec le meme GET. Puis, je lui demande de stocker les temps de PUT, les temps de FETCH des valeurs, temps totals, les erreurs détectés.... et je lui demande aussi de stocker une chaine de 1 millions de caractères, ce qui créé des fichiers de sessions de 1.2Mo. Histoire de le soliciter encore plus, j'ai paramétré sharedance pour que les sessions expirent au bout de seulement 60 secondes, ce qui provoque des "clean" plus souvent.

Avec ce test réel, on est monté à environ 900 sessions pour 1.2Go de données sur la partition tmpfs de 2Go.

Sharedance cpu-network

Ce graph représente à droite l'utilisation CPU, à gauche le traffic réseau. En haut le serveur sharedance, en bas un des serveurs PHP. On voit nettement quand j'ai arrêté le test à 17:13. On peut constater que le serveur sharedance encaisse 300Mb/s entrant + autant en sortant, sans broncher ! La charge du serveur n'a jamais atteint 1, le serveur ayant 4 coeurs (bi-dual). Via un top, je constate aussi que sharedance utilise de manière homogène les 4 coeurs.

Les petits pics rouge sur le graph CPU de sharedance sont du à un cron qui se lance pour analyser les temps mini, avg et max stockés dans les sessions.

Les dernières stats :

  • Sessions: 1082
  • put mini: 0.000153
  • put avg: 0.019551
  • put max: 0.260032
  • fetch mini: 0.003848
  • fetch avg: 0.041149
  • fetch max: 0.525085
  • total min: 0.001805
  • total avg: 0.343540
  • total max: 0.981712

Je n'ai pas eu le temps de faire un beau graph excel :) On voit qu'il a mis au maximum 0.9 seconde pour stocker puis récupérer 1.2Mo de données, auquel il faudrait soustraire les temps d'accès aux pages PHP x2 !!

Le choix est fait !

Les gestionnaires de sessions PHP

Actuellement, pour les sessions, nous utilisons un gros serveur et MySQL avec des tables en HEAP pour stocker les sessions. Problème, ces tables ne supportent pas les types BLOB et TEXT, ce qui implique d'utilise un champ VARCHAR, limité à 255 caractères, on atteint très vite cette limite.

Je suis donc à la recherche d'alternatives, sachant qu'on va stocker plus d'informations pour éviter au maximum les cookies, et que les performances requises sont importantes: aujourd'hui environ 2000 requêtes de sessions / secondes, demain ce sera bien pire à cause du web 2.0.

MySQL Cluster

MySQL n'est pas encore sortie en version stable en 5.1, version nécéssaire pour avoir un MySQL Cluster. Avec tous les problèmes que l'on rencontre avec 5.1 (enfin, uniquement les nouvelles fonctionnalités), le temps de mise en oeuvre, le coût des serveurs, cette solution est fortement compromise. D'autant plus que MySQL n'utilise pas sa propre solution pour ses propres besoins...

Zend Cluster

Alléchant sur le papier, mais beaucoup trop cher ! Ils vont devoir s'aligner pour espérer continuer à en vendre...

memcached

http://www.danga.com/memcached/

Comme stipulé à plusieurs endroits dans la doc, memcached est un serveur de cache avant tout. Ce qui veut dire perte de données en cas d'arrêt du démon. Il a été prévu pour faire du cache, et le fait d'ailleurs très bien. Son modèle cluster est orienté scalability et pas du tout redondance ni failover. Admettons que nous avons 3 serveurs memcached en cluster, A B et C. A chaque requête PHP en écriture (ajout, remplacement d'une session), le client se connecte à tous les serveurs, créé une clef en fonction de ces serveurs, et choisis un des serveurs: B. Seul B aura la valeur pour cette clef. La requête suivante, en lecture, veut lire cette clef, le client PHP se connecte aux 3 serveurs, génère la clef, et va chercher la valeur sur B. Très bien, on répartie la charge sur ces 3 serveurs, et la mémoire n'est pas gaspillé car les données ne sont pas duppliqué. Ainsi, si B tombe, on perd uniquement les données de sessions de ce serveur, on déconnecte donc seulement 1/3 des utilisateurs. Seulement voilà, c'est pas aussi beau. Si un noeud tombe, la liste des serveurs dans le pool change, et le client va regénérer toutes les clefs !! En d'autre terme, si un noeud tombe, on perd tout le cache ! On se retrouve donc avec autant de POF (Point Of Failure) que de serveurs. Dropped.

memcachedb

http://memcachedb.org/

Reprenant le moteur de memcached, le principe est différent, et cette fois le but n'est pas de faire du cache mais de stocker des données persistentes. En mode cluster, on a un fonctionnement identique à MySQL: un noeud est maitre, les autres noeuds répliquent et peuvent être accédé en lecture. Les performances sont là, leur benchmark indique atteindre 20000 écritures / secondes, et 45000 lectures / secondes, ce qui est amplement suffisant. Mais le principe du single master to many slaves est genant: il m'arrive régulièrement de retirer un serveur de la production, pour le mettre à jour, le restaurer, ou en cas de problèmes hardware... et si c'est le master qui a un problème ? on doit créer un autre master, et changer la config des slaves afin qu'ils répliquent leurs données depuis un autre master ! Dropped.

Sharedance

http://sharedance.pureftpd.org/

Ce logiciel a été créé pour cet usage et uniquement pour cet usage. Tout comme memcached, il excèle dans son travail. Tous les commentaires que j'ai pu trouvé sur le net en font l'éloge, et surtout on retrouve tout le temps "Ca n'a jamais planté". Un utilisateur atteint 200Mbps x 2 sur un seul serveur, époustouflant ! C'est la solution quasiment idéal... et oui, le soucis, c'est que c'est un SPOF ! Si ce serveur tombe, on n'a plus de sessions. Alors on pourrait implémenter un 2ème serveur avec Heartbeat, mais ce 2ème serveur n'aurait pas les données, en cas de crash on déconnecte alors tout le monde. Sharedance reste pour l'instant la meilleur solution, même si je ne l'ai pas encore testée, ça ne saurait tardé. Il manquerait une réplication type DRBD sur une partition tmpfs, pour allier performance et failover.

mcache

http://www.mohawksoft.org/?q=node/8

mcache semble le produit idéal, sur le papier. Il stock les données en ram et les copie (si besoin) sur disque régulièrement, possède un garbage collector pour supprimer les sessions périmées, et fonctionne en environnement distribué: un mcache par serveur PHP. Il faut que je le mette en place avec plusieurs noeuds, et vérifier les points suivants : si un noeud tombe, que se passe t'il ? Il faut aussi valider les performances.

Je vais donc créer plusieurs images Xen 32bits afin de tester mcache, et en parallèle tester sharedance. La suite aux prochains billets !