Post épisode: Mathias découvre Cloudfoundry et le PaaS

Je vous ai donc parlé de mon projet NSynapse (qui commence à dater), et je voulais faire le rapprochement avec un PaaS: CloudFoundry.

Ce qui m’a donné envie d’en parler, c’est l’état d’avancement des solutions PaaS aujourd’hui, mais surtout la présentation de l’architecture interne de CloudFoundry: Presentation:  Cloud Foundry: Design and Architecture
Je vous conseil de la voir avant de lire ce qui suit.

Elle montre à quel point CloudFoundry n’est pas juste un outil de déploiement et de monitoring, mais c’est pour moi un serveur d’application nouvelle génération: multi-techno, avec gestion de scallabilité horizontale, etc.

Ce serveur d’app, j’en ai rêvé pendant des années, et c’est aussi mon projet que je vais dévoiler dans l’épisode finale.

1. Conteneur d’application Web, mais pas que…

L’objectif de ce projet était de fournir un serveur d’application pour l’écosystème .Net, comme il en existe en Java (Tomcat/JBoss/Weblogic/etc.)
Cela explique l’Episode 2: Mathias découvre J2EE

Le but étant de faire quelque chose de cross-plateforme (compatible Mono) afin de ne pas dépendre de IIS et Windows.
Mais je voulais faire plus qu’un serveur Web IIS: je voulais que le serveur d’app contienne des applications de type Web mais aussi de type « Service Windows » ou « Daemon », ou encore de type « Tâche schedulée ».
Cela explique l’Episode 12: Mathias découvre Topshelf

On retrouve cette distinction dans de nombreux PaaS, comme Azure (Web Role et Worker Role).

2. Un mini PaaS

J’avais imaginé une solution qui soit un « bundle » à installer avec le serveur d’app, mais aussi plusieurs middlewares:

  • une base de donnée,
  • une MOM,
  • un cache,
  • etc.

L’inspiration m’est venu de par la succès de EasyPHP qui offre tout ce qu’il faut pour faire une application sans avoir à installer quoi que ce soit d’autre.
Cela explique l’Episode 1: Mathias découvre le PHP
Mais je voulais surtout démocratiser des middlewares comme les Queues ou les Caches en fournissant une implémentation par défaut.

Certains vont me dire que « Windows AppFabric » est la version « PaaS privé » de Windows Azure, et qu’il fournit déjà:

  • la possibilité de faire des applications Web (IIS)
  • la possibilité de faire des tâches schedulées ou des services windows
  • un MOM (MSMQ)
  • un cache distribué (anciennement Velocity maintenant AppFabric Caching)
  • une base SQLServer

Mais tout ça est trop lié à l’OS Windows, et je voulais quelque chose qui s’installe aussi sur les plateformes Linux.

3. Packaging et déploiement multi-instances

Un autre objectif était de pouvoir déployer une application facilement, sur plusieurs serveurs de manière transparente.
Je voulais faire quelque chose qui se rapproche des déploiements de « Processing Unit » avec Gigaspaces: on peut ainsi préciser le nombre d’instances, et le nombre de backup. Gigaspaces s’assure ensuite de déploiement ces instances sur les serveurs disponibles, et en cas de crash de l’un d’entre eux, Gigaspaces re-déploie l’instance qui a crashée sur un autre nœud du cluster.

Ce dernier peut être considéré comme un serveur d’App, car on peut y déployer:

  • des services, appelé Processing Unit, qui effectue des traitements dans le cache ou expose des services
  • des applications Web, des Processing Unit évoluées qui embarque un serveur d’App Jetty

Cela explique l’Episode 5: Mathias découvre Gigaspaces

En parlant de Gigaspaces, ils ne m’ont pas attendu pour faire leur propre PaaS: Cloudify est un PaaS qui exploite les mêmes briques techniques de gestion de cluster (déploiement de multiples instances, monitoring, Self Healing) et le plus beau c’est que c’est gratuit et OpenSource!

Mais quand on dit « multi-instances », ça ne sert à rien s’il n’y a pas un load-balancer au dessus.
Je ne savais pas lequel prendre, et je ne suis pas arrivé à ce stade du développement, ma solution étant mono-serveur pour le moment.

Pour pouvoir déployer, il faut aussi packager. Mieux encore, je voulais gérer une notion de dépendance entre les packages, en m’inspirant d’OSGI:

  • l’application A dépend de B en version 1.0
  • quand je déploie A, ça déploie d’abord B 1.0, le démarre, et passe au déploiement de A

Cela explique l’Episode 3: Mathias découvre Eclipse (et un peu OSGI)
Et l’Episode 4 : Mathias découvre Spring (et un peu plus OSGI)

Il m’a fallut alors inventer une API commune aux application (pour gérer le cycle de vie start/stop/restart) et un format de package (c’était avant qu’OpenWrap et Nuget existent).
J’avais étudié des solutions de « plugin », mais rien ne me satisfaisait.
En fait, ça se rapproche plus des notions de « Recipes/Cookbooks » qu’il y a dans les solutions comme Puppet, Chef ou Cloudify.

4. Binding de service transparent

Je ne voulais pas que cette notion de dépendance s’arrête aux applications .Net, je voulais l’étendre aux middlewares:

  • l’application A dépend de MySQL et de QPid

La notion de dépendance entre application .Net fonctionne, mais pas celle avec les middlewares.

Je voulais d’ailleurs m’abstraire de l’implémentation et avoir des dépendances de « services »:

  • l’application A dépend d’un service SQL et Amqp: les implémentations seront fournies par MySQL et QPid
  • l’application A dépend du WebService « Pricing »: l’implémentation sera fournie par l’application B

Cela explique l’Episode 7: Mathias découvre Unity+WPF+MVVM
Et aussi l’Episode 9: Mathias découvre MEF

J’ai bloqué sur le sujet car je ne voyais pas comment marier la notion de dépendance vers des services avec la notion de dépendance d’application.
En fait, pour abstraire la notion de service, il me fallait faire une « annuaire de services » ou une découverte de service dynamique.
C’est pour cela que j’ai étudié DBus Sharp et le protocole Zeroconf et aussi COM.
Cela explique « DBus avec .Net » et l’Episode 8: Mathias découvre COM

Je voulais aussi abstraire la communication entre les service avec un « Service Bus » maison: l’objectif étant d’avoir une middleware entre les applications qui assure la communication, et ainsi les applications n’ont pas un lien « en dure » entre elles (ne connaissent pas l’IP de leurs dépendances).
DCOM et DBus font exactement cela, mais je voulais quelque chose d’asynchrone avec une couche de « Messaging » comme « NServiceBus » ou « MassTransite« .
Je voulais faire un service bus maison car je voulais quelque chose de plus light que ce qui existe, je me suis alors lancé en utilisant ZeroMQ et le format Protobuf.
Vu l’ampleur du travail j’ai abandonné :)

5. En conclusion:

Si vous avez été suffisamment courageux pour lire tout ce qui précède, et que vous avez pris le temps de voir la présentation de l’architecture de CloudFoundry, vous allez voir qu’il y a de grosses similitudes:

  • Cloudfoundry possède un « conteneur d’application générique » qui peut être du Java, PHP etc. et pas seulement une application Web
  • Cloudfoundry fournie de base des services, comme MySQL, mais avec des services modernes, comme MongoDB et RabbitMQ
  • Cloudfoundry abstrait la notion de déploiement multi-site et d’instances, et vient avec un LoadBalancer  grâce à son Routeur
  • Cloudfoundry n’offre pas de dépendance entre applications, mais le fait entre les applications et les services, à l’aide du « bind de service »
  • Cloudfoundry utilise son propre format de packaging pour le déploiement (voir: http://blog.cloudfoundry.com/2011/04/18/what-happens-when-you-vmc-push-an-application-to-cloud-foundry/ )
  • Cloudfoundry se repose sur une couche de messaging pour faire communiquer les différentes briques dans une environnement distribué

Je me dis alors que c’est la démarche à suivre, la bonne architecture.
Cloudfoundry ne fait pas encore tout ce que j’avais prévu, et plus aussi.
Est-ce que ça vaut toujours le coup de faire son propre « Cloudfoundry like », un PaaS simple et spécifique .Net ?
Étant donnée que Cloudfoundry peut aussi contenir des applications .Net, est-ce qu’il ne vaut pas mieux parier dessus?

La question reste ouverte, mais ce projet m’aura appris pas mal de chose entre temps…

Conclusion: Mathias se lance sur .Net Server

Au cours des 12 derniers épisodes, je vous ai un peu raconté ma vie…
Mais je vous ai surtout fait partagé ce qui m’a sans doute le plus influencé dans le monde du développement .Net/Java.

Maintenant la boucle est bouclée: je me suis lancé sur le développement d’un serveur d’application .Net avec pour influence:

  • EasyPHP
  • Tomcat
  • Spring DM Server
  • OSGI
  • Spring.net
  • COM
  • Gigaspaces
  • Google Chrome
  • Eclipse RCP

Si je reviens au premier épisode d’introduction : Mathias est heureux… mais pourquoi ? je vous montre une pauvre screenshot d’une petite application Winform… mais qu’est-ce que ça cache?

Et bien, cette application exploite mon « moteur à la OSGI » pour :

  • charger des plugins, soit dans un AppDomain, soit dans un processus
  • démarrer dynamiquement les instances de service IService qui font office de point d’entré du plugin
  • demander aux services de se dessiner dans la fenêtre principale

Cela donne quelque chose similaire à Google Chrome, puisque si vous « killer » un process correspondant à un plugin, cela n’affecte pas l’application.

Les plugins peuvent dépendre les uns des autres, ce qui veut dire que le moteur va démarrer les dépendances avant.
Les plugins peuvent communiquer entre eux, comme le fait l’application principale avec le point d’entré IService. Cette communication est faite en .Net remoting (pipe).

Mais ce moteur peut aussi  être utilisé en mode console pour agir comme un serveur d’application!
Vous pouvez alors:

  • lister les « Bundles » qui tourne
  • stopper/démarrer un Bundle, ce qui  va bien sûr démarrer les dépendances nécessaires
  • les bundles sont isolés dans des AppDomains ou Processus différents
  • installer un Bundle à partir d’un ZIP
  • installer un Bundle à partir d’un « repository » (comme dans Spring DM Server)
  • dans le cas de l’installation à partir d’un repository, le serveur va aussi télécharger et installer les dépendances, en tenant compte de la version bien sûr

Vous en voulez plus?

  • Le Repository de Bundle n’est autre qu’une application de type Bundle
  • un Bundle peut être de type « Web », ce qui va démarrer une instance de XSP (serveur ASP.net de Mono)
  • le Bundle « BundleRepository.Web » fournit une interface Web à la gestion du Repository
  • le Bundle « WebManager » fournit une interface Web à la gestion des Bundles et du serveur d’application

Pas mal non?
Ce qui manque à tout cela:

  • Une meilleur gestion des dépendances, exprimée à l’aide d’un XML descripteur de service (comme le XML des plugin Eclipse) basé sur Spring.net
  • Une meilleur communication inter-processus que .Net Remoting, avec gestion d’un annuaire et d’un descripteur de service (comme un WSDL)
  • Des Bundles de type « Job schedulé », avec gestion de Workflow, tout cela avec une interface Web pour leur gestion
  • Le déploiement des Bundles sur plusieurs instances de serveurs (cluster) avec gestion de faillover
  • Un Bundle fournissant une couche de sécurité transverse
  • Un Bundle fournissant un accès à une source de donnée hébergé (SQLite)
  • Un Bundle fournissant un service de type cache (Memcache?)
  • Un Bundle fournissant un service de type Bus (Laharsub?)
  • Un Bundle fournissant un service de « Perf. Counter »
  • Un Bundle fournissant un service de logging transverse
  • Une console d’administration à distance
  • Garantir la compatibilité avec Mono+Linux
  • Des gens motivés pour participer à ce projet OpenSource!
  • Héberger un « Plateform as a Service » sur le Could!!
  • Conquérir le Monde!!!

Alors, qu’en pensez-vous?

Le code source est sur BitBucket (il est aussi sur Github mais beaucoup plus vieux): https://bitbucket.org/grozeille/nsynapse

(PS: je suis super mauvais en nom, j’aurai du l’appeler « carotte » ça passerait mieux)

Episode 12 – Mathias découvre Topshelf

Je vous l’avez bien dit que j’ajouterai des épisodes pour faire durer le suspens :)

Il était primordial que je parle de TopShelf, qui a forcement marqué mon existence.
Pour résumé Topshelf, je dirais que c’est… un serveur d’application!
Je vais peut-être trop loin en disant ça, mais c’est la voie qu’il est en train de prendre…

Une des premières fonctionnalités de Topshelf, est de pouvoir développer une application qui peut s’exécuter en mode « console » ou en mode « service Windows »: vous n’avez plus d’excuse pour avoir besoin des droits d’admin ! ;)

La deuxième, tout aussi importante, est de pouvoir déployer votre application sans avoir besoin de redémarrer votre service Windows: Topshelf agit comme une application Web ASP.Net, ne lock pas vos DLLs, exécute votre application dans un AppDomain isolé, et relance l’application après détection d’un changement de celles-ci.
C’est donc bien un « conteneur d’application » !
Vous pouvez y déployer autant d’application que vous voulez dans un service Windows sous la forme d’une DLL, le bootstrap de Topshelf s’occupe de son cycle de vie.

Suite naturelle de son évolution, Topshelf est fourni maintenant avec une « application » déployé par défaut: Topshelf Dashboard. Cette dernière offre un portail Web pour pouvoir stopper/démarrer ces applications.
Ça ressemble donc fortement à mon projet :)
Il est clair que c’est une très bonne source d’inspiration pour améliorer encore plus mon projet.

Episode 11: Mathias découvre Windows AppFabric aux Techdays 2010

Bon, assez parlé d’application RCP, parlons de serveurs d’applications.

Si Java a fait du chemin dans le domaine, .Net se résume à : RIEN !
Mais Microsoft tente de rectifier le tir en 2010 : Windows AppFabric, le premier serveur d’application .Net.

Mais j’ai été très déçu du résultat : Windows AppFabric n’est qu’un nom commercial pour désigner un serveur Windows 2008 avec tout ce qu’il y a d’installé dessus :

  • Serveur Web IIS
  • MMC de gestion du serveur, avec une nouvelle interface pour IIS permettant de déployer une application sur plusieurs serveurs (ENFIN !)
  • MSMQ pour le messaging
  • SQL Serveur pour la base de données
  • Velocity en tant que cache distribué

Mais voila, tout ces outils n’ont rien à voir les uns avec les autres, à par le fait qu’ils s’installent uniquement sur Windows.

On est très loin du serveur d’application J2EE qui héberge tout ces services et qui s’installent en quelques cliques avec gestion de dépendances.
On est très loin de Gigaspaces en terme de cache distribué.
On est très loin de l’interface Web pour gérer tout cela : si le serveur est obligatoirement un Windows, la MMC vous oblige aussi d’avoir comme poste client un Windows !

On est aussi très loin de la simplicité d’installation de EasyPHP.

Bref, je suis super déçu, mais pas surpris.

C’est pourquoi j’ai décidé de me lancer, et de développer mon propre serveur d’application .Net, CrossPlatform (Mono/Linux compatible), en prenant pour exemple ce qui existe dans le monde Java…

Episode 10: Mathias découvre Google Chrome

Il faillait que je vous parle de Google Chrome, car il m’a aussi beaucoup influencé !

Un navigateur est une application lourde composée de plusieurs vues et de plugins (ou extensions).
On peut même dire que les vues sont décrites en « une sorte d’XML » appelé HTML (non non, ce n’est pas du XAML).

Pour isoler chaque page et chaque plugin, Google a fait le choix de les séparer en différent processus.

Et moi, j’ai trouvé ça très très malin !
Google avance la raison suivante : la gestion des ressources (mémoire, CPU) est le rôle de l’OS. Pourquoi réinventer cette gestion de ressource entre les plugins d’une même application ?

Episode 9: Mathias découvre MEF

Après cette petite pause sur COM la dernière fois, revenons sur le sujet des clients lourds et de la « composition ».

Je vous ai déjà BEAUCOUP parlé de l’IDE Java Eclipse et la richesse de son framework de plugins basé sur OSGI.

Je vous ai parlé de .Net qui rattrape son retard à l’aide d’IOC et de MVVM.

Mais je ne vous ai pas encore parlé de VisualStudio.
Ce dernier offre depuis la version 2008 un noyau indépendant de l’IDE pouvant être utilisé pour n’importe quel type d’application : VisualStudio Shell.

Cella est possible à l’aide d’une gestion de « plugins » comme Eclipse (appelé « add-in »).
La gestion des add-ins de VisualStudio s’appuie sur COM (voila pourquoi il fallait que j’en parle avant ;) ).
Cela n’est pas étonnant puisque c’est LA technologie de communication inter-processus sur Windows.

Mais récemment, Microsoft a travaillé sur une nouvelle technologie d’activation de service et de « gestion de dépendances » et cette fois-ci 100% .Net. Cette dernière a été utilisée dans VisualStudio, afin de ne charger en mémoire que les add-in nécessaire suivant le besoin.

Cette technologie s’appelle MEF : Managed Extensibility Framework.
Et MEF fait du bruit : il est inclus officiellement dans .Net 4.0, Mono l’inclut dans la version 2.8 (car MEF est OpenSource, BRAVO Microsoft), et MEF est annoncé comme « remplaçant de l’IOC ».
En fait, même si on déclare des dépendances, ce n’est pas une solution IOC/DI…
D’ailleurs, je n’ai eu que de mauvais écho sur son sujet: mauvais usage, trop jeune?

Ce qui est bon à prendre, c’est l’aspect « attributs » pour déclarer ce qui serait visible à l’extérieur ou dans le conteneur IOC. Cela fait aussi pensé à la JSR-299 qui propose des annotations standards en Java pour tout type de conteneur IOC.

J’ai aussi exploré d’autres pistes pour une gestion de « plugin »: Mono.Addin. Je trouve le principe très bien, et très inspirant, mais peut-être trop spécifique à ce pourquoi il a été inventé, cad, la gestion d’add-in dans Monodevelop.
Cette solution s’appuie aussi sur les attributs pour déclarer les Addins, donc c’est une bonne voie à suivre.

Episode 8: Mathias découvre COM

Bonjour tout le monde, et merci de votre patience…
Ça fait presque 5 mois que je n’ai pas blogué, et que j’ai interrompu ma série « Mathias découvre… »
Comme j’en découvre tous les jours, j’ajouterai bien d’autres épisodes avant la conclusion finale, mais j’ai peur que ça dure une éternité :)
En réalité, je voulais « jouer la montre » avec ces blogs, afin de stabiliser mon projet et lui trouver un nom sympathique. Mais je n’ai pas vraiment trouvé le temps d’y travailler, alors je vais « pousser l’oisillon hors du nid », et j’ajusterai plus tard s’il ne vole pas très bien ;D

Je change de sujet par rapport aux précédents postes, et je m’attaque à un autre sujet épineux: la communication inter-processus.

Au début de ma vie professionnel, je n’ai pas commencé à travailler en .Net, mais en Delphi.

J’avoue que Delphi était séduisant. Avant .Net, c’était la manière la plus efficace de réaliser des applications Windows lourde avec un Designer d’interface unique. Et puis, n’oublions pas que l’inventeur du langage Delphi n’est autre que Anders Hejlsberg, qui fut embauché par Microsoft pour inventer C# !

Quand .Net prenait de plus en plus d’ampleur,  j’ai alors réussi à convaincre tout le monde de s’y mettre.
Mais comme la migration devait se faire petit à petit, il fallait intégrer Delphi avec .Net.

Pour cela, j’ai découvert COM.
COM est une technologie 100% Microsoft, mais qui se base sur les mêmes principes que Corba.
COM permet de communiquer entre les applications, peu importe le langage. La communication se faisait en activant des services, à l’aide d’un contrat qui se rédigeait dans un langage indépendant du langage de compilation : IDL (Interface Definition Language).

C’était magique : on pouvait inclure un UserControl .Net dans une application Delphi existante ! On pouvait aussi appeler des services .Net depuis Delphi, et vis vers ça !

Les services étaient d’ailleurs enregistrés auprès de Windows, dans la base de registre. Donc, quand un programme Delphi demande un service qui répond à une interface, Windows se charge de le localiser (DLL ou EXE) de l’héberger dans un conteneur (dans le cas de l’EXE, il lance ce dernier, dans le cas de la DLL, il l’host dans DLLHOST.exe) et d’instancier le service pour qu’il puisse être utilisé.

Et ce n’est pas tout ! Il y avait aussi DCOM qui est la version distribué de COM. Cela veut dire que si la DLL n’est pas sur la machine actuelle, Windows se charge d’interroger les autres serveurs DCOM pour qu’ils instancient le service à distance ! Tout cela avec une couche de sécurité ultra complexe !

De plus, le langage IDL supporte les méthodes, les propriétés, les événements, les paramètres de type « out », l’héritage d’interfaces, la gestion des versions, etc.…

Si vous souhaiter exposer des services sous Windows, cette technologie semble la plus appropriée.

Dans le monde des serveurs J2EE, ce fût Corba, concurrent direct à COM, qui remplissait ce rôle.

Mais voila : COM est 100% Windows, 100% Natif (non managé) ce qui rend le pont COM-.Net peu performant.

Concernant CORBA, il existe bien des connecteurs pour .Net, mais pas de serveur CORBA 100% managé.
De plus, CORBA est abandonné dans certains domaines à cause de sa lourdeur : les distributions Linux ont migré de CORBA à DBUS pour avoir aussi leur « équivalent à COM ». A noter que DBus existent en 100% .Net: http://www.ndesk.org/DBusSharp

Microsoft abandonne d’ailleurs COM pour sa technologie de communication phare : WCF.
Avant WCF, Microsoft avait introduit une autre solution 100% .Net: .Net Remoting. Mais ce dernier était trop simple et a fini par être abandonné, même si c’est toujours la technologie par défaut pour communiquer inter-AppDomain.

Alors, que choisir comme technologie de communication et d’activation de service ? Point à Point ou par un intermédiaire (Bus/Broker)? Quel format de message/marshalling doit-on utiliser?

Pour ma part: COM n’est pas multi-plateforme, je ne suis pas convaincu par l’usine à gaz WCF, DBusSharp est trop bugué, .Net remoting est trop simple/limité… je reste un sur ma fin.

Mais entre temps, j’ai découvert le « Messaging » et la communication asynchrone, qui est parfaite pour un environnement distribué. On ne peut pas remplacer le RPC par le Messaging dans tous les cas, mais il a falloir que j’exploite cette voie.

Suivre

Recevez les nouvelles publications par mail.