Dans cet article nous allons voir comment Ceph, le système de stockage objet à haute disponibilité et hautes performances, fonctionne et s'il est possible de le soumettre, sans danger, à quelques petites expériences. Nous verrons également qu'une expérimentation à grande échelle est menée au CERN.
Lorsque l'on confie ses données à un système de fichiers ou un système de stockage, réparti ou non, il faut avoir une certaine confiance dans ce système (les sauvegardes aident un peu). Pour avoir un peu confiance, il faut voir comment le système fonctionne en temps normal mais aussi par gros temps (en mode dégradé par exemple). De même je trouve qu'une bonne documentation et des commandes ou outils qui permettent de triturer le système augmentent la confiance que l'on peut avoir dans un système de stockage. Voyons donc quel degré de confiance nous pouvons accorder à Ceph.
1. Architecture
1.1 Haute disponibilité
Ceph est un système de stockage objet à haute disponibilité et hautes performances dont l'installation a déjà été expliquée dans GNU/Linux Magazine n°179 [1]. Pour le moment seuls les serveurs mon et osd (voir encadré) peuvent être plusieurs dans un cluster. Il est même très vivement recommandé d'avoir au moins trois serveurs mon (plus ne peut pas nuire) et le maximum possible de serveurs physiques exécutant un serveur osd par périphérique de stockage (les plus nombreux possibles).
osd, mon et mds sont des abréviations pour, respectivement, Object Server Daemon (c'est lui qui va enregistrer les données), monitor server (c'est lui qui va gérer le dispatch) et Meta Data Server (c'est lui qui gère les méta données des fichiers tels dates d'accès, de création, taille...). Pour plus d'informations reportez vous à mon article précédent [1].
Le serveur mds qui est utile à Ceph n'est, à l'heure où j'écris ces lignes, pas encore en version stable pour le support de multiples instances (d'après le site Web officiel du projet). Il n'est donc pas redondant (si le serveur mds est cassé, l'accès au système de fichiers CephFS est rendu impossible). Nous n'utiliserons donc pas ce système de fichiers en production (en tout cas, pas pour le moment).
Pour voir les configurations des différents serveurs on utilisera les commandes ceph osd dump, ceph mon dump et ceph mds dump. Ce qui donnera une sortie similaire à :
$ ceph mon dump
dumped monmap epoch 1
epoch 1
fsid a5bf6b38-02f4-43fb-bffc-9c932e98888e
last_changed 0.000000
created 0.000000
0: 192.168.122.77:6789/0 mon.ceph-mon
En tapant la commande ceph osd dump on se rend compte que les serveurs osd sont numérotés à partir de 0. Dans une configuration de production, on veillera à ce que le premier osd soit nommé 0 afin d'éviter toute confusion possible lors des interventions (ce qui m'est trop souvent arrivé).
Avec Ceph, la haute disponibilité n'est pas un vain mot. Par exemple, pour accéder à un objet, Ceph ne recherche pas sa position dans un index, il la calcule. En effet, si un index était utilisé il serait un point d'accès systématique (pour chaque objet) et donc un goulot d'étranglement et un ensemble de données très critiques (en cas de perte de l'index plus aucun objet ne pourrait être localisé !). La méthode de calcul de la position d'un objet se nomme CRUSH : elle est déterministe et pondérée ce qui permet une définition hiérarchique des serveurs de stockage osd. Cela permet de définir comment les serveurs osd peuvent tomber en panne et donc induit le placement des données pour permettre cela. Par exemple on pourra indiquer host pour que la panne d'un serveur physique n’entraîne aucune perte de données même s'il fait fonctionner plusieurs serveurs logiciels osd. On peut aussi indiquer datacenter par exemple ! Les valeurs possibles sont :
type 0 osd
type 1 host
type 2 chassis
type 3 rack
type 4 row
type 5 pdu
type 6 pod
type 7 room
type 8 datacenter
type 9 region
type 10 root
Avec les commandes ceph osd crush add-bucket pour créer les emplacements (par exemple : des racks, des salles, des datacenters ou des régions...) et ceph osd crush move pour déplacer les éléments dans les bons emplacements. Nos racks étant dotés de 3 PDU (Power Distribution Unit – ensemble de prises électriques, type multiprise) indépendants électriquement, on pourra définir des emplacements et ajouter les serveurs comme suit par exemple :
$ ceph osd crush add-bucket rack1-pdu1 rack
$ ceph osd crush add-bucket rack1-pdu2 rack
$ ceph osd crush add-bucket rack1-pdu3 rack
$ ceph osd crush add-bucket rack2-pdu1 rack
$ ceph osd crush add-bucket rack2-pdu2 rack
$ ceph osd crush add-bucket rack2-pdu3 rack
$ ceph osd crush move ceph-osd0 rack=rack1-pdu1
$ ceph osd crush move ceph-osd1 rack=rack1-pdu1
$ ceph osd crush move ceph-osd2 rack=rack1-pdu1
$ ceph osd crush move ceph-osd3 rack=rack1-pdu2
...
$ ceph osd crush move ceph-osd10 rack=rack2-pdu1
...
$ ceph osd crush move ceph-osd15 rack=rack2-pdu3
$ ceph osd crush move rack1-pdu1 root=default
$ ceph osd crush move rack1-pdu2 root=default
...
$ ceph osd crush move rack2-pdu2 root=default
Pour voir la totalité de la carte du cluster ceph il faut exécuter les deux commandes qui suivent. La première récupère la carte sous forme binaire, la seconde la transforme en fichier texte (/tmp/crush.txt) lisible par l'informaticien moyen :
$ ceph osd getcrushmap -o /tmp/crush.map
$ crushtool -d /tmp/crush.map -o /tmp/crush.txt
De manière plus rapide et assez lisible, l'arborescence du cluster est directement visible avec la commande ceph osd tree qui pourra produire un résultat similaire à celui-ci (tiré de l'exemple précédent) :
ceph osd tree
# id weight type name up/down reweight
-1 8.12 root default
-18 2.26 rack rack1-pdu1
-2 0.45 host ceph-osd0
0 0.45 osd.0 up 1
-3 0.45 host ceph-osd1
1 0.45 osd.1 up 1
-4 0.45 host ceph-osd2
2 0.45 osd.2 up 1
...
-22 1.81 rack rack2-pdu2
-14 0.45 host ceph-osd12
12 0.45 osd.12 up 1
-15 0.45 host ceph-osd13
13 0.45 osd.13 up 1
-16 0.91 host ceph-osd14
14 0.91 osd.14 up 1
Par la suite on pourra créer une règle nommée rack-pdu via la commande ceph osd crush rule create-simple rack-pdu default rack :
$ ceph osd crush rule dump rack-pdu
{ "rule_id": 2,
"rule_name": "rack-pdu",
"ruleset": 2,
"type": 1,
"min_size": 1,
"max_size": 10,
"steps": [
{ "op": "take",
"item": -1,
"item_name": "default"},
{ "op": "chooseleaf_firstn",
"num": 0,
"type": "rack"},
{ "op": "emit"}
]
}
Finalement il est possible d'associer cette règle à un ou plusieurs pool (ici pour le pool periph) : ceph osd pool set periph crush_ruleset 2. Une fois associée, cette règle prendra soin de distribuer les données au niveau « rack » de sorte que la perte inopinée de l'ensemble des serveurs osd se trouvant dans un « rack » ne pose aucun problème d'un point de vue données. Dans notre cas il s'agit d'un tiers de rack physique (un PDU complet).
On prendra soin de bien définir les bonnes règles et de les associer rapidement aux différents pools avant qu'ils ne contiennent beaucoup de données car cela peut conduire à de très grands mouvements de données dans le cluster (cela peut rendre le cluster indisponible pour la production normale !).
1.2 Les commandes
Il y a de nombreuses commandes pour dialoguer avec un cluster Ceph mais en temps normal nous en utiliserons principalement trois. La commande ceph que nous avons déjà vue, la commande rbd qui permet, entre autres, la gestion de périphériques et la commande rados plutôt portée sur la gestion des « pools ». Notons enfin qu'une librairie, la librados, fourni l'API aux différents langages de programmation (C, C++, Python…) pour accéder au cluster (voir la figure 1 pour un schéma complet de l'architecture).
Fig. 1 : Pile de l'architecture (Inspirée d'une image d'Inktank Storage).
Certaines des options de ces commandes sont redondantes mais donnent les résultats sous une forme différente (par exemple ceph osd lspools et rados lspools).
La cerise sur le gâteau est que l'ensemble des commandes peuvent effectuer leur sortie selon plusieurs formats (option --format=). Le format par défaut est plain (celui qui est utilisé dans cet article), mais il est possible d'utiliser json, xml, json-pretty ou xml-pretty. Ces deux dernières sont moins économes en octets mais plus lisibles par le commun des mortels.
1.2.1 Ceph
Il y a trois façons d'utiliser la commande ceph :
- en ligne de commande comme nous l'avons vu jusqu'à maintenant ;
- en mode interactif : invoquer ceph puis entrer vos commandes directement sans répéter la chaîne « ceph » à chaque fois (par exemple osd lspools) ;
- en observation des changements de l'état du cluster (à la manière d'un tail -f) : ceph -w.
La commande ceph --help donne l'aide complète (et là on se dit « mais pourquoi ai-je pris la pilule bleue ? »). On peut obtenir l'aide d'une commande spécifique en utilisant --help après celle-ci (par exemple ceph mon --help).
1.2.2 Rados et rbd
Pour les commandes rados et rbd il faudra indiquer le pool sur lequel portera la commande avec l'option -p (typiquement : rados -p metadata ls) ou directement comme on le ferait avec un dossier (par exemple : rbd create –size=1024 periph/harddrive).
rados permet de gérer les pools et les objets qu'ils contiennent tandis que rbd permet de gérer les images des machines virtuelles (ou de CD, DVD...) et les périphériques blocs pour une machine hôte.
1.3 Partitionnement logique (les pools)
Les pools permettent le partitionnement logique de l'espace de stockage du cluster. Il est possible d'indiquer quelques paramètres qui seront spécifiques à chaque pool :
- le nombre de réplicats pour les objets et le nombre minimal de réplicats acceptables pour continuer de fonctionner en mode dégradé (par défaut c'est respectivement 2 et 1) ;
- les propriétaires et les droits d'accès ;
- le nombre de groupes de placement (par défaut c'est 8) ;
- la règle CRUSH à utiliser (par défaut la règle 0) ;
Il est fortement recommandé de changer ces valeurs par défaut qui ne sont pas faites pour une utilisation normale. La formule pour calculer le nombre de groupes de placement idéal est la puissance de 2 immédiatement supérieure à (100 * nombre d'osd) / nb de réplicats (ce qui donne 128 pour notre cas particulier avec 2 réplicats et 2 osd). Voyons maintenant quelques commandes sur les pools.
La valeur par défaut pour la taille (le nombre de réplicats) a changé depuis la version firefly 0.80.x elle est maintenant de 3 car c'est la valeur constatée le plus couramment chez les utilisateurs de Ceph.
1.3.1 Lister les pools
Pour voir les pools déjà existants utilisez la commande ceph osd lspools ou rados lspools qui vous donnera un résultat similaire (au moins au début) :
$ ceph osd lspools
0 data,1 metadata
$ rados lspools
data
metadata
1.3.2 Créer un pool
Pour ajouter des pools à ceux qui sont créés par défaut il convient d'utiliser la sous-commande mkpool comme suit :
$ rados mkpool test1
successfully created pool test1
Si on veut spécifier le nombre de groupes de placement souhaités on peut utiliser une autre commande qui permet également la création d'un pool :
$ ceph osd pool create test2 100
pool 'test2' created
1.3.3 Détruire un pool
Pour détruire un pool il faut lui donner deux fois le nom à la commande et indiquer l'option --yes-i-really-really-mean-it. Ce sont des garde-fous pour éviter de détruire accidentellement un pool (il n'existe pas de commande ou d'option pour reconstruire ou récupérer un pool détruit) :
$ ceph osd pool delete test3 test3 --yes-i-really-really-mean-it
pool 'test3' deleted
1.3.4 Lister les objets d'un pool
Chacun des pools est destiné à stocker des objets. Pour voir quels objets sont contenus dans un pool il est possible d'utiliser la sous-commande ls (raccourci pour « list ») :
$ rados -p metadata ls
1.00000000.inode
100.00000000
100.00000000.inode
1.00000000
2.00000000
200.00000000
...
1.3.5 Instantanés d'un pool
Les instantanés d'un pool permettent de garder l'état de ce pool au moment précis où l’instantané a été pris, un peu comme une photographie. Pour créer un instantané (ou snapshot en anglais) nommé instantane1 du pool test1, on utilisera la commande mksnap :
$ ceph osd pool mksnap test1 instantane1
created pool test1 snap instantane1
Nous pouvons maintenant lister les instantanés disponibles grâce à la sous-commande lssnap de rados (cette sous-commande ne semble pas disponible avec la commande ceph osd pool) :
$ rados -p test1 lssnap
1 instantane1 2014.01.20 22:02:02
1 snaps
La destruction d'un instantané est similaire à sa création (d'ailleurs il est possible d'utiliser la sous-commande rmsnap avec la commande ceph osd pool) :
$ rados -p test1 rmsnap instantane1
removed pool test1 snap instantane1
La commande rbd propose également des sous-commandes pour créer, détruire et gérer des instantanés. Il s'agit ici d'instantanés réalisés sur les images des machines virtuelles (c'est à dire sur des objets d'un pool).
2. Dans les faits, ça se comporte comment ?
Tout d'abord, je dois dire que je n'ai pas porté une attention particulière à l'ordre dans lequel j'éteignais mes machines virtuelles lors de mes tests. Je n'ai jamais eu de problème lorsque je ré-allumais mes machines : le cluster était le plus souvent dans un état active+clean. Lorsque ce n'était pas le cas, le système a retrouvé un état active+clean assez rapidement.
Les tests de performance n'auraient aucun sens s'agissant de machines virtuelles stockées dans un PC de bureau sur lequel il n'y a qu'un seul disque dur. Cela d'autant plus que les volumes sont assez faibles et sont certainement très rapidement en cache (cette machine de bureau est plutôt bien fournie en mémoire). Je vous propose donc quelques essais sur les aspects comportement et fiabilité.
2.1 Ajouter des serveurs « monitor » au cluster Ceph
Pour faire de la haute disponibilité il faut au moins 3 serveurs monitor dans le cluster Ceph. En effet, il faut que puisse se dégager une majorité entre eux et cela est impossible avec 2 moniteurs seulement. Ici nous n'en n'avons qu'un seul et il faut donc en ajouter deux. Il faut préparer deux autres machines virtuelles (comme nous l'avons déjà fait dans les paragraphes précédents). Mes machines seront :
192.168.122.240 ceph-mon1
192.168.122.66 ceph-mon2
2.1.1 Méthode automatique
Pour le moment, utiliser ceph-deploy est une mauvaise idée : le cluster devient injoignable car le quorum ne peut-être atteint avec deux moniteurs et il semble que ceph-deploy n'arrive pas à terminer son ajout !
Si comme moi vous avez fait cette erreur et que plus rien ne répond vous pouvez vous en sortir en réinjectant la bonne carte (le monmap) directement dans votre premier moniteur (ici sur ceph-mon) :
# /etc/init.d/ceph stop
# ceph-mon -i ceph-mon --extract-monmap /tmp/monmap
# monmaptool --generate --set-initial-members --rm ceph-mon1 \\
--fsid a5bf6b38-02f4-43fb-bffc-9c932e98888e /tmp/monmap
# ceph-mon --inject-monmap /tmp/monmap
# /etc/init.d/ceph start
Dans mon cas, avant de récupérer l'accès à mon cluster ceph il faudra que je redémarre les serveurs ceph-osd1, ceph-osd2 et ceph-mds.
2.1.2 Méthode manuelle
Il faut donc ajouter les deux moniteurs à la main. J'exécute sur ceph-mon1 (faire de même avec ceph-mon2) les commandes suivantes :
# mkdir -p /var/lib/ceph/mon/ceph-ceph-mon1/tmp
# cd /var/lib/ceph/mon/ceph-ceph-mon1/tmp
# ceph auth get mon. -o mon.keyring
# ceph mon getmap -o monmap
# ceph-mon -i ceph-mon1 --mkfs --monmap monmap --keyring mon.keyring
# ceph mon add ceph-mon1 192.168.122.240:6789
Lorsque l'on tape cette dernière commande la sortie nous indique qu'il est parti chasser le moniteur... et plus rien ne fonctionne. Sur le premier moniteur ceph-mon j'ai récupéré la carte du cluster et je lui ai ajouté le troisième moniteur. J'ai ensuite indiqué aux deux nouveaux moniteurs leurs adresses publiques respectives :
# /etc/init.d/ceph stop
# ceph-mon -i ceph-mon --extract /tmp/monmap
# monmaptool --generate --set-initial-members --add ceph-mon2 192.168.122.66:6789 \\
--fsid a5bf6b38-02f4-43fb-bffc-9c932e98888e /tmp/monmap
# /etc/init.d/ceph start
# ssh ceph-mon1 ceph-mon -i ceph-mon1 --public-addr 192.168.122.240:6789
# ssh ceph-mon2 ceph-mon -i ceph-mon2 --public-addr 192.168.122.66:6789
Et voilà... la commande ceph mon dump exécutée sur chacun des moniteurs achèvera de vous convaincre que tous les moniteurs se connaissent.
Maintenant, pour les clients nous pouvons indiquer les différents moniteurs dans le fichier de configuration /etc/ceph/ceph.conf (les moniteurs, eux, utilisent en interne la carte monmap) :
[global]
fsid = a5bf6b38-02f4-43fb-bffc-9c932e98888e
mon_initial_members = ceph-mon
mon host = ceph-mon,ceph-mon1,ceph-mon2
mon addr = 192.168.122.77:6789,192.168.122.240:6789,192.168.122.66:6789
auth_supported = cephx
osd_journal_size = 1024
filestore_xattr_use_omap = true
N'oubliez pas de mettre à jour le fichier ceph.conf du dossier /home/dup/demo-ceph de la machine d'administration.
2.1.3 Finalement
Au vu de la difficulté que j'ai eue pour ajouter un moniteur, je recommande très chaudement d'installer directement trois moniteurs à la création du cluster. Au passage, il faut noter d'une part l'existence de nombreux outils pour éditer et triturer le cluster et d'autre part l'excellente documentation qui contient des paragraphes entiers pour la résolution de problèmes. Cela est rassurant lorsqu'on envisage un éventuel passage en production.
2.2 Arrêter brutalement l'un des deux osd
Pour les besoins du test, j’exécute le script suivant dans le répertoire exporté par le zfs (/testpool) : watch --interval=1 "ls -ls; date >>date.txt" puis je force l'extinction de la machine virtuelle ceph-osd2. Après environ 40 secondes le statut du cluster devient :
# ceph status
cluster a5bf6b38-02f4-43fb-bffc-9c932e98888e
health HEALTH_WARN 252 pgs degraded; 247 pgs stuck unclean;
recovery 329/658 objects degraded (50.000%); 1/2 in osds are down
monmap e6: 3 mons at {ceph-mon=192.168.122.77:6789/0,
ceph-mon1=192.168.122.240:6789/0,
ceph-mon2=192.168.122.66:6789/0}, election epoch 4,
quorum 0,1,2 ceph-mon,ceph-mon1,ceph-mon2
mdsmap e156: 1/1/1 up {0=ceph-mds=up:active}
osdmap e102: 2 osds: 1 up, 2 in
pgmap v23634: 252 pgs, 6 pools, 1145 MB data, 329 objects
2293 MB used, 27636 MB / 29929 MB avail
329/658 objects degraded (50.000%)
252 active+degraded
client io 21190 B/s wr, 14 op/s
Puis je redémarre la machine virtuelle. Lorsque celle-ci est démarrée, je regarde le contenu de mon fichier date.txt et il contient bien toutes les secondes. Le processus en cours n'a pas été affecté et le fichier est cohérent. Une phase de reconstruction a eue lieu (elle n'a pas affecté le processus non plus) et l'état du cluster est revenu à la normale :
# ceph status
cluster a5bf6b38-02f4-43fb-bffc-9c932e98888e
health HEALTH_OK
monmap e6: 3 mons at {ceph-mon=192.168.122.77:6789/0,
ceph-mon1=192.168.122.240:6789/0,
ceph-mon2=192.168.122.66:6789/0}, election epoch 4,
quorum 0,1,2 ceph-mon,ceph-mon1,ceph-mon2
mdsmap e156: 1/1/1 up {0=ceph-mds=up:active}
osdmap e104: 2 osds: 2 up, 2 in
pgmap v23646: 252 pgs, 6 pools, 1145 MB data, 329 objects
2308 MB used, 27621 MB / 29929 MB avail
252 active+clean
client io 3386 B/s wr, 2 op/s
S'agit-il d'un coup de chance ? Le fichier est si petit qu'il est, tout entier, dans la mémoire cache ? Pour éviter cela, je vais copier une image iso de la distribution 2013 de texlive (2,3 Gi) pendant la copie, je coupe la machine virtuelle ceph-osd2 : la copie se déroule sans accroche, même si les performances sont visiblement dégradées (en comparaison des performances lorsque les deux osd sont en fonctionnement). Redémarrons la machine ceph-osd2. La récupération se lance automatiquement et se déroule sans accroche jusqu'à son terme (alors même que la copie est toujours en cours). En revanche, les accès sont très lents et la copie indique parfois -stalled- ce qui n'est pas forcément bon signe. Toutefois, cette procédure s'effectue sur des machines virtuelles qui sont toutes stockées sur un même et unique disque dur dans une même machine physique et, vu que les auteurs de ceph indiquent que la procédure de récupération est gourmande en ressource, on pouvait s'attendre à ce résultat. En tous les cas les sommes de contrôle sha1 du fichier source et du fichier copié sont identiques !
2.3 Un osd tombe, vite montons un nouvel osd
Dans la vraie vie, les serveurs qui s'arrêtent ont souvent des problèmes qu'il est parfois difficile de résoudre en trois minutes. Une fois le serveur ceph-osd2 arrêté et que l'on est en mode dégradé, est-il facile de configurer et faire rentrer un nouveau serveur osd dans le cluster ?
Il faut préparer une nouvelle machine virtuelle et suivre la procédure du paragraphe « 2.6.5 Les serveurs de données (osd) » du précédent article [1]. Le cluster intègre le nouvel osd et commence la récupération de données. Lorsque celle-ci est terminée, ceph indique qu'il contient 3 osd et que 2 sont up et 2 sont in.
Ce n'est pas plus difficile d'ajouter un serveur osd quand le cluster est en mode dégradé qu'en temps normal !
2.4 Changement du disque dur dans l'osd en panne
Finalement, c'était le disque dur où sont stockées les données qui était cassé... On le remplace avec un nouveau disque dur tout neuf... (on simule cela en détachant, dans la machine virtuelle, l'image disque et en en ajoutant une nouvelle).
Redémarrons la machine. Rien ne se passe car il n'y a ni donnée, ni journal. Au point où nous en sommes il reste à réinstaller complètement le serveur. Avant cela prenons la précaution de supprimer l'ancien moniteur (ceph-osd2 qui était nommé osd.1 en interne) :
$ ceph osd crush remove osd.1
$ ceph auth del osd.1
$ ceph osd rm 1
On peut maintenant réinstaller le serveur osd. J'utilise l'option --overwrite-conf car le fichier /etc/ceph/ceph.conf est toujours là et sans cette option ceph-deploy refuse de l'écraser :
$ ceph-deploy disk zap ceph-osd2:sdb
$ ceph-deploy --overwrite-conf osd prepare ceph-osd2:sdb
$ ceph-deploy osd activate ceph-osd2:sdb
Nous voilà avec 3 serveurs osd et 3 serveurs mon (notez que j'ai arrêté le serveur mds pour libérer un peu de mémoire sur ma machine) :
$ ceph status
cluster a5bf6b38-02f4-43fb-bffc-9c932e98888e
health HEALTH_WARN mds ceph-mds is laggy
monmap e6: 3 mons at {ceph-mon=192.168.122.77:6789/0,
ceph-mon1=192.168.122.240:6789/0,
ceph-mon2=192.168.122.66:6789/0}, election epoch 4,
quorum 0,1,2 ceph-mon,ceph-mon1,ceph-mon2
mdsmap e8397: 1/1/1 up {0=ceph-mds=up:active(laggy or crashed)}
osdmap e392: 3 osds: 3 up, 3 in
pgmap v26450: 436 pgs, 6 pools, 8196 MB data, 2122 objects
7319 MB used, 37575 MB / 44894 MB avail
436 active+clean
Le serveur ceph-osd2 est maintenant nommé osd.3 en interne :
$ ceph osd tree
# id weight type name up/down reweight
-1 0.02998 root default
-2 0.009995 host ceph-osd1
0 0.009995 osd.0 up 1
-3 0.009995 host ceph-osd2
3 0.009995 osd.3 up 1
-4 0.009995 host ceph-osd3
2 0.009995 osd.2 up 1
La perte du disque où sont stockés les journaux (qui est généralement un SSD pour des questions de performances) n'entraîne pas nécessairement la perte complète des osd correspondants. En effet, grâce à une procédure [2] de reconstruction des partitions du disque, (à partir de l'UUID des journaux de chacun des osd) il est possible de repartir comme si de rien était !
2.5 Arrêter deux osd
Normalement l'arrêt de deux serveurs osd sur trois devrait me rendre un certain nombre d'objets inutilisables étant donné que mes pools sont configurés avec une taille de 2 et une taille minimale de 1 :
$ ceph osd pool get images size
size: 2
$ ceph osd pool get images min_size
min_size: 1
L'arrêt brutal non prévu de deux des trois serveurs osd laisse le cluster Ceph dans un état dégradé :
$ ceph health
HEALTH_WARN 291 pgs degraded;
145 pgs stale; 145 pgs stuck stale; 291 pgs stuck unclean;
2 requests are blocked > 32 sec;
recovery 3081/6686 objects degraded (46.081%); mds ceph-mds is laggy
On voit que 46% des objets ne sont plus accessibles. Comme mes objets sont probablement en cache dans mes machines virtuelles cette coupure ne semble pas avoir d'incidence sur les périphériques et notamment le système de fichiers ZFS : /testpool est toujours accessible ! Mais si on exécute la commande dd if=texlive2013.iso of=morceau bs=1M count=200 qui produira un fichier morceau avec les 200 premiers méga octets du fichier texlive2013.iso rien ne se passe (même au bout d'une minute la commande est toujours en suspend et aucune erreur n'est apparue...).
Démarrons les machines virtuelles qui étaient arrêtées. Dès que les deux serveurs osd sont démarrés et accessibles, Ceph entame une procédure de récupération des données et arrive rapidement à un état stable. La commande qui était « stoppée » a démarré toute seule et s'est correctement terminée :
# ls -lsh /testpool
total 2,6G
190M -rw-r--r-- 1 root root 200M juin 17 11:50 morceau
2,4G -rw-r--r-- 1 root root 2,4G juin 12 14:39 texlive2013.iso
2.6 Arrêt subit d'un serveur moniteur
Maintenant que trois serveurs moniteur existent, que se passe-t-il si l'un de ces serveurs s'arrête subitement ? L'existence du fait que l'un des serveurs moniteur est HS se note sur la deuxième ligne : 1 mons down et au niveau du quorum qui n'est plus constitué que de deux serveurs moniteur (ceph-mon1 et ceph-mon2) :
$ ceph status
cluster a5bf6b38-02f4-43fb-bffc-9c932e98888e
health HEALTH_WARN mds ceph-mds is laggy; 1 mons down,
quorum 0,2 ceph-mon1,ceph-mon2
monmap e6: 3 mons at {ceph-mon=192.168.122.77:6789/0,
ceph-mon1=192.168.122.240:6789/0,
ceph-mon2=192.168.122.66:6789/0},
election epoch 6,
quorum 0,2 ceph-mon1,ceph-mon2
mdsmap e16666: 1/1/1 up {0=ceph-mds=up:active(laggy or crashed)}
osdmap e415: 3 osds: 3 up, 3 in
pgmap v27896: 436 pgs, 6 pools, 4599 MB data, 1198 objects
7727 MB used, 37167 MB / 44894 MB avail
436 active+clean
client io 11480 B/s rd, 34736 B/s wr, 21 op/s
Sinon, toutes les opérations sont faisables sans aucun problème particulier :
# rbd -p periph --size 1024 create dd4
# rbd map periph/dd4
# zpool add testpool spare /dev/rbd/periph/dd4
# zpool status -v
pool: testpool
state: ONLINE
scrub: none requested
config:
NAME STATE READ WRITE CKSUM
testpool ONLINE 0 0 0
rbd/periph/dd1 ONLINE 0 0 0
rbd/periph/dd2 ONLINE 0 0 0
rbd/periph/dd3 ONLINE 0 0 0
spares
rbd/periph/dd4 AVAIL
errors: No known data errors
La copie d'un fichier ou l'installation d'une machine virtuelle se terminent sans aucun souci. Le retour du serveur moniteur est immédiat et, là encore, cela ne pose aucun problème.
2.7 Maintenance programmée
Lorsque l'on doit intervenir sur un serveur osd pour réaliser une maintenance, comme par exemple l'ajout de barrette mémoire, il est possible de prévenir le cluster afin d'éviter que les données ne soient automatiquement redistribuées :
$ ceph osd set noout
set noout
Dans le même ordre d'idée on peut demander à mettre en pause le scrub et le deep-scrub :
$ceph osd set noscrub
set noscrub
$ ceph osd set nodeep-scrub
set nodeep-scrub
On peut éteindre l'osd pour effectuer la maintenance programmée. À l'issue de la maintenance, lors de la mise sous tension du serveur, les scripts d'initialisation redémarrent automatiquement le service ceph :
$ ssh ceph-osd2 sudo /etc/init.d/ceph stop
=== osd.3 ===
Stopping Ceph osd.3 on ceph-osd2...kill 3148...kill 3148...done
$ ceph status
cluster a5bf6b38-02f4-43fb-bffc-9c932e98888e
health HEALTH_WARN 276 pgs degraded; 276 pgs stuck unclean;
recovery 3741/8218 objects degraded (45.522%); mds ceph-mds is laggy;
1/3 in osds are down; noout flag(s) set
monmap e6: 3 mons at {ceph-mon=192.168.122.77:6789/0,
ceph-mon1=192.168.122.240:6789/0,
ceph-mon2=192.168.122.66:6789/0},
election epoch 4,
quorum 0,1,2 ceph-mon,ceph-mon1,ceph-mon2
mdsmap e16511: 1/1/1 up {0=ceph-mds=up:active(laggy or crashed)}
osdmap e396: 3 osds: 2 up, 3 in
flags noout
pgmap v27615: 436 pgs, 6 pools, 15962 MB data, 4109 objects
7310 MB used, 37584 MB / 44894 MB avail
3741/8218 objects degraded (45.522%)
160 active+clean
276 active+degraded
Une fois la maintenance terminée, le serveur redémarré et le service ceph en fonctionnement il ne faut pas oublier d'enlever les drapeaux noout, noscrub et nodeep-scrub :
$ ceph osd unset noout
unset noout
$ ceph osd unset noscrub
unset noscrub
$ ceph osd unset nodeep-scrub
unset nodeep-scrub
Et voilà, c'est tout ! Évidemment, il faut veiller à ce que ce mode de maintenance soit le plus court possible et si possible ne pas éteindre le mauvais serveur osd !
2.8 Mise à jour du cluster (passage à firefly)
D'après la note de version il convient de migrer en premier les serveurs moniteurs puis les serveurs osd et enfin seulement le serveur mds. Sur chacun des serveurs moniteurs on change la version de ceph de « emperor » à « firefly » :
$ ssh ceph-mon sudo sed -i s/emperor/firefly/ /etc/apt/sources.list.d/ceph.list
Sur chacune des machines on réalise alors la mise à jour :
$ ssh ceph-mon sudo aptitude update
$ ssh ceph-mon sudo aptitude safe-upgrade
On réalise la même chose sur chacun des serveurs osd, sur le serveur mds puis sur les clients (ici ceph-admin et debian-virt2). Ensuite la documentation indique que si l'on utilise Ceph avec une version plus ancienne du noyaux Linux que 3.9, il convient de réaliser la commande suivante (debian wheezy est en version 3.2) :
$ ceph osd crush tunables legacy
Par acquit de conscience sur la machine debian-virt2 j'ai arrêté le service zfs-fuse, redémarré rbdmap et relancé zfs-fuse.
La mise à jour de la version « firefly » vers la version « giant » s'effectue exactement de la même façon et selon le même protocole.
3. Une expérimentation à grande échelle au CERN
Le CERN, l'organisation européenne pour la recherche nucléaire, possède les équipements scientifiques les plus imposants de la planète. De par leur gigantisme (aussi gros que des cathédrales) mais aussi de par les masses de données qu'ils produisent. En effet, quelques chiffres [3] en disent long : le LHC produit 1 péta octet de données par seconde d'expérience (40 millions d'images à 100 Méga pixels) qui une fois filtré génère 30 pétaoctets de données par an. Les données sont traitées au rythme d'un pétaoctet par jour.... Songez que les détecteurs du LHC ne sont pas les seules expériences du CERN !
Les systèmes de fichiers CASTOR et EOS recueillent les données des expériences et ils supportent un flot de données d'environ 10 gigaoctets par secondes. CASTOR fait environ 89 pétaoctets et EOS environ 20 pétaoctets. Un « petit » système de fichiers AFS stocke l'ensemble des répertoires personnels des 30 000 personnes liées au CERN. Il fait environ 300 téraoctets et contient plus de 2 milliards de fichiers.
Un « petit » cluster de test [4] a permis de réaliser la validation de Ceph comme solution de stockage pour le CERN. Il s'agit de 47 serveurs physiques de stockage comportant chacun 2 processeurs Xeon E2650 (8 cœurs à 2 Ghz soit 16 cœurs et 32 threads par serveurs), 64 Go de mémoire vive, une interface Ethernet à 10 Gbits connectée (sur deux utilisables), 24 disques de 3 téraoctets pour les données et 3 disques de 2 téraoctets en miroirs pour le système. Chacun de ces serveurs physiques fait fonctionner 24 serveurs logiciels osd (un par disque). Le cluster comporte également 5 serveurs physiques moniteurs dont la particularité est d'utiliser des disques dur SSD pour les serveurs mon. Un petit calcul rapide (24 disques de 3 téraoctets sur 47 serveurs) donne un volume utilisable de 3 384 téraoctets soit 3,3 pétaoctets !!
En effet, Le CERN est en train d'opérer un changement majeur dans son architecture informatique en passant à un système d'information virtualisé et redondant. Pour la redondance, un nouveau datacenter a été construit à Budapest. La plateforme choisie pour la virtualisation est OpenStack (elle est déjà en production). Ceph (le cluster de test est maintenant passé en production) réalise une partie du stockage pour cette plate-forme et comporte déjà plus de 500 volumes OpenStack Cinder, 15 millions d'objets, et environ 1000 images OpenStack Glance. Le tout occupe un espace de 60 téraoctets (180 sur les disques puisque la configuration du cluster stocke 3 fois les données) et supporte en temps normal entre 3000 et 5000 opérations par seconde.
Ce cluster est déployé via Puppet et les scripts d'Enovance [5] légèrement modifiés [6]. L'ajout d'un serveur est automatique (mon ou osd). Les disques des serveurs osd sont détectés, préparés, initialisés et insérés dans le cluster. Le fichier ceph.conf est auto-généré, seule l'opération de démarrage du cluster (service ceph start) reste manuelle afin de laisser la possibilité de tout vérifier avant.
Conclusion
Ceph réalise l'unification, la convergence et la virtualisation du stockage (et aussi le stockage de la virtualisation ;-)). C'est un changement de paradigme. Cet article et le précédent [1] ne sont qu'une toute petite introduction à Ceph et ce que nous avons vu est déjà impressionnant. Les quelques tests basiques qui ont été réalisés montrent sa robustesse et sa fiabilité. Le degré de confiance dans ce système de stockage me semble tout à fait compatible avec un usage en production (ce qu'est en train de faire le CERN). Maintenant c'est à vous d'aller plus loin dans la découverte du système et peut-être d'écrire un programme utilisant la librados ou l'API REST pour accéder directement au cluster Ceph fraîchement mis en œuvre via les interfaces S3 ou Swift ?
Je remercie ma femme et mes enfants pour leur patience infinie, Fanny pour sa relecture de la version alpha de l'article, Dan Van Der Ster et Mélissa Gaillard pour leur autorisation de publier un paragraphe sur le CERN (et leur relecture bienveillante de ce paragraphe).
Références et liens intéressants
[1] O. Delhomme, « Présentation et installation du système de stockage réparti Ceph », GNU/Linux Magazine n°179, février 2015, p. 32 à 38
[2] Récupération des données après la perte du journal : http://www.sebastien-han.fr/blog/2014/11/27/ceph-recover-osds-after-ssd-journal-failure/
[3] l'informatique au CERN : http://home.web.cern.ch/about/computing
[4] Une présentation de Ceph au CERN : http://fr.slideshare.net/Inktank_Ceph/scaling-ceph-at-cern
[5] Les scripts d'Enovance : https://github.com/enovance/puppet-ceph/
[6] Les modifications du CERN : https://github.com/cernceph/puppet-ceph/