Shinken : la notion de pool, ou comment pousser encore plus loin l’architecture

Posted in Nagios by Nap on October 29, 2009 2 Comments

L’illumination du jour

Bonjour,

Hier j’ai eu tout le temps de pousser l’architecture de Shinken plus loin que je ne l’avais fait jusqu’alors. En effet, elle permet dans sa forme actuelle d’avoir un point unique d’administration de plusieurs ordonnanceurs, pollers, reactionners et brokers. Les hôtes sont dispatchés sur les ordonnanceurs, les services suivent, les satellites (poller/reactionner/broker) tapent sur tous les ordonnanceurs. C’est implémenté, et le pire, c’est que ça fonctionne. Tout le monde est content.

Tout le monde? Non. Un petit village d’irréductibles gaul… oups, je m’égare…

Tout le monde? Non. Imaginons un peu qu’un administrateur ait une infrastructure distribuée sur plusieurs continents (un quelconque rapport avec l’infra de l’auteur est fort plausible…). Avec l’archi de Shinken actuellement, si l’administrateur a mis deux ordonnanceur : un a Bordeaux et un à Shangaï (toujours par le plus grand des hasard hein…) et de même un poller sur Bordeaux, et un sur Shangaï, les pollers tapent sur les deux ordonnanceurs, et pour ceux qui n’ont pas le grand bonheur d’avoir un site à shangaï, autant vous dire que les lignes internet sont plutôt… bon disons que c’est aléatoire pour rester poli. De plus, un hôte va se voir affecté sur un ordonnanceur ou un autre sans pouvoir influer dessus.

Bref, Shinken, dans son état actuel, est pratique pour avoir de la haute dispo, répartition de charge et performance mais pour un site unique. Et là vous me voyez venir à des kilomètres : la gestion des sites.

Un pool, des pools

Alors on va utiliser un nom plus général qu’un site (après tout ça peut être une séparation plus organisationnelle que géographique) : un pool. (A ne pas confondre avec les pollers donc).

Un pool est un groupe de ressources indissociables auquel vont pouvoir être rattachés des hôtes ou des groupes d’hôtes. Une telle association sera unique, un hôte ne pourra se trouver que dans un pool donné et il faudra que ses parents soient dans le même pool (sinon le découpage de conf et le dispatchign ne sera pas content). Si ces derniers n’ont pas de pool désignés, il hériterons de celui-là.

Un pool est donc un groupe de schedulers, pollers, [reactionners], [brokers] (les deux derniers sont optionnels). Dans un pool, les pool vont se connecter à tous les schedulers du pool.

Un pool peut contenir un autre pool. Ceci ne change rien pour les ordonnanceurs/pollers, ceux-ci ne s’adressant qu’aux ordonnanceurs du même pool. Les hôte d’un pool ne seront dispatchés que sur les schedulers du pool, pas de ses fils. Là où une hiérarchie de pool devient utile concerne les reactionners/brokers : ils sont associés à un pool, mais si ce dernier contient d’autres pools (qui eux même en contiennent d’autres etc etc) et bien les reactionners/broker vont chercher les infos sur tous les ordonnanceurs de la hiérarchie de pool.

En fait, cette notion de satallites qui peuvent atteindre les sous-pools devrait être paramétrable, genre une option acces_inner_pool avec comme valeur par défaut les pollers a 0, et les reactioners/broker 1. Si après l’administrateur veux le changer pour décloisonner/cloisonner, libre à lui.

Il faut bien retenir une chose : un seul Arbiter (et son spare) et une seule conf, quelque soit le nombre de pools que vous avez. Ah une autre chose : pour l’instant rien n’est implémenté! Mais bon ça ne devrait pas être trop méchant je pense.

Au secours, je comprends rien!

Pas clair? Oui je m’en doute un peu, avec mes pools, sous-pool, pollers et schedulers.

En résumé, vous mettez un hôte ou un groupe d’hôte dans un pool. Celui-ci est un ensemble de ressources pour superviser vos hôtes et les services qui y sont raccrochés. Vous pouvez enlever ou rajouter des ressources au pool sans avoir à changer la conf des 30K hôtes que vous avez patiemment configuré car vous avec rajouté un ordonnanceur ou un poller de plus dans le lot.

Bref, le pool est une facilité pour gérer ses ressources. Si vous n’avez qu’un petit site gérable par un ordonnanceur/poller/reactionner/broker, pas la peine de vous embêter avec un pool, par défaut shinken en créera un pour vous à la volée et vous n’en entendrez même pas parler :)

Dessine moi un diagramme

Des diagrammes, c’est encore mieux que toutes ces explications :)

Imaginons que l’on a deux environnements distribués un peu partout dans le monde. Dans un cas, on souhaite un cloisonnement total des continents. Dans un autre, on accepte que les réactionners et brokers soient communs à tous les ordonnanceurs du monde (oui, rien que ça :) ).

Les diagrammes

Voici le cas isolé :

shinken-architecture-isolated-pools

Et le cas plus communs avec les réactionner/broker de communs :

shinken-architecture-global-poolComme vous pouvez le voir, les éléments sont raccrochés à un seul pool. suivant l’héritage qu’on leur a donné, ils utilisent les ordonnanceurs des sous-pool ou non.

Et dans la conf, ça donne quoi?

Voici ce que ça devrait donner pour le second cas :

define pool {
pool_name    All
pools         Europe, US, Asia
}
define pool{
pool_name    Europe
pools                Paris
}

(je ne sais pas encore si c’est bien utile de forcer la définition des autres pools même s’ils n’ont qu’un nom…).

define scheduler{
scheduler_name       sched Paris
pool                                 Paris
}
define reactionner{
reactionner_name   reactionner-maitre
pool                        All
}

Et dans les hôtes :

define host{
host_name         serveur-paris
pool                       Paris
[...]
}

Pour ces derniers ce paramètre sera géré par l’héritage comme toutes les propriétés des hôtes.

Ce qui est susceptible de changer

Il me reste quelques petits points à voir : doit-on faire le lien entre les schedulers/pollers/reactionners/broker et les pools au niveaux du define des pools, ou bien comme ci-dessus au niveau des éléments? Les deux? Mais quoi faire en cas d’incompatibilité des deux types de configuration? Je prends tout commentaires :)

Shinken : dispatch des commandes externes

Posted in Nagios by Nap on October 24, 2009

Des commandes importantes

Nous avons déjà vu le dispatch des configurations vers les schedulers et les satellites, regardons désormais comment se passe l’envoi de commandes externes par le client. Dans la philosophie Shinken, celui-ci n’a besoin d’envoyer ses ordres que d’un seul endroit, à côté de l’Arbiter.

Il faut séparer les commandes en deux catégories :

  • les commandes globales à tous les ordonnanceurs;
  • les commandes spécifiques à un élément (host/service/contact).

En fait une partie des deuxièmes commandes est en fait globale : les contacts sont partout et les commandes les concernant sont envoyées partout.

Comment shinken les dispatch

En fait ce n’est pas sorcier. Pour chaque type de commande Shinken sait s’il elles sont globales ou non. Pour les globales, il ne se pose pas de question, il envoie à tout le monde et voila.

Pour les spécifiques, il faut qu’il trouve quel est l’ordonnanceur en question. Il cherche pour cela dans les N configurations l’élément impacté (hôte ou service). Une fois trouvé, il sait à qui envoyer l’ordre et il le fait.

Une fois les ordres reçus, les ordonnanceurs n’ont plus qu’à les appliquer.

? Vous voulez un diagramme? Bon ok, voici un exemple avec une commande spécifique et une globale.

shinken-external-commands

Shinken : le dispatching des configurations et les spares

Posted in Nagios by Nap on October 23, 2009 4 Comments

Rappel sur les daemons et les configurations

J’ai déjà évoqué le fait que Shinken utilise plusieurs daemons qui ont chacun leur rôle. Le maître de tous est l’Arbiter qui lit la conf, la découpe et l’envoie vers ses petits camarades. Bien sûr, les satellites comme les pollers ont besoin de connaître l’adresse des ordonnanceurs. Ces derniers ont la responsabilité de l’ordonnancement de la supervision. La perte d’un d’entre eux peu être embêtante : une partie des hôtes ne seront plus surveillés!

C’est pourquoi Shinken utilise un système de spare : des daemons seront lancés mais non actifs. Ils ne se verront affecter une configuration et donc une responsabilité que si un daemon maître meurt. Typiquement un placement de ces spares sur la machine de l’Arbiter peut être utile, il y a peu de chance qu’elle perde le lien avec elle même.

Regardons un peu le dispatching des configurations vers les ordonnanceurs et ce qui se passe lorsqu’un ordonnanceur n’est plus disponible

Dispatch des configurations

L’arbiter lit la configuration globale de l’administrateur, il la coupe en morceaux (autant que l’ordonnanceurs NON spare). Le dispatcheur (une Classe dans l’Arbiter), l’envoi vers les ordonnanceurs. Puis il créé une configuration particulière avec juste les adressess des ordonnanceurs à destinations des satellites comme les pollers ou le broker. Et hop, tout le monde est content.

Ca se résume en un diagramme:

shinken-conf-dispatching

Lorsqu’un ordonnanceur tombe

Personne n’est parfait, les OS non plus. Une machine ca peut tomber, un réseau aussi. Bref, les daemons ne seront pas toujours joignables. C’est pour cela qu’on peut définir des spare qui vont reprendre le flambeau des vérifications. Pour l’instant, seul les ordonnanceurs peuvent avoir un spare, mais ca ne devrait pas tarder pour les satellites car ce n’est pas bien différent.

L’Arbiter vérifie régulièrement que tout le monde est vivant. Si un ordonnanceur est déclaré mort alors qu’il avait la responsabilité d’une configuration, il envoie la configuration vers un spare disponible.Il met à jour les informations des satellites pour qu’ils prennent en compte cette nouvelle disposition.

Un cas intéressant arrive lorsque l’ordonnanceur n’était pas disponible à cause d’une perte réseau (vous savez, cette grande variable aléatoire :mrgreen: ). Il était encore vivant mais on ne le voyait plus c’est tout. Si la conf a été envoyé à un spare, on a un problème : deux ordonnanceurs avec la même conf. Pour l’instant il est demandé à l’ordonnanceur maître de gentiment arrêter son ordonnancement et d’attendre une nouvelle conf. Dans l’avenir, une solution plus élégante sera de demander plutôt au spare de lâcher la main, car il y a de fortes chances que ce dernier aient moins d’informations que le premier.

Ca se résume en un diagramme :

shinken-scheduler-lostEn bref

Imaginez un même système en C (juste le dispatching et la gestion des spares). … Ca y est vous le voyez? Compter le nombre de lignes que ca demande. … Combien alors? Tout ça? Maintenant regardons combien ce prends dans Shinken : dispatcher 200 lignes, satellitelink 100 lignes (et ca va fortement diminuer), satellite pour la gestion de la conf : 50 lignes. Ah oui,  le tout avec 30% de commentaires :-)

Le Python c’est bon.

Patch Nagios : SSL pour Ndo

Posted in Nagios by Nap on October 16, 2009 2 Comments

J’avais travaillé sur 3 patchs pour Nagios et je n’en ais évoqué ici que 2 pour la bonne raison que c’étaient les seuls à être intégrés. Et bien en fait c’est inexact : le troisième l’a été aussi :)

Ce patch permet d’établir une connexion chiffrée entre le module ndomod et ndo2db. En effet, avant tous les paquets étaient envoyés en clair sur le réseau. Ceci a beau être de la supervision, il y a tout de même le nom de toute nos machines, c’est assez embêtant. Avec le patch que j’ai proposé (commit sur http://nagios.git.sourceforge.net/git/gitweb.cgi?p=nagios/ndoutils;a=commitdiff;h=9d9dcccab9690c896a7f1c3d2015064430c5157a par Hendrik Baecker) il y a une option de plus sur ndomod.cfg et ndo2db.cfg : use_ssl.

Par défaut elle est à 0 pour un soucis de compatibilité. Une fois passée à 1, la communication sur socket (uniquement celle en réseau, pas cette sur le socket unix) est chiffrée.

Je n’ai pas réinventé la roue, j’ai emprunté le code à NRPE tout simplement. Je l’ai juste un peu adapté et mis au bon endroit.

Et voila, je suis dans le fichier THANKS de ndoutils maintenant :)

Shinken : 100K checks/5minutes

Posted in Nagios by Nap on October 13, 2009

Je viens de faire un test sur une “petite” machine : un Xeon 5140 (4coeurs, 3.1Ghz). J’ai réussi à dépasser la symbolique limite des 100000 (oui oui, 100K) checks en 5 minutes. J’ai un peu triché pour cela : j’ai exporté le broker et la base MySQL sur un autre serveur. J’arrive à un trafic à 50Ko/s entre le scheduler et le broker, ce qui est raisonnable vu le nombre de checks ;)

Petite preuve avec un ninja situé sur la machine avec la base :

100kPour ceux qui sont curieux : oui, Ninja rame un peu avec autant de services à gérer, mais cela reste acceptable ;)

Cette configuration sera de plus la plus répandue sur les gros environnements avec plusieurs schedulers. Pour rappel, sur cette même machine je plafonne à 10K checks avec un Nagios non tuné, 30K en le tunant un max.

Moi je ne dirais qu’une chose : merci Python, mettre en place un pool de process est d’une simplicité monstrueuse. Maintenant, reste à faire de même avec Nagios (et de convaincre ses auteurs…). Qui sait, la barre des 200K sera peu être atteinte un jour?

Shinken : Les grandes lignes

Posted in Nagios by Nap on October 6, 2009 2 Comments

Il y a quelques temps j’ai présenté dans les grandes lignes mon proof of concept Shinken, le Nagios en Python. Et bien il a plutôt bien avancé depuis. En voici un état des lieux et une idée de là où il va.

Architecture générale

Shinken est pensé pour les environnements distribués. Il est bien sûr possible de faire tourner tous ses composants sur une seule et même machines. Les composants justement, parlons en.

Architecture de Nagios

Nagios est (quasiment) monolithique. Il lit la conf, la traite, ordonnance les checks, les lance ainsi que les actions qui en résultent (les notifications et les event handlers). Il exporte également des informations vers un daemon externe pour mise en base de données.

Lorsque l’on a un petit environnement, tout marche bien, c’est pratique et presque rapide. Le problème se pose avec les grands environnements : Nagios est capable de gérer facilement jusqu’à 10000checks/5minutes sur un serveur moyen de gamme. Avec du tuning on peu arriver à 30000, mais gère plus, même en rajoutant pleins de CPU sur le serveur. La mise en place des environnements distribués n’est pas triviale (la preuve, elle demande un chapitre à part entière dans mon livre :) ). La tâche est encore plus hardue pour les environnements distribué ET hautement disponibles. Cette dernière exigence est très complexe à gérer si on ne veux pas perdre trop en performances, voir pas faisable du tout pour les très gros environnements sauf à mettre une armée de serveurs.

C’est là que vient Shinken : mettre en place un environnement distribué hautement disponible facilement. Le côté facile doit venir aussi de la gestion de conf. Nagios a une gestion de la configuration impressionnante, mais qui nécessite un gros travail manuel lorsqu’il est question d’environnements distribués.

De même pour donner des ordres à Nagios, il faut passer par le pipe nommé nagios.cmd situé sur le même serveur. Pour un serveur ça va, mais pour une dizaine, se souvenir sur quel serveur Nagios se trouve l’hôte que vous voulez rescheduler devient un peu plus complèxe…

Pour résumer la situation, l’architecture de Nagios est la suivante:

nagios-architecture

Architecture de Shinken

Shinken propose une solution à ces problèmes : le découplage des rôles de Nagios. Ces rôles sont éparpillés sur différents processus. Voici le schémas global, le rôle de chaque élément sera précisé plus bas:

shinken-architecture

  • Arbiter : lit la configuration, la découpe en N partie et l’envoi vers les autres processus. Il lit l’unique fichier nagios.cmd de l’architecture, et transmet les ordres à qui il faut. Il est également le garant de la haute disponibilité et la répartition de charge.
  • Schedulers (nom de processus Shinken) : il lit la conf que lui envoi Arbiter. Il peux y avoir N schedulers, chacun avec ses propres éléments (hôtes/services). Il est en charge d’ordonnancer les checks, de les proposer aux autres éléments, récupère le retour des checks, et propose des notifications/event handlers si besoin qui seront lancé par des éléments externes.
  • Pollers : Il peux y en avoir autant qu’on veut. Ils récupèrent les checks auprès des schedulers, les lance et renvoi le retour aux scheduler en question. Il n’y a pas intelligence ici. Ils récupèrent des checks, les lancent, renvoient le résultat. Point barre.
  • Actionner : De préférence il n’y en a qu’un (et un spare). Il est en charge de lancer les notifications et les event handlers. Il fonctionne de la même manière que les pollers, mais il est à part car on préfère en avoir un et un seul qui fait les notifications (pour les problèmes d’acès aux serveur SMTP ou les flux RSS par exemple).
  • Broker : Unique avec un spare, Les schedulers exportent des informations dans des ‘broks’, des morceaux d’informations. Ils sont récupérés par le Broker qui en fait ce qu’il veut après, suivant les plugins qu’il a. Chaque plugin traite l’information comme il le veut. Les plugins actuellement développés sont l’export du fichier service-perfdata et l’export dans la base merlin. La base ndo ne devrait pas tarder, mais ca sera plus long que pour celle de merlin, car elle est vraiment mal fichue!
  • Bah c’est tout. C’est déjà pas mal non? :)

Les éléments de charge sont éclatés d’où le load balancing. L’arbiter est le garant de la haute dispo, il réparti les conf aux vivants, et envoi les conf des éléments morts aux spare si un membre actif vient à mourrir (bah ca peut arriver hein, personne n’est parfait). L’administrateur n’a pas à se soucier de quel scheduler va gérer son élément (hôte), l’arbiter va découper la conf pour lui de manière automatique, et en faire des paquets les plus équilibrés possible en terme de charge. Shinken tiens son nom de là d’ailleurs :)

La configuration

Qui dit nouveaux éléments dit nouvelle configuration. L’arbiter mis à part, chaque élément a un élément de configuration qui lui est dédié. Elle est de la forme (par exemple ici pour les scheduler):

define scheduler{

name     scheduler-main

address      192.168.0.1

port      7768

spare        0

}

define poller{

name      poller-main

schedulers     scheduler-main, scheduler-spare

address      192.168.0.1

port      7771

}

Ceci doit être donné à l’arbiter dans le fichier nagios.cfg, comme n’importe quel autre configuration d’éléments dans Nagios. Ceci va permettre à l’Arbiter d’envoyer les configuration et de gérer les liens avec les schedulers, pollers and co. Je n’ai pas encore prévu de configuration locale au poller and co. Mais à part le port d’ouverture, il n’y aura pas gand chose à configurer.

Je prévois de faire en sorte de créer automatiquement un élément en local s’il n’est pas défini dans la configuration, genre dans le cas de l’import d’une configuration existante sans avoir à la modifier.

Les performances

J’en vois déja arriver avec leur grands sabots : “c’est en python donc c’est tellement lent qu’on ne va pas pouvoir tester sur de vrais environnements”. Ca aurait été sacrément inutile si c’était le cas. Je n’aime pas trop perdre mon temps. Allons directement à la mesure dans de vraies conditions : serveur Xeon bi-coeurs 3ghz. J’ai utilisé une configuration générée tout comme dans le chapitre 9 de mon livre (quoi,vous ne l’avez pas encore lu?). La latence nous permet de savoir si le programme a assez de ressources ou non.

  • Nagios dans sa configuration standard a stagnée a 9500 checks/5min, avec du tunning poussé, 25000. Je n’ai pas encore fait les tests avec export en base de données avec ndo2db;
  • Shinken arrive à 50000 avant que j’ai eu à faire du tunning de code…Et l’export en base de données fait en prime, le tout sur la même machine bien sûr.

Il n’y a pas de secret ici : La charge de Nagios vient du lancement de nouveaux process Nagios qui doivent lancer les plugins et le fait de “reaper” les résultats dans des fichiers plats. Shinken utilise un pool de process (les pollers ont un pool de workers) donc pas de surcharge ici, et les pollers envoient directement les résultats des checks en mémoire (technique d’objets distribués de type Corba, mais en autrement plus simple à utiliser). Pas de fichiers à parser, beaucoup moins de charge. “Et voila”.

Par contre ce n’est pas parfait : le lancement de l’Arbiter est légèrement plus lent que Nagios pour la lecture de la configuration, mais rien de rédhibitoire. Je vois revenir les gros sabots pour la consommation mémoire : Oui, ceci consomme plus de RAM que Nagios. Nagios est vraiment bien optimisé sur ce point, Shinken est “seulement” 3 fois plus consommateur, genre 250Mo pour les 50000 checks. C’est tout à fait acceptable à mon goût.

Bref, c’est testable même avec des grands environnements. Et ca veut dire que l’on peut encore améliorer Nagios. Bon reste à faire la partie Worker en C. Je l’aurais bien prise chez Apache, mais question de licence, ça le fait pas je pense. Puis le code est .. complexe pour juste une gestion de worker, mais bon c’est le C hein…

Ce qui est déjà fait

Les fonctionnalités principales de Nagios sont déjà dans Shinken:

  • ordonnancement de Nagios (HARD, SOFT, etc)
  • gestion des périodes de temps Nagios (sauf les exclusions)
  • checks passif
  • gestion des dépendances
  • macros
  • vérification de la fraicheur des états
  • export des données de performances
  • export des données dans une base MySQL de type Merlin
  • la gestion du flapping
  • le cache de checks pour les dépendances
  • services volatiles (pour les logs)
  • gestion du fichier de rétention

Pas si mal hein?

Ce qu’il reste à faire

Avant de le présenter “officiellement” aux auteurs de Nagios, je tiens à ce que la gestion des spares soient complète. De même que l’export vers la base ndo. Après je le présente, avec dans l’espoir de voir les bonnes idées s’il y en a (comme le pool de process) intégrée dans Nagios si c’est possible. (Bon tout est possible, mais en C ça devient beaucoup plus long à faire… beaucoup plus long à faire même…et pourtant j’aime le C, faut pas croire).

Ah oui, il faut que je fasse une VM de type VirtualBox avec Shiken et Ninja pour l’interface. En fait plusieurs VM seraient mieux pour l’aspect distribué.