Nodecast : passé, présent et avenir

Voici un moment que je n’avais pas trouvé le temps d’écrire un nouvel article sur nodecast. Depuis le dernier en juillet 2012, il y a eu énormément d’apprentissage et d’avancées, et même si ce projet n’est pas encore prêt à être utilisé en dehors de mon usage, j’ai bon espoir qu’il puisse être présentable d’ici quelques mois.

Passé

A l’origine j’avais débuté ce projet en tant que backend de mon projet de supervision système nodecast.net. Le frontend web étant en Ruby on Rails il m’a paru évident d’utiliser Ruby pour le backend. Il avait pour but de recevoir les payloads envoyées par mon client natif en Qt/C++ et qui contenaient les informations système (CPU, réseau, mémoire, etc). J’ai utilisé pour ce backend différents serveurs de file d’attente afin de le rendre asynchrone, propriété impérative à tout système ayant la prétention de tenir la charge. Il s’est avéré qu’avec juste quelques clients le backend montait rapidement en charge CPU et mémoire, la faute au langage script et aux innombrables couches de bibliothèques.

Il me fallait donc un langage compilé ce qui me permettait de plus d’éviter des bindings vers mongodb pas forcément optimisé et à jour. Utilisant Qt pour mon client desktop, je me suis lancé dans la réécriture du backend en Qt/C++. Ruby fut malgré tout intéressant car il me permit de développer rapidement un prototype.

La réécriture du backend se fit en plusieurs passes, en fonction des technologies que je testais et des contraintes qui s’imposaient. L’objectif étant d’avoir un minimum de dépendances vers des outils annexes et une stack très légère permettant d’exploiter l’ensemble sur un environnement matériel très léger ou ancien. Pour cela Zeromq supprime la dépendance d’un serveur de file d’attente tout en fournissant les mêmes propriétés, hormis la persistance disque. Je l’ai réglé en stockant les payloads dans mongoDB en sus des autres données.

Coté fonctionnalité, mon backend était typé en fonction du métier de la supervision. J’ai donc travaillé pour sortir le métier du serveur ncs vers des workers externe, cela afin de le rendre générique et facilement adaptable à des besoins différents. Ce travail pris tellement de l’ampleur que j’ai fini par percevoir plus d’intérêt. En effet si un backend générique asynchrone pouvait voir le jour, il permettrait de développer plus rapidement des logiciels, laissant le développeur se concentrer sur son cœur de métier. De plus cela permettrait de séparer l’IHM des traitements, ce qui procure l’immense avantage de développer facilement plusieurs IHM (desktop, mobile, web).

Les payloads envoyées sur l’API HTTP peuvent être du json ou bien des fichiers binaires. Dans ce dernier cas nodecast les stocke dans GridFS pour les transmettre immédiatement aux workers ou lorsqu’un worker en fait la demande. Comme usage on peut très bien imaginer envoyer à nodecast des fichiers vidéos pour les faire traiter à différents workers qui vont les transcoder, les dupliquer, les distribuer, etc. L’upload HTTP ayant ses limites, le service FTP permettra d’envoyer de gros fichiers avec possibilité de resume en cas de coupure.

Présent

A ce jour l’architecture est basée sur QtZeromq et mongoDB. J’étais parti sur le postulat d’offrir des services embarqués dans des threads, ceci pour simplifier l’installation et la configuration. C’était cependant une erreur de sécurité, une simple faille dans un service (FTP par exemple) aurait compromis l’ensemble du processus ncs de nodecast, ensuite cela aurait obligé de futurs contributeurs à utiliser Qt/C++ et à m’assurer de chaque ligne de code de leur service avant de l’intégrer.

Je travaille donc actuellement à externaliser ces services, cependant sans sacrifier en performance puisqu’il resteront en C/C++ ou dans un langage compilé. La difficulté étant de trouver un outil adapté à ces contraintes, j’ai fini par trouver le projet zerogw qui est un serveur HTTP en frontal et un backend vers Zeromq. Dans un simple fichier de configuration, ce serveur permet grâce à des règles de routage de transférer les requêtes HTTP vers le serveur nodecast. Les performances de zerogw sont incomparables avec ce que je pouvais espérer avec la libqxt et cela me permet d’installer ce service sur une machine dédiée, nodecast restant alors au chaud sur un serveur non routable depuis l’extérieur.

Les deux autres services HTTP sont l’IHM web d’administration et le tracker bittorrent. Pour cela j’ai trouvé l’excellent treefrogframework qui propose une stack façon Ruby on Rails en Qt/C++. Cependant puisque les services nodecast seront externes, au même titre que les workers, il sera tout à fait possible de les développer dans un autre langage tel que Go  qui possède des frameworks web (Revel, Gorilla) . Quant au service FTP, rien de plus simple de sortir celui que j’ai développé à partir de CftpServer.

L’idée finale étant que ces services communiquent avec nodecast via zeromq voir également via stdin/stdout comme les workers.

Futur

Nodecast, et plus précisément le serveur ncs, se présentera comme un HUB entre des workers et des services. L’utilisateur pourra l’utiliser via l’API HTTP et les différents services, et effectuer ses traitements métiers dans ses workers. L’enchaînement de ses traitements se fait via un workflow qu’il définit lui même. Le workflow est pour l’instant très basique puisque c’est une simple suite ordonnée (worker1 puis worker2, etc). A long terme je souhaite pouvoir conditionner les enchaînements par exemple si le worker1 renvoit true -> worker2a sinon worker2b, puis avec des conditions plus complexes (présence de fichier, date, etc) grâce au state machine framework de Qt.

Enfin le deux derniers services à finaliser seront le serveur XMPP et le tracker bittorrent. Ils permettront la communication et le partage de fichiers entre des utilisateurs depuis une interface native dédiée à cela, cette interface fait partie de mon prochain projet nodeseed.

ncs architecture

Nodecast : évolution vers un ordonnanceur opensource

Depuis mon dernier article sur nodecast en novembre 2011 j’ai depuis extraordinairement avancé. Historiquement Nodecast.net représentait pour moi un outil de monitoring système, via un client natif desktop et un backend asynchrone. J’ai rapidement décidé de rendre ce backend agnostique pour qu’il puisse être utilisé par tous types de projets. Le site du projet est donc Nodecast.org qui renvoie pour l’instant sur le compte github en attendant une page web de présentation.

Nodecast devient donc officiellement un ordonnanceur, même si ce terme est encore très pompeux face aux ténors propriétaires du marché. Je ne sais pas encore ce qu’il adviendra du projet de monitoring, ni si j’aurais le temps et l’envie de le migrer vers la nouvelle version de Nodecast. Côté desktop j’ai à vrai dire une idée de projet plus excitante :)

A ce jour Nodecast permet de gérer des workers qui reçoivent en paramètre un exécutable à lancer. Une fois enregistré, on poste en HTTP un JSON qui contient un workflow d’enchainement des workers, exemple :

curl -H "X-workflow: test" -d '{ "ls": 1, "rm": 2}' --user "user@email.com:16dsqqs" 

http://127.0.0.1:4567/workflow/create

Le premier worker qui s’exécutera s’appelle « ls » et le deuxième « rm », ils lancent bien entendu les commandes éponymes.  L’API renvoi un uuid à utiliser par la suite.

On poste ensuite le fichier binaire ou texte que l’on souhaite traiter, ici qxmpp-0.4.0.tar.gz :

curl -H "X-workflow-uuid: 66e994e8-1824-4604-bcf0-f1a321986888" 
-H "X-node-uuid: d4bd950b-7a04-4ff3-bf73-f840947d1171" 
-H "X-node-password: 69df62ab-4084-4e22-b788-6803c80c9931" 
-H "X-payloadfilename: qxmpp-0.4.0.tar.gz" 
-X POST --data-binary @qxmpp-0.4.0.tar.gz 

http://127.0.0.1:4567/payload/create

Les informations à fournir sur le node (le serveur qui POST) sont obtenues auparavant par la commande suivante :

curl -H "X-nodename: your-node-name" --user "email:token" http://127.0.0.1:4567/node/create

Le fichier est ensuite stocké par Nodecast dans GridFS, puis extrait dans le filesystème et son path transmis au premier worker. le retour de la commande (ls dans cet exemple) et transmis au deuxième worker, via Nodecast, qui la donne en paramètre à son exécutable (rm ici). Rien de transcendant comme exemple, mais grâce à l’architecture de Nodecast basée sur Zeromq, il est possible de lancer de multiples workers « ls » et « rm », les messages seront alors transmis à une instance aléatoire de chaque type de worker. La connexion entre les workers et Nodecast étant en TCP il est bien sur possible de répartir les workers sur une grappe de serveurs. Attention le fichier transmis à Nodecast étant stocké sur le file system, il faudra un partage NFS pour que les workers y aient accès en réseaux. Je souhaite cependant utiliser les fonctionnalités de stream de données de Zeromq pour la transmission vers les workers.

Mon prochain gros travail sera de terminer les workers de type service et leur éventuel communication avec les workers. Ensuite développer une API qui permettra de développer des IHM afin de connaitre l’état des workers, les piloter, etc …

Pour finir voici les derniers schémas côté utilisateur et développeur

NCS : un serveur applicatif

Lors de mon dernier article sur nodecast je terminais sur la possibilité d’y intégrer un serveur web pour remplacer le serveur ruby Thin qui exposait l’API HTTP REST. C’est maintenant chose faite, la libqxt via son module QxtWeb m’a permis de mettre en œuvre assez simplement un serveur web dans un thread du serveur ncs. J’ai migré tout le projet sur github, le code du serveur est visible ici : http_api.cpp. Ce how to m’a été très utile : How to create a simple webservice using qt and libqxt

Dans la lancée j’ai également intégré un serveur XMPP grâce à QXmpp  ce qui permet au client Geekast d’effectuer des push en XMPP. Il fonctionne également dans son propre thread. Outre la rapidité de ce protocole face à HTTP, cela va permettre aux clients Geekast d’avoir une socket persistante avec le serveur ncs et donc permettre à celui-ci de faire du push vers tous les clients connectés. Les usages restent à définir mais cette possibilité ouvre un grand nombre de portes. Par exemple proposer la possibilité d’agir sur tous ses clients geekast depuis l’interface web (kill de processus, etc). L’envoi par HTTP sera toujours présent dans le client, au cas où la connexion XMPP est impossible (firewall, etc).

L’autre avancée est sur le format de donnée entre le client et le serveur, qui migre du XML vers JSON via QxtJson. Ainsi le serveur ncs qui reçoit les payload en json peut directement les transformer en bson object, format binaire de MongoDB. Plus besoin de passer par un lourd parsing du xml et des conversions vers des tableaux pour en extraire les données. La ligne suivante montre la simplicité d’une telle conversion :

bson::bo m_bo_json = mongo::fromjson(json.toStdString());

Le serveur ncs est donc maintenant autonome, Ruby est uniquement utilisé pour l’exécution du frontal web en Ruby on Rails.

Pour finir, voici un schéma du fonctionnement interne du serveur ncs.

Nodecast : backend asynchrone avec zeromq

Depuis mon dernier article sur Nodecast il y a 6 mois, de nouvelles idées ont germés qui ont données lieux à une nouvelle et sans aucun doute dernière (on y croit) réécriture du backend.

En effet dans mon dernier article je me sers d’un logiciel propriétaire pour présenter ce que je crois être l’avenir de services sur Internet via des technologies en Peer to Peer. Dans cette architecture P2P je pense que l’auto-hébergement est alors crédible car les données sont répliquées et leur accès répartie.

C’est pourquoi j’ai à nouveau réécris le backend, car dans un contexte où chaque utilisateur est encouragé à s’auto-héberger, il est nécessaire que le logiciel soit léger, simple à packager et donc avoir le moins de dépendance possible. Lorsque j’ai découvert Zeromq j’ai décidé d’implémenter avec, la gestion de la file d’attente et de répartition des jobs pour remplacer le serveur Qpid. Tous les serveurs de file comme Qpid, RabbitMQ ou Redis sont excellent dans un environnement centralisé mais sont à mon avis une contrainte s’ils sont imposés dans un environnement décentralisé ou réparti.

Zeromq me permet de migrer dans le dispatcher la gestion des files, grâce à des sockets ZMQ de type PUSH/PULL gérées dans des threads. L’usage de Zeromq est in fine plus complexe puisque plus bas niveau qu’une API fourni avec un serveur de file, mais les possibilités sont quasiment infinie, voir les différents exemples dans de nombreux langages et surtout les nombreuses spécifications de protocoles. A noter que Zeromq ne permet pas de persistance disque comme le font Qpid ou RabbitMQ, cependant une implémentation du protocole Titanic le permettrait, et il n’est sans doute pas sorcier de les ajouter en option.

A propos de la persistance des messages, tout dépend du type d’application gérée, pour un système bancaire il ne peut y avoir de perte de message bien entendu. Au contraire, il me semble avoir lu que les dev du  backend de last.fm avaient choisi une technologie sans persistance pour privilégier la performance.

Schémas

Voici le schéma de la nouvelle architecture et du dispatcher

Description

Ce schéma décrit le fonctionnement interne du processus dispatcher. Les numéros en rouge indiquent le workflow suivi par un job. Même s’il n’y a plus de serveur de file dans l’architecture nodecast, le dispatcher permet d’en conserver les propriétés grâce d’une part aux threads et aux envois non bloquant :  la directive ZMQ::NOBLOCK indique à la socket zmq de ne pas attendre de confirmation du destinataire.

  1. L’API géré par Thin (externe au processus dispatcher) réceptionne les données XML envoyées par les clients nodecast. Le serveur Thin a bindé le port 5555 local, stocke le XML dans GridFS, construit un hash et le push dans la socket ZMQ_PUSH.
  2. Le thread Zreceive est connecté sur le port 5555 via une socket ZMQ:PULL. Avec ce protocole il peut y avoir plusieurs instance du dispatcher connectés, mais un seul recevra un même job. A contrario en ZMQ PUB/SUB tous les subscribers recoivent une copie du job.
  3. Zreceive a créé un ZMQ_DEVICE. Celui-ci relie la socket ZMQ_PULL vers une socket ZMQ_PUSH. Le device transmet tout ce que reçoit la socket de PULL vers la socket de PUSH. A noter que la socket ZMQ_PUSH est ici de type ZMQ_INPROC, ce n’est donc pas une socket TCP mais une zone mémoire partagée avec une autre thread.
  4. Un thread Zdispatch est connecté en ZMQ_PULL sur la zone mémoire inproc. Il désérialize les jobs reçu dans un objet BSON puis émet un signal Qt avec la charge créée.
  5. L’objet Payload reçoit la charge dans un slot. A noter que cet objet possède à une référence vers un objet Nosql ce qui lui permet d’interroger MongoDB. Dans ce cas il est impératif que le slot Payload ne soit pas appelé alors qu’il n’a pas fini ses tâches en cours. Pour cela le QObject::connect qui relie le signal de Zdispatch avec le slot de Payload doit impérativement posséder la directive  Qt::BlockingQueuedConnection. Payload découpe la charge reçue, effectue des traitements, sérialize des objects puis emet des signaux pour chaque worker.
  6. Le thread worker_push possède un slot par signal emit par Payload. Lors de sa construction il a bindé chaque socket ZMQ_PUSH par worker. Il transmet alors la charge en mode non bloquant ZMQ_NOBLOCK.
  7. Chaque worker ZMQ_PULL sur sa socket TCP dédié. Traite puis stocke dans MongoDB.

Les cadences.

Elles rythmes le workflow, s’il n’y avait qu’une seule cadence ce backend serait synchrone. Cependant on voit très bien plusieurs.

  1. Tout d’abord le serveur Thin, qui transmet le job et retourne aussitôt une réponse au client.
  2. Ensuite le thread Zreceive, retransmet à son rythme les jobs dans une zone mémoire
  3. Le thread Zdispatch lit la zone mémoire puis faire suivre les jobs dans des signaux Qt.
  4. L’objet Payload transmet les bouts de job dans des signaux vers des slots.
  5. Le thread worker_push envoie à chaque worker sa charge
L’entrée et la sortie du dispatcher sont non bloquante. Si ce dernier plante, le serveur Thin et le worker se rendront compte de rien. De plus contrairement à un serveur classique, les sockets zeromq permettent de lancer des clients même si le serveur n’est pas lancé. Si le dispatcher tombe il pourra être relancé sans problème et les workers recevront à nouveau leur jobs.

Conclusions

L’architecture du dispatcher n’est pas encore optimisée, par exemple les positions 4, 5 et 6 pourraient fusionner. Cependant le Proof Of Concept est concluant, ce backend devrait pouvoir s’exécuter correctement sur une machine recyclée. Une dernière tâche serait de migrer le serveur Thin dans un thread en Qt afin de simplifier et optimiser encore l’architecture, ou bien d’utiliser Mongrel2 à la place de Nginx et Thin comme me le conseillait un certain Zed Shaw :)
La cible d’obtenir un backend asynchrone brokerless étant atteinte la prochaine étape est l’intégration d’un worker qui permette la synchronisation en P2P des données du backend. L’objectif est qu’une instance Nodecast se synchronise avec l’instance d’un contact de l’utilisateur. Gros travail en prespective, les solutions sont nombreuses comme telehash mais qui ne fourni pas pour l’instant d’implémentation en C/C++, ou bien la lib bitdht utilisée par entre autre par retroshare.
Bonnes vacances (ou bon courage) aux lecteurs !

Nodecast : évolution d’une architecture web

Après ces quelques mois sans nouvelle, voici un article de mes dernières avancées sur mon projet Nodecast. En effet depuis mon dernier article Nodecast : architecture d’une application web il y a eu quelques changements d’implémentation.

Constat et évolution

Tout d’abord Gearman qui était idéal sur le papier s’est avéré très instable à l’usage, comme l’ont constaté d’autres développeurs sur la liste de diffusion. Ils ont l’air malgré tout d’avoir confiance en leur produit car ils vont ouvrir un service d’hébergement de files d’attente basé sur German : GearmanHQ.

Après quelques recherches je me suis finalement dirigé vers un serveur de files qui implémente le protocole AMQP ce qui permet de ne pas dépendre d’un serveur en particulier. Plusieurs serveurs libres l’implémentent, comme RabbitMQ (racheté par VMware), ActiveMQ ou Qpid.

L’autre problème est venu des workers qui traitent les données envoyées par le client desktop ( nodecast-gui ). Le code Ruby était tellement lent qu’il fallait parfois plus de 1 minute pour effectuer un traitement de parsing et insertion dans MongoDB. Je pense que le problème venait de la pile Ruby / Mongoid / Mongodb ruby driver et non de Ruby seul, mais il n’est tout simplement pas concevable que le worker qui intègre dans la base les processus utilisateur met plus ou moins 2 minutes pour effectuer 1 traitement avec une charge CPU maximale.

J’ai donc décidé de récrire les workers ainsi que le dispatcher, en C++ avec l’aide de Qt. Mes tests en développement sont passés à moins de 1 seconde sur le worker process, le plus lourd…. Evidemment l’effort de développement est certes plus conséquent mais les résultats sont largement payant pour que cet investissement technique paye.

Qpid quant à lui s’est pour l’instant imposé de lui même, car il est le seul à proposer une API C/C++ fonctionnelle. Des plugins permettent de lui ajouter une persistance sur disque, des fonctionnalités de cluster, du support SSL et XML en natif. Il fait d’ailleurs partie du coeur de la solution de Red Hat Enterprise MRG. Cette architecture représentée par le schéma plus bas reste tout de même à valider par l’épreuve du feu de la production.

Ingénierie

Néanmoins il est à mes yeux évident qu’un service web ayant pour objectif à moyen/long terme la prétention de monter en charge, se doit d’avoir une architecture scalable et cela dès sa conception. C’est toute la différence entre créer un site web et créer une architecture web, ou bien entre le développement logiciel et l’ingénierie logicielle. Cette dernière implique une réflexion sur les méthodes de travail, les outils à utiliser, qu’ils soient ceux utilisés par les développeurs que ceux à utiliser dans l’architecture;  la veille techno, etc. En somme tout ce qui permet d’optimiser sa productivité, l’architecture mise en place n’en sera que le reflet, réussi ou pas, de ces choix…

Voici un exemple du résultat de l’ingénierie logiciel avec cette présentation de l’architecture logicielle de la nouvelle version de LinuxFR.org l’un des plus gros site technique francophone.

Implémentation

Pour revenir à Nodecast, les workers utilisent les drivers natifs de memcached, pour invalider le cache dont la page a été mise à jour, de MongoDB et de Qpid, ce qui permet, en ayant aucune couche d’abstraction intermédiaire d’obtenir les performances maximales. Le framework Qt permet d’obtenir une certaine simplification du développement, grâce entre autre aux signaux, même si en effet la bibliothèque Boost intègre cette fonctionnalité.

J’ai développé nodecast-worker de manière relativement générique afin qu’il instancie la bonne classe worker selon le paramètre –worker-type fourni en argument :

nodecast-worker --memcached-ip=127.0.0.1 --memcached-port=11211 
--mongodb-ip 127.0.0.1 --mongodb-base=nodecast_prod --qpid-ip=127.0.0.1 
--qpid-port=5672 --worker-type=process

L’usage du serveur de file Qpid, permet outre le fait de rendre les traitements asynchrones, de monter un cluster de worker d’un même type sans développement particulier. En effet chaque worker s’abonne à la même file d’attente Qpid de type pub/sub (amq.topic). Une routing key appliquée par le dispatcher sert à taguer chaque message envoyé dans la file d’attente. Ainsi les workers filtrent les messages qui leur sont destiné, par exemple le tag worker.cpu pour le worker qui va traiter les messages qui contiennent les données de CPU envoyées par le client desktop nodecast-gui.

Comme il est possible de lancer plusieurs instances worker du même type, chacun des worker dépile la même file taguée ce qui permet de répartir la charge sur plusieurs processus, voir aussi de la répartir sur des machines physiques différentes puisque les workers utilisent des connexions TCP … !

Pour comprendre les rouages et le potentiel d’une telle architecture, je conseille la lecture de ces 2 excellents articles sur l’utilisation d’un serveur AMQP : Introduction à RabbitMQ – AMQP Partie I et Introduction à RabbitMQ – AMQP Partie II

Pour finir sur cet épisode, ce développement me met de plus en plus la puce à l’oreille sur la nécessité de développer un framework / service qui permettrait le développement rapide de workers, de les enchaîner, les monitorer en temps réel et de les administrer. Ce framework / service proposerait en outre l’accès à une multitude de bibliothèques et d’API vers des services externes afin de pouvoir implémenter n’importe quelle idée, de manière rapide, stable et scalable. Cela éviterait de devoir redévelopper la roue et de devoir gérer toutes les exceptions inhérente à l’utilisation d’API bas niveau (timeout, déconnexion, reprise, exception, start/stop, …). En quelque sorte un tarpipe OpenSource mais qui permettrait d’utiliser n’importe quel langage script ou langage compilé. Comme on dit, je dis ça, je dis rien :)

Workflow

Le schéma suivant montre l’architecture en court de développement du backend de Nodecast. On y voit les 3 paliers asynchrones par lesquelles transite le traitement d’un message.

nodecast architecture

Palier 1

Le premier palier nécessite 7 étapes.

  1. Le client nodecast extrait les données système de la machine, génère un XML et l’envoie par un POST (ajout) ou un PUT (update) HTTP.
  2. le serveur web Nginx fait suivre la requête vers le cluster web Thin.
  3. Thin exécute via rack le DSL Sinatra qui sert à créer simplement l’API REST de nodecast.
  4. Ce dernier vérifie dans MongoDB les droits d’accès (couple email / token) grâce à un auth basic request HTTP transmis par le client,
  5. Si l’autorisation a réussie, le code Sinatra stocke le XML dans le GridFS mongoDB, génère une collection de hash et transmet la charge dans queue dédiée au dispatcher.
  6. Le code sinatra génère un XML de réponse au client.
  7. NGinx le fait suivre au client, ce qui termine du point de vue utilisateur le traitement.

L’objectif de ce palier est d’être le plus minimaliste possible afin qu’une autre requête puisse être traité avec le moins d’attente possible. L’auth, la conception de la charge, sa transmission et la réponse au client sont malgré tout chacune nécessaire. Dans cette architecture asynchrone il n’est pas possible de signaler dans la même passe, la bonne fin du traitement à moins de revenir à une architecture synchrone non scalable… A vrai dire il n’est de toute manière pas nécessaire de le signaler puisque le service tourne en arrière plan sur le poste utilisateur.

Palier 2

La transmission de la charge utilise 2 canaux AMQP direct : dispatcher.update ou dispatcher.add. Le dispatcher est lancé selon cette ligne de commande :

 nodecast-dispatcher --mongodb-ip 127.0.0.1 --mongodb-base=nodecast_prod 
--qpid-ip=127.0.0.1 --qpid-port=5672
  1. Il écoute les 2 files d’attente puis lors de la réception d’une charge, il vérifie l’existence de l’hôte à mettre à jour si c’est un update ou bien créé l’hôte si c’est un ajout.
  2. Il injecte ensuite le XML extrait du GridFS dans un QHash Qt. Il sérialise ce QHash et envoie par AMQP la partie dédiée à chaque file de chaque worker concerné (hash[« network »] pour le worker network par exemple). En clair, le XML est découpé et chaque morceau est envoyé dans la file d’attente de chacun des workers.

Palier 3

  1. Tous les workers sont lancés et écoutent la file d’attente amqp.topic sur leur tag respectif (worker.cpuworker.loadworker.uptimeworker.networkworker.memoryworker.process).
  2. A réception d’un message, ils le sérialisent, mettent à jour la base de donnée puis invalident le cache de leur page web associée.
  3. Ils transmettent via syslog leurs statuts et leurs exceptions.

Avenir

A ce jour les workers process et cpu ont été réécrit et fonctionnent. Il reste l’implémentation des logs vers syslog ou AMQP afin de tracer les traitements des workers via des streams Graylog2.

Je souhaite remplacer Memcached par Redis pour profiter de ses très intéressantes fonctionnalités. Migrer le frontal web de Rails 2 vers la version 3. Stabiliser le client desktop et lui ajouter toutes les fonctionnalités de la lib SIGAR. Développer un client Android. Terminer le rework et Dominer le Monde :)

Nodecast : architecture d’une application web

Certains le savent peut-être, je travaille depuis quelques mois sur mon projet personnel Nodecast. Pour résumer, ce projet a l’ambition de proposer un outil de monitoring simple à mettre en œuvre mais aussi un outil de recensement façon Linux counter. Il n’a cependant pas pour objectif de concurrencer un logiciel de type Nagios. Outre le challenge du développement de la partie web, il y a également celui du client desktop en Qt, mais qui fera peut-être l’objet d’un futur billet.

Lire la suite

Une API asynchrone avec Gearman, Sinatra et mongoID

Même si Ruby on Rails facilite énormément la création d’une API REST il y a un grand intérêt à séparer le site frontal de l’API. Le site peut subir des montées en charge ou une coupure de maintenance qui occasionnerait de fait une interruption de l’API. Or s’il peut être gênant que le frontal soit interrompu, ça l’est encore plus pour l’API qui permet de mettre à jour des données ou de les fournir à une multitude de clients tiers. Dans ce billet je présente sans aller trop loin dans les détails, la création de cette API. Lire la suite