dimanche 6 novembre 2016

Cluster de serveurs d'application Java EE

Un cluster, oui mais pourquoi ?

Un cluster est un ensemble de serveur d'application qui vont travailler ensemble. En général une instance particulière est appelé Master et les autres slaves, ils sont tous des noeuds (nodes) du cluster.
Plusieurs raisons peuvent justifier de mettre en place un cluster :
  • Avoir de la haute disponibilité (HA) :
    • Permettre de déployer sans interruption ni perte de session des utilisateurs.
    • Permettre d'effectuer des opérations de maintenance sur les nœuds (les uns après les autres) sans interruption
  • Gérer la charge :
    • En multipliant les nœuds sur des machines différentes il est possible d'avoir une puissance démultiplié 
    • On peut ajouter des nœuds dynamiquement pour occasionnellement gérer des montés en charge et les retirer ensuite.

Cluster EJB vs HTTP

Les EJB se clusterisent parfaitement sur les serveurs d'application, en fait c'est le proxy porté par les clients qui répartissent leurs appels sur les nœuds de façon transparente.
Les sessions sont répliquées et une affinité de session se met en place (sur des EJB Statefull).


De base pour HTTP le serveur d'application (ex : jboss) ne sont pas capables de répartir les requêtes HTTP, il faut donc mettre en place un Loadbalancer logiciel (Apache, Nginx...) ou physique (F5...). Ce dernier remplace le proxy de l'EJB client mais introduit aussi un SPOF (single point of failure), une solution est de jouer avec les DNS pour mettre en place plusieurs loadbalancers sur différents IP répondant au même nom de domaine.

Cluster et performances

A puissance égale une machine unique sera toujours plus performante qu'un cluster (la machine unique possède la puissance de l'ensemble des machines du cluster). La performance n'est pas l'objectif principal d'un cluster mais la haute disponibilité. Mais à partir d'un certain seuil le coût d'une machine très puissante dépasse largement la somme de machines plus standard fournissant une puissance équivalente.

Le cluster va entraîner une consommation supplémentaire (flèches bleus en pointillés) :
  • En bande passante pour synchroniser les sessions des nœuds, pour informer l'états des nœuds.
  • En mémoire et CPU chaque nœud devrait avoir l'ensemble des sessions et doit réaliser les mises à jour des actions réalisées sur d'autres nœuds. 
Clairement c'est la gestion des sessions qui va pénaliser le cluster. La solution est simple faire des services stateless, voir des applications web stateless (la session est gérée côté client en javascript, comme le bon vieux client lourd) : éliminer la session. C'est évidement la tendance de ces dernières années avec des service REST stateless, et des frameworks javascript puissants ou des applications mobile.

Mais cela ne résout pas tout...

Cluster et accès à la base de données

On parle d'un cluster de serveur d'application Java EE, souvent il y a une base de données pour y stocker les informations. 
En Java EE on utilise généralement JPA. De base mettre en cluster ne va pas provoquer de problème à moins que le cache de niveau 2 soit activé. Or si vous avez besoin de performance la base de données peu rapidement devenir le point de contention du système et le cache est une solution efficace voir indispensable et JPA propose le cache de niveau 2 pour cela.

Avec ce cache on retrouve sensiblement le même problème que les sessions, il faut impérativement que le cache soit synchronisé sur tous les nœuds sinon le comportement de l'application sera imprévisible et fallacieux. Heureusement le cas est prévu par la plupart des outils de cache (EHCache, Memcached, Infinispan, Coherence...), mais si vous faites cela à la petite semaine avec vos petits doigts il est fort à parier que votre cache maison ne va pas aimer être clusterisé. 
Principalement 2 topologies de cache sont utilisés et une 3ème qui est un peu luxueuse :
  • Répliqué et synchronisé sur tout les nœuds, ainsi chaque nœud du cluster a en local un cache complet et à jour.
  • Distribué sur les nœuds du cluster, chaque nœud à une partie du cache, cela permet d'avoir une capacité disponible plus importante pour la taille du cache.
  • Un mixe des 2 : une distribution du cache avec un facteur de réplication.
Suivant les besoins de votre application l'une ou l'autre des ces topologies sera plus pertinente. 

Caractéristique du cache répliqué : 
  • cache rapide avec un temps de réponse constant quelque soit le nœud.
  • une mise à jour du cache coûteuse et un coût qui augmente avec la taille du cluster.
  • La perte d'un nœud n'a pas d'impact sur le contenu du cache.
Caractéristique du cache distribué :

  • Le cache est potentiellement moins rapide car il peut nécessiter un appel réseau pour aller chercher la valeur sur un autre nœud.
  • Le coût de mise à jour du cache ne dépend pas de la taille du cluster.
  • Lors de la perte d'un nœud une partie du cache est perdu il faudra la reconstituer en sollicitant la base de données, il y aura une charge supplémentaire sur la base de données et une dégradation des performances de l'application.

Ce dernier point n'est pas rédhibitoire, sans cache l'application est sensée répondre dans des temps corrects sur un appel unitaire, si ce n'est pas le cas, on n'est face à un cache "cache misère"... 

La 3ème est en fait une base Nosql, c'est la cas de Coherence d'Oracle par exemple, 
prévoir quelques euros pour la licence et un sous réseau dédié à votre cluster (oui ça broadcast en UDP). Et ça marche bien, il faut juste se demander si on a encore besoin de la base de données pour les données qui vont aller dans ce cache...

mercredi 26 octobre 2016

Mise en oeuvre : Master Data Management (MDM)

Qu'est que le MDM ?

Wikipedia pourra vous renseigner...
En résumé l'objectif du MDM, si dans un système d'information une entité (unité de sens, par exemple le client) est stockée dans plusieurs logiciels ou bases de données dont les informations arrivent dans chaque système avec des processus différents. Le MDM va être le lieu ou toutes ces informations vont être consolidées, identifiés et dont on va extraire un enregistrement de référence (en utilisant des règles), souvent appelé Golden Record, qui sera alors redistribué à tous les systèmes pour unifier la notion (le client) dans l'organisation.

Principe

Ici 3 sources de données sont poussées dans le MDM, pour chaque enregistrement il y a une mise en qualité (quatity gate) qui peut s'appuyer sur des règles, des données de références, une base de connaissances.
Puis l'enregistrement est intégré et rapproché par des règles à un cluster qui contient tous les enregistrements d'une même instance d'entité (ex : le client André Dupont).
A partir de tous les enregistrements du cluster d'une instance, un golden record est réalisé en faisant du picking par des règles sur les champs des enregistrements du cluster.
En théorie un cluster doit être composé d'un enregistrement par source, ou moins.
Si dans un cluster, 2 enregistrements de la même source se retrouvent regroupés alors il a un problème, cela demande une remédiation. Il est possible qu'un doublon soit présent dans une des bases, et cela peut nécessiter une intervention métier pour dédoublonner (ex: que faire des points de fidélité dans le CRM qui sont sur deux comptes alors que c'est la même personne ?), et cela montre qu'il a peut-être une amélioration a réalisé au niveau des processus de ce système.
C'est à ce niveau qu'intervient le workflow de remédiation et le rôle du Data Steaward, il est alerté d'un doublon et a pour objectif d'analyser l'origine du problème :

  • règles de rapprochement à améliorer (les champs utilisés ne sont pas tous pertinants)
  • mise en qualité trop intrusive (modification d'un prénom en utilisant la base de connaissance)
  • problème de  la base d'origine (doublon réel)
  • ...
En suite il doit prendre des actions :
  • Correction manuel du cluster et association avec un autre cluster ou création d'un cluster dédié
  • Ne rien faire cela n'a pas d'impact métier
  • Remonter le problème au responsable de l'application d'origine pour réaliser une intervention métier
  • Modifier les règles de rapprochement
L'approche MDM est l'amélioration continue, on ne sait pas encore quelle donnée posera un problème mais le système est prêt à être amélioré, affiné lorsqu'un nouveau cas est rencontré.

Performance et volumétrie

Regroupant l'ensemble des données de l'organisation pour une unité de sens, stockant l'historique pour permettre l'analyse et retracer le comportement d'un cluster, le MDM va nécessiter une volumétrie beaucoup plus importante que les bases des systèmes métier l'alimentant.

Jouant pour chaque nouvelle enregistrement un ensemble de règles pour le rapprochement à un cluster puis réalisant un nouveau Golden record pour ce cluster (ce dernier est aussi stocké), l'ajout dans le MDM d'un enregistrement est coûteuse. Il est peu probable pour que cela puisse être réalisé en temps réel ou de façon synchrone. En consultation on peut avoir une performance correct mais l'utilisation de cache semble indispensable. 

La rechercher dans le MDM peut-être coûteuse si on souhaite respecter la même logique que celle utilisé pour le rapprochement (mise en qualité et règle de rapprochement). 


Mise en oeuvre

Une fois les unités de sens identifiés, elles représenteront les entités du modèle MDM. Chaque entité doit être sémantiquement indépendante les unes des autres, le modèle MDM n'est pas un modèle relationnel : une table du MDM contient l'intégralité de son sens, le sens d'une entité n'est pas le produits de plusieurs tables, il peut y avoir des relations entre les entités.

Exemple :
Nous souhaitons intégrer à un MDM une entité client, quid de l'adresse. Deux modélisations sont possibles :
  1. Le client doit avoir une adresse cela faire partie de son unité de sens et permet de le déterminer : une entité client
  2. L'adresse et le client sont indépendants mais il y a une relation possible entre les deux : une entité client et une entité adresse
Dans le cas 1 les champs de l'adresse (rue, code postal...) sont ajoutés au client, et permettent de différentier les clients aussi bien que le nom et le n° de téléphone. Le déménagement d'un client risque d'avoir pour conséquence la création d'un nouveau client si cela n'est pas spécifiquement géré côté métier.
Dans le cas 2 les champs de l'adresse ne peuvent être un discriminant pour distinguer les clients et l'entité Adresse contiendra un ensemble d'adresse dont l'objectif sera de fournir des adresses le plus juste possible indépendamment des clients. Le volume de données est aussi moins important.


Les 2 approches sont valides, tout dépendant des volumes et des objectifs du MDM. Si vous êtes un opérateur majeur de la grande consommation et que votre base client est très volumineuse et représente une part importante de la population alors le modèle 2 est plus adéquate car l'entité adresse aura une valeur ajoutée, vous arriverez à discriminer les adresses valides et invalide : un nom de rue rencontrée qu'un fois est suspect, vous aurez rapidement exhaustivité des nom de rue. Sur un ensemble plus restreint, comme sur une base client B2B, le modèle 1 sera plus pertinent.

  

jeudi 26 mai 2016

Java vs .Net C#

C'est un débat sans fin mais comme je développe sur les deux environnements je me dois d'y participer un peu, d'apporter mon caillou au tas de gravats.

Je vais balayer d'un revers de main l'aspect performance : c'est pareil ou presque. Bon quand même on va dire que les Winform sous Windows ont un rendu certainement plus rapide et réactif que du Java swing ou autre. Pour le reste cela dépend beaucoup du développeur et on peut voir une programmation d'un algo en Java battre le même en C à cause de la mise en oeuvre : un mauvais développeur C/C++ fera pire qu'une mauvais développeur Java/C#.
Et on peut jouer avec cela : http://benchmarksgame.alioth.debian.org/
Donc grosso c'est pareil.

Attaquons d'un point de vue langage et syntaxe. Ce sont des syntaxes très proches, C# est fortement inspirées de Java et C et Java est elle-même inspirée de C. Mais plus en détail question langage, le C# est clairement meilleur, plus flexible et plus juste. Son secret, le C# n'est pas rétrocompatible ce qui lui a permis de briser certaines barrières et d'évoluer plus vite.
Ainsi les generics sont vraiment gérés au runtime ce qui n'est pas le cas de Java et dès qu'on s'attaque à faire de la réflexion on réalise que cela a de l'importance.
En suite le gros apport de C# c'est linq qui permet de réaliser des requêtes dans les structures de données les plus divers (SQL, XML, objets...).
Le foreach multi threads et quelques raccourcis pour faire un code utilisant plusieurs threads mais je crois que maintenant il y a un équivalent en Java.
De plus il y a une certaine flexibilité dans la gestion des fichiers de code source : une classe peut-être implémentée dans plusieurs fichiers, pratique pour le code généré, et la structure namespace-classe ne doit pas comme en Java être identique à celle répertoire-fichier (mais cela n'a pas que du bon). 
Enfin à chaque nouvelles versions ils progressent et l'écart se réduit ou change de géométrie.

Ensuite l'environnement de développement, Visual Studio contre Eclipse, Intelij, Netbean... bon aujourd'hui ils sont tous très aboutis, mais le développement d'une application reste complexe, et il fini par y avoir pléthores de menus et sous menu et modules... bref c'est ainsi. Visual Studio intègre nativement plus de chose ce qu'il fait qu'il est plus simple d'approche. Il faut aussi noté qu'il y a dans l'ASP.NET et autre finalement pas mal de code généré par Visual Studio qui est masqué à l'utilisateur. Après pour avoir la couverture de code par les test dans Visual Studio faut s'attaquer à une licence qui vaut quelques milliers d'€...

En en arrive a la réalisation d'un projet Web par exemple, c'est quand même mieux intégré dans Visual Studio, on est tenu par la main. En Java il faut déjà faire beaucoup de choix, Java EE, Spring, JPA, JSF, JSP, GWT... tout ça décliné en version, cela demande un certain savoir faire sans compter que cela change régulièrement aujourd'hui on partirait plus sur Java EE REST, JPA + Angular (ce qui simplifie la donne ou déplace le problème vers le développement javascript). En ASP.NET y a moyen de chercher du Nhibernate, Castle, EntLib, Unity et autres mais étrangement c'est assez peu couru de méditer sur la stack ASP.NET.

Ce que fait la grande différence lors de la réalisation c'est la gestion des librairies tiers, d'un côté Maven (ou Gradle) pour Java et Nuget pour .net. Mais il faut dire que Maven a des années d'avance et une pratique assez généralisée aussi bien dans les projets tiers qu'au sein même de l'entreprise. Nuget commence a entrer dans les mœurs.

Un autre aspect qui fait la différence est l'écosystème, en Java il y a de grandes organisations qui gèrent de l'opensource (Apache, Redhat, Spring...) de gros éditeurs (Oracle, IBM...). Du coup c'est très riche on peut vite s'y perdre, mais il y a aussi Java EE pour normaliser et cadrer un peu tout cela. A contrario le monde .Net est plus fermé, il a quelques éditeurs spécialisés dans les composant d'interfaces et autres outils : Telerik, ComponentArt, ComponentOne. Les projets opensource en c# dans http://www.codeproject.com/ et http://codeplex.com ont rarement un gouvernance clair, les bonnes idées finissent absorbées par Microsoft sous une forme ou une autre, alors souvent le plus simple est de ne surtout rien faire et attendre la prochaine version du framework. Et inversement Microsoft y déverse les éléments qu'il ne souhaite plus maintenir (ex : Entlib, Unity).

Finalement la grande différence c'est le développeur. Le développeur .Net et le développeur Java sont très différents dans leurs approches et leurs travers. Mais cela mérite son propre post.

lundi 18 janvier 2016

On continue l'aventure GAE Endpoint et SEO

Voila depuis quelques temps que mon application de compteur en ligne est en production en version Alpha. Bien entendu personne ne l'utilise, même par mégarde. Du coup je me dit qu'un petit effort de SEO, optimisation pour les moteurs de recherche, s'impose.
Pour cela 2 axes possibles :
  • Plus de contenus
  • Une URL plus parlante

Pour le 1er axe, c'est possible en réalisant des pages de documentation pour l'utilisation de l'application, c'est prévu mais il faut du temps. Par contre modifier l'URL du site pour que cela soit plus efficace semble assez rapide. L'URL compte beaucoup pour les moteurs d'indexation, car c'est un champ limité en taille, obligatoire et potentiellement compliqué à modifier, très engageant : achat de domaine, mise à jour DNS, redirection du site...

Pour mon cas je ne vais pas investir dans un domaine, mais j'en ai déjà un capverszero.fr, du coup je vais faire un sous domaine bien parlant : https://onlinetallycounter.capverszero.fr

Alors avec Google Cloud Endpoint c'est le parcours du combattant...
Première étape enregistrer le nouveau domaine, au travers de la console Google AppEngine, montrer patte blanche et prouver que vous êtes bien propriétaire du domaine. J'ai opté pour la validation au travers de l'ajout d'une directive DNS. Une fois ceci passé Google donne la directive DNS à ajouter pour redirigé le sous domaine vers l'application GAE. 
Il faut bien noter que chaque mise à jour du DNS prend un certain temps... plusieurs heures... donc faut pas être pressé.
Et là stupeur les Cloud Endpoints ne supportent pas les custom domain... oui c'était une petite note dans la documentation... Heureusement la page HTML est bien accessible sur le nouveau domaine mais les services ne sont pas disponibles sur ce domaine. Argh !!! 

Donc il faut se lancer dans la modification du code de l'application pour utiliser CORS (Cross-Origin Resource Sharing). Ça marche dans les nouveaux navigateurs, ça signifie tout simplement qu'il faut appeler les services REST de Google Cloud Endpoints sur l'adresse contingit.appspot.com, en dur, et ça marche ouf.

Et maintenant il faut mettre à jour le référencement de mon site dans les outils Google (Webmaster Tools et Analytics), et là il demande qu'une redirection HTTP 301 soit mise en place pour valider que c'est bien une migration de site. Et là impossible de réaliser cette redirection côté serveur : je n'ai qu'une page statique... Je me lance sur une redirection par balise meta... c'est pas classe mais il parait que ça peu marcher. Mais la blague c'est que je n'ai qu'une page et c'est physiquement la même au 2 adresses donc tout cela semble compromis je risque d'être redirigé indéfiniment. J'ai bien fait le test en mettant une seconde page mais cela ne m'a pas permis de valider la migration du site dans l'outil google... du coup c'est comme s'il y avait 2 sites...


Enfin je m'arrête ici et j'attends de voir si je monte un peu dans le ranking google, à suivre...

dimanche 13 décembre 2015

Le voyage du Kimsufi en Docker (Etape 5) subsonic

Voila on attaque la dockerisation de Subsonic, on trouve déjà des images et des Dockerfile, donc ce n'est pas trop compliquer de s'en inspirer voir on pourrait les reprendre directement. Mais pour divers raisons je recompile Subsonic à partir des sources et puis je voulais compiler ffmpeg dans le container histoire de voir si le tout est plus performant. Mon mini Kimsufi souffre un peu avec l'encodage à la volée côté puissance c'est un peu léger.

Bien entendu c'est la dernière version de Subsonic, j'avais espéré la brancher à la base de donnée MariaDB (mysql) mais ce n'est pas encore pour cette fois... peut-être faire un fork du projet pour le migrer de JDBC à JPA et mettre à jour le lecteur en HTML5... mais ça c'est vraiment si je trouve du temps... à voir si y a pas déjà un énervé qui a lancé un projet sur GitHub.
Vu que Subsonic est un conteneur autonome, il y a juste un partage de volume pour récupérer la musique et patienter un peu pour que la base de données se remplisse.

Je n'ai vu de différence notable, mais l'avantage de passer par un container rend la migration plus sécurisée, en effet sur le serveur l'ancienne version de Subsonic est utilisable et n'a pas été écrasée. Si je n'avais pas utilisé Docker j'aurais du écraser ma précédente installation.
Voila un lien vers l'images dans docker hub : https://hub.docker.com/r/niclange/subsonic/

Sinon le fait d'utiliser une version compilée à partir des sources pour ffmpeg ça donne cela :
Version compilée :
real 10m53.476s
user 38m21.924s
sys 0m30.456s

Version installée avec subsonic :
real 14m23.775s
user 45m1.728s
sys 0m31.908s


mardi 17 novembre 2015

Counting IT version Alpha

Voila c'est fait... un peu de développement pour un peu de résultat. Un petit site qui n'a pas encore une grande utilité mais qui sait... avec quelques fonctionnalités de plus y a moyen ou pas que cela intéresse un peu de monde. Enfin l'objectif c'est de tester des nouvelles technologies :

Pour le frontal :
  • React Material
  • Design Lite
  • Google Web Starter Kit
J'ai parlé de tout cela dans un précédent billet.

Pour la partie serveur :
  • Google Application Engine (GAE) avec le développement d'un Endpoint.
  • OAuth de google, oui il faudra un compte google pour accéder à l'application
  • Le Datastore de Google avec Objectify
Et tout l'écosystème qui en dérive, stockage des données, authentification OAuth2, API management... et la console de google developer.

La bonne nouvelle c'est que cela marche assez facilement après quelques mises au point avec les outils et l'environnement de développement qui mock l'utilisateur, il faut donc prévoir un horrible code pour gérer cela :
     if (user.getEmail().equalsIgnoreCase( "example@example.com" ))
Oui en mode développement on a pas accès au vrai profile de l'utilisateur.

Sinon je n'ai presque rien à dire... le client javascript du GAE Endpoint est généré à la volé par les API google donc pas de soucis particulier pour générer des requêtes, tout est masqué en fait : 
     gapi.client.countingit.countersAPI.count({'counterId':12345,'countTime':date }).execute(
      function(resp) {
          if (!resp.code) {
              this.setState({data:resp.result});
          }
          else{
              console.error(resp, status, err.toString());
          }
        });
Et c'est assez simple à intégrer avec le fonctionnement de React. Le petit détail est de s'assurer que les API google client sont bien chargées et cela prend du temps avant de tenter des requêtes au serveur.
Bref beaucoup plus de souci entre MDL et React côté interface que côté serveur et appels de services REST.


mardi 27 octobre 2015

Développer un Frontal Web : Google Web Starter Kit & Material Design Lite & React

Parlons un peu de développement Web histoire de se changer les idées car dernièrement dans mes derniers projets professionnels je n'ai pas trop tâté du Web. Je suis côté cœur de SI : services métier, médiation, stockage des données... Mais de temps en temps il faut bien se replonger dans le développement Web car c'est un monde qui bouge beaucoup... et un peu trop vite, c'est quasiment impossible d'être à jour, le temps de réaliser un projet et déjà de nouvelles normes, de nouveaux frameworks... Personnellement j'ai raté pas mal d'étapes et c'est temps mieux, je me suis arrêté à Ext-JS (maintenant Sancha, quand c'était gratuit...) et à JQuery, JQueryUI. Bon tout ça existe toujours mais ils ont moins le vent en poupe. Et du coup j'ai sauté la période Bootstrap / AngularJS (qui va surement se relancer avec la version 2) et qui restent à la pointe et s'améliorent.

Donc je m'attaque au développement Web avec Material Design Lite (porté par les standard de Google) mixé avec React (le framework de Facebook), oui les deux mastodontes d'internet, pourquoi s'en priver c'est gratuit. Et je ne me lance pas dans un développement complexe qui pourrait nécessiter un Backbone.js mais à terme pourquoi pas c'est l’intérêt de React : ça ne ferme pas les portes. Et puis pour cadre tout ça le Google Web Starter Kit.

Material Design Lite

Commençons pas présenter MDL qui implémente le Material Design de Google, c'est très léger : du CSS et un javascript. Cela donne un cadre pour réaliser une interface web, c'est très pratique pour les ingénieurs comme moi qui sont très loin d'être des web designer, ici, on a qu'a choisir la couleur (oui c'est assez restrictif mais ça évite de faire un site qui pique les yeux), un template (ou pas) et les composants. Après ce framework n'est pas très complet aujourd'hui et il manque pas mal de composants, j'attend la version suivante !

React JS

React JS c'est un framework de génération de DOM HTML utilisant le syntaxe JSX qui permet d'écrire cela simplement. React promet simplicité et performance.
Bon c'est pas si simple car on perd les bases du déroulement de la page html et de son chargement. Bref il faut utiliser des astuces pour réaliser lancer les petits scripts nécessaires à MDL pour décorer les composants.

Google Web Starter Kit

Peut de développement dans ce kit, juste le packaging d'outils basés sur node.js pour avoir un platforme de développement web qui est vraiment efficace. On peut modifier le gulpfile.js pour prendre en charge le JSX avec Babel et le tour est joué.

Conclusion

Ces outils marchent PRESQUE ensemble out-of-the-box. C'est React (normal c'est l’intrus) qui fou la grouille.

Voila la solution pour MDL avec React :
var Header = React.createClass({
  componentDidUpdate: function() {
      // Décore tous les composant avec 'mdl-js-* class
      componentHandler.upgradeDom();
  },
Sans oublier l’utilisation d'un require(../material.min.js) pour être sur d'avoir la méthode accessible que browserify gérera...

Et pour le Web Starter Kit une petite modification du gulpfile.js pour prendre en compte JSX (mais je pense que dans la prochaine version ce sera inclus) : 
gulp.task('scripts', function () {
  return gulp.src('app/scripts/monApp.jsx')
  .pipe(babel())
  .pipe(browserify())
  .pipe(gulp.dest('app/scripts/'));
});
[...] 
// Build production files, the default task
gulp.task('default', ['clean'], function (cb) {
  runSequence('styles', ['scripts', 'jshint', 'html', 'images', 'fonts', 'copy'], cb);
});

Mise à jour 02/11/2015 :

Bon quelques soucis j'ai l'impression que le componentHandler.upgradeDom(); fait sauter les événements enregistrés par React... du coup j'ai ajouté react-native-listener. Je ne sais pas si c'est LA solution mais ça marche...

Mise à jour 05/11/2015 :

Pour le même problème que précédemment une solution est d'enregistrer l’événement à la suite :
componentHandler.upgradeDom();  
document.getElementById('myButton').addEventListener("click", this.props.handleClick);

Mise à jour 01/01/2016 :

Suite à la mise à jour de material design lite à la version v1.0.6 je n'ai pas plus besoin de react-native-listener pour la plupart des événements. Cela s'améliore de jour en jour.

lundi 12 octobre 2015

Considération sur l'Architecture en Microservices

Voila la nouvelle voie de l'architecture applicative ! Les microservices vont révolutionner votre SI et diminuer drastiquement les coûts, réduire les temps de développements bref que du bonheur. Mouais faut relativiser, c'est comme tout, faut-il encore bien le faire. Par ce que bon depuis le temps, je suis pas certain que nous les "nouvelles technologie" aient permis de retrouver la productivité, la performance et la fiabilité des bon vieux Mainframe !
Enfin bon moi je suis dans la nouvelle tech alors parlons un peu des microservices. Un petit tour sur Wikipedia et divers sources et on retient :
  • L'architecture en microservice est une architecture applicative que l'on peut rapprocher d'une architecture n-tiers.  
  • Elle n'est pas en concurrence avec une approche SOA car orienté application et non système d'information : seuls les microservice de "haut niveau" sont exposés au SI et ceci dans le respect des règles de la SOA.
Une telle architecture permettrait de donner de la flexibilité non plus au niveau d'un SI (où règne la SOA) mais au niveau d'un applicatif. Ainsi si une fonctionnalité est très consommatrice en ressource pourquoi ne pas la coder dans un technologie plus efficiente comme en GO ou en C ou encore clusteriser le service...  Cette flexibilité technologique aussi de construire un composant  de l'application avec par exemple une application NodeJS existante (genre NodeRed).

Côté humain, pour que cela fonctionne il vous faut une équipe de superman multi techno, et puis côté production c'est la panique alors une alternative est de passer le tout sous Docker... donc ça veut dire qu'en fin de développement une bonne part du travail de l'exploitation est réalisé. Alors là va falloir soit briser les barrières entre les développeurs et les exploitants, ce qui n'est pas évident... entre les uns qui subissent les bugs des autres, les autres disent que les uns veulent juste presser UN bouton... c'est pas gagné. OK ce qu'il vous faut c'est une équipe de super DevOps comme on dit, mouais va falloir les trouver les petits gars, piquer quelques ressource chez OVH et Google et c'est parti. C'est fou comme tout de suite ça devient moins réaliste.

Côté infrastructure, au lieu d'avoir un découpage par API au sein d'une application on a un découpage de service, de services exposés sur le réseau. Cela sous entend qu'ajouter un passage sur le réseau n'est pas un problème pour vous, bande passante démesurée et latence faible... bon aujourd'hui ça se trouve facilement. En suite vous aurez un surconsommation de mémoire et de CPU par rapport à une application monolithique :
  • Le passage par le réseau va nécessiter une sérialisation et dé-sérialisation (CPU) ce qui grosso-modo entraîne un pique x4 de la trace mémoire qui sera absorbé par les garbage collector ou autre gestionnaire de mémoire (CPU).
  • Mutualisation des API tiers dans un application monolithique et du serveur d'application (Jboss ou autre). 

Après une réalité économique est que les coûts du CPU, de la mémoire, du le réseau diminuent rapidement avec le temps alors que le coût de la main d'œuvre augmente (j'aimerais qu'il augmente un peu plus). Donc l'architecture en microservices a du sens. Bien utilisé certains pensent même que cela pourrait mettre à défaut la loi de Brooks, ce dont je doute mais c'est le rêve de tout chef de projet, parfois ils rêvent éveillés, mais attention au réveil le bilan est souvent lourd...

 

lundi 14 septembre 2015

Java Spring, J2EE et Java EE état de lieux

Java Spring, J2EE, Java EE sont les mots clés les plus trouvés dans le monde de l'informatique d'entreprise. Depuis les années 2000 les entreprises ont massivement investi dans la technologie JAVA.
Le cœur de cible de J2EE était de remplacer à moindre coût les infrastructures Mainframe dans lesquelles les entreprises se sentaient emprisonnées par les éditeurs sur des technologies vieillissantes et du matériel spécifique hors de prix. L'avènement de l'architecture PC pour les serveurs permit alors d'acquérir une puissance de calcul à un coût très compétitif mais il faut une technologie pour y développer des applications d'entreprise : J2EE.
Mais le passage vers J2EE ne tiendra pas vraiment ses promesses, pour divers raisons :
  • Alors que l'architecture des applications Mainframe est globalement mise en place et validée par la solution de l'éditeur et au final les développeurs sont dans un cadre qui permet de se concentrer sur l'implémentation du métier. Avec J2EE la complexité d'une application transactionnelle, répartie sur plusieurs machine doit être prise en compte par l'équipe de développement.
  • En plus de gérer des concepts compliqués l'implémentation des composant J2EE est tout aussi complexe.
  • J2EE un standard ouvert mais les implémentations sont le plus souvent payantes.
  • De plus c'est la révolution du Web, on veut des applications d'entreprise en client Web qui sont finalement beaucoup plus contraignantes et complexes à développer que les applications client lourd pour souvent un rendu utilisateur de moins bonne qualité.
Sur le tas de cendre, laissé par les développements J2EE, Spring démarre en flèche. Il modifie le paradigme et on parle de conteneur léger (Tomcat), en général elles sont montées en cluster de type silo.

Finalement Spring a pris une place majeur dans l'écosystème Java, à grossi, c'est enrichi et c'est complexifié... en même temps J2EE a évolué et changé de nom pour Java EE et s'est fait peau neuve pour devenir plus simple. Aujourd'hui ces 2 solutions sont sensiblement équivalentes mais Java EE est tiré par des serveurs d'applications d'entreprise (JBOSS, Weblogic, Websphere...) alors que Spring peut-être utilisé avec du pur Java SE et a un écosystème qui lui est propre.

Et maintenant que trouve-t-on sur le terrain ? De mon expérience,  je rencontre des applications développées sur Spring déployées sur des serveurs d'applications Java EE, et c'est quasiment systématique. Les développeurs ont acquis une expérience plutôt positive avec Spring mais au niveau de l'exploitation les serveurs restent Java EE car soit il y a un historique ou la nécessité d'avoir le support d'un éditeur.
En soit pas de souci les 2 technologies peuvent s'intégrer. Donc en général ce n'est pas un problème c'est juste étrange de ne pas exploiter certaines fonctionnalités fournies en standard par le serveur.
Mais ça devient plus problématique quand l'application développée sur Spring embarque des librairies sur lesquels ce base le serveur Java EE ou qui implémente les même fonctionnalité. En effet le serveur Java EE a été testé, certifié par une communauté ou un éditeur pour fonctionner avec ses propres librairies, c'est d'ailleurs une part importante de leur valeur ajoutée. Dans le cas où l'application apporte des librairies en conflit il faut s'attendre à des soucis au démarrage, pour passer outre il faudra démonter le serveur d'application (avec un peu de configuration dans le meilleur des cas, en modifiant dans le système de fichier dans le pire des cas) pour qu'il charge nos librairies à la place des siennes. Par ailleurs les exploitants fournissant le serveur n'auront alors aucune garantie sur la réelle configuration et une montée de version ne se fera pas sans surprise.
En générale avec des serveur d'application propriétaire (Websphere, Weblogic), il y a moins de risque de collision de librairie car il n'est pas évident d'embarquer les leurs par inadvertance vu qu'elles sont payantes et rarement fournies sans le serveur. Par contre pour les serveur open source (JBoss, Glassfish) il est fort probable qu'en embarquant Hibernate, Log4j, Jersey  un conflit se produise et ce n'est qu'un début. Sans parler des possibilités de monitoring de la console d'administration qui risque de ne plus être opérationnelle.
Mixer Spring et un serveur Java EE nécessite une petite étude préalable et il est possible que les développements finissent par être adhérents au serveur Java EE choisi lors de la phase de développement. Alors qu'une application Java EE devrait être (en théorie) portable d'une plateforme à une autre, sans parler de la taille des binaires à déployer, utilisant le serveur Java EE il y aura fort peu de librairies à embarquer et sur le terrain livrer un binaire de plusieurs centaine de Mo et quelques Mo ça change la vie.

mercredi 9 septembre 2015

RecUnitTest : enregistrer pour mocker

Un petit article pour présenter ce petit développement https://github.com/niclange/RecUnitTest toujours à base d'AOP et pour l'instant uniquement pour une application utilisant le framework Spring. Je compte bien faire une version JEE.

L'objectif de cette librairie et d'aider à réaliser des tests unitaires de non régression sans faire de mock avec une libraire de type EasyMock ou Mockito. Elles sont très bien mais c'est toujours coûteux de réaliser des mocks quand parfois on peut l'éviter.
Voici le scénario pour utiliser RecunitTest :
Vous avez un développement qui utilise par exemple des service tiers (web ou autre) voir une base de données (mais normalement avec DBUnit ce cas est couvert). Il peut jouer en local les tests unitaires de type "intégration" qui utilisent donc de vrais services tiers fonctionnels (mais dédiés aux développements) au cours de son exécution, il doit savoir préalablement que les environnements sont fonctionnels et en état pour réaliser les cas de test. Mais sur la PIC, typiquement avec un Jenkins les tests seront lancés n'importe quand et il est compliqué et coûteux de maintenir des environnements uniquement pour ces tests.
Bref l'idée est d'enregistrer le comportement des réponses des environnements tiers, lors d'un tire de test unitaire maîtrise, dans un fichier pour être à même de le rejouer sur la PIC. De plus pour de la non régression ce fichier pourrait être utilisé dans le cas où remonter des environnements nécessaires est coûteux.

Pour réaliser cela j'ai mise en oeuvre :
  • l'AOP Spring pour intercepter les méthodes à enregistrer et à rejouer.
  • J'utilise une base clé / valeur embarquée mapdb pour stocker les données dans un fichier.
  • Un parser JSON mais peut-être que je pourrais m'en passer...
Donc le développement est assez simple, la mise en œuvre complète sur un projet peut-être un peu plus complexe et nécessite de l'organisation. Je pense qu'il faut s'appuyer sur les profils maven (dans le pom) pour piloter la configuration de l'outil c'est à dire son mode : Record ou Play et le fichier de stockage qu'il faudra probablement pousser au travers du gestionnaire de configuration.

Je n'ai pas réalisé de tests avec un application massivement multi-thread mais j'ai essayé de prendre en compte cette problématique dans les développements. 


Bref il me reste encore à l'utiliser dans un cas réel et voir comment cela se passe pour donner plus de détails.

samedi 5 septembre 2015

Docker et ffmpeg optimisation compilation

Sur ma Debian wheezy je peux récupérer un obscure paquet ffmpeg.
>># ffmpeg -version 
ffmpeg version 1.0.10
built on Jul 25 2014 07:50:40 with gcc 4.7 (Debian 4.7.2-5) configuration: --prefix=/usr --extra-cflags='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security ' --extra-ldflags='-Wl,-z,relro' --cc='ccache cc' --enable-shared --enable-libmp3lame --enable-gpl --enable-nonfree --enable-libvorbis --enable-pthreads --enable-libfaac --enable-libxvid --enable-postproc --enable-x11grab --enable-libgsm --enable-libtheora --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libx264 --enable-libspeex --enable-nonfree --disable-stripping --enable-libvpx --enable-libschroedinger --disable-encoder=libschroedinger --enable-version3 --enable-libopenjpeg --enable-librtmp --enable-avfilter --enable-libfreetype --enable-libvo-aacenc --disable-decoder=amrnb --enable-libvo-amrwbenc --enable-libaacplus --libdir=/usr/lib/x86_64-linux-gnu --disable-vda --enable-libbluray --enable-libcdio --enable-gnutls --enable-frei0r --enable-openssl --enable-libass --enable-libopus --enable-fontconfig --enable-libfdk-aac --enable-libdc1394 --disable-altivec --disable-armv5te --disable-armv6 --disable-vis --shlibdir=/usr/lib/x86_64-linux-gnu
libavutil 51. 73.101 / 51. 73.101
libavcodec 54. 59.100 / 54. 59.100
libavformat 54. 29.104 / 54. 29.104
libavdevice 54. 2.101 / 54. 2.101
libavfilter 3. 17.100 / 3. 17.100
libswscale 2. 1.101 / 2. 1.101
libswresample 0. 15.100 / 0. 15.100
libpostproc 52. 0.100 / 52. 0.100 
Et le tout sur un petit Atom ça fait pas de miracle. Je me suis dit qu'avec un peu de chance en mettant en oeuvre un container Docker, il y a moyen d'avoir à la fois une version compiler et à jour de ffmpeg sans pour autant pourrir mon serveur.
Oh miracle des images existent et de jolie fichier Dockerfile sont disponibles pour monter rapidement une image en partant des sources des divers librairies. Je suis parti de ce DockerFile, deux, trois vérifications et choix des librairies (un peu au hasard je dois bien l'avouer, je ne suis pas un expert en format vidéo et autre encoding), me voila avec une image permettant de lancer ffmpeg dans un container Docker.
Le docker retourne quand à lui (j'ai fait un alias) :
>># ffmpeg2 -version 
ffmpeg version 2.7.2
Copyright (c) 2000-2015 the FFmpeg developers built with gcc 4.9.2 (Debian 4.9.2-10) configuration: --prefix=/usr/local --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/lib --bindir=/usr/local/bin --extra-libs=-ldl --enable-version3 --enable-libx264 --enable-gpl --enable-postproc --enable-nonfree --enable-avresample --enable-libfdk_aac --disable-debug --enable-small
libavutil 54. 27.100 / 54. 27.100
libavcodec 56. 41.100 / 56. 41.100
libavformat 56. 36.100 / 56. 36.100
libavdevice 56. 4.100 / 56. 4.100
libavfilter 5. 16.101 / 5. 16.101
libavresample 2. 1. 0 / 2. 1. 0
libswscale 3. 1.101 / 3. 1.101
libswresample 1. 2.100 / 1. 2.100
libpostproc 53. 3.100 / 53. 3.100 
Sans l'alias le commande ressemble à cela
docker run --rm -t -i -v /Video:/Video bb30ceac9f83 -ss 1418 -i "/Video/test3.avi" -b 1000k -s 640x360 -ar 44100 -ac 2 -v 0 -f flv -vcodec libx264 -preset superfast -threads 4 - > test3.flv 
On remarquera que le container est effacé suite à chaque exécution.
C'est le moment du petit Benchmark ente les 2 ffmpeg et avconv avec le command time :

ffmpeg host ffmpeg compile docker avconv docker avconv host
real 61m29.758s         real 51m16.200s                      real 57m51.491s             real 61m48.041s
user 156m1.020s user 0m31.176s user 0m35.628s user 156m6.080s
sys 1m55.872s sys 1m26.520s sys 1m32.788s sys 1m59.684s

Je n'ai pas comparé la qualité des fichiers ni même la taille, les option étant les mêmes je fais confiance. Conclusion : ça va plus vite ! Soit 16,6% plus rapide avec le docker. La commande time ne peut pas dire grand chose sur l'usage du CPU vu que cela s'exécute dans un container. En tout cas ce n'est pas négligeable tout ça peut être justifié par la montée de version, la compilation, les options...

lundi 24 août 2015

Le voyage du Kimsufi en Docker (Etape 3)

Là je m'attaque à la base de données MySql qui est utilisée essentiellement pour Seafile. Il y a bien au d'autre tests avec mais actuellement elle sert exclusivement à Seafile. Cela va limiter la difficulté à migrer.
Encore une fois je part d'une image officiel, celle de MariaDB. Oui t'en qu'a faire autant prendre du vrai opensource, en général Oracle ne prend pas très soin de ses rachats... alors j'anticipe les soucis futures avec MySQL. Un petit run de l'image officiel de MariaDB tout en modifiant le port histoire d'avoir les 2 bases de données actives :
docker run --name mariadb -e MYSQL_ROOT_PASSWORD=AAAAA --publish=3307:3306 -d mariadb 
Et le tour est joué encore plus simple qu'un apt-get install... après faut faire confiance aux images officiels.
Maintenant il s'agit de réaliser les import / export d'un instance à l'autre de créer les users nécessaires et d'attribuer les droits. Pour cela j'ai utilisé mysql-workbench qui est vraiment complet et sympa, ok c'est un produit Oracle, mais j'ai pas dit qu'ils ne savent pas développer.
Le truc est qu'il faut accorder les droit d'accès non pas en localhost pour la connexion avec seafile mais avec l'IP de l'interface Docker0.

Pour la configuration de la base de données pour Seafile voici les fichiers :
ccnet/ccnet.conf
seafile-data/seafile.conf
seahub_settings.py 
Et un petit restart :
./seafile.sh stop
./seahub.sh stop
./seafile.sh start
./seahub.sh start-fastcgi

Voila maintenant il reste le plus compliqué s'attaquer à des outils comme Seafile et Subsonic, je ne peux plus m'appuyer sur des repos Docker officiel, mais il y a pas mal d'images réalisées sur ces outils. On est pas à l'abri que cela se déroule simplement voir que cela soit trivial !!!

Sinon là c'est clair que le Monit voit de moins en moins de chose... mais cAdvisor de plus en plus !!

Petit détail il faut gérer le firewall (iptables) pour que l'interface docker0 puisse accéder au localhost !!

mardi 18 août 2015

Le voyage du Kimsufi en Docker (Etape 2)

Petit billet pour une petite étape pas de révolution mais de petites améliorations suite à divers lectures. Et la bonne surprise c'est qu'il y a beaucoup de ressources sur Docker, cette richesse rend l'utilisation de Docker vraiment simple car avec quelques recherches on trouve vite une solution à ses problèmes.
Ainsi j'ai mis en place supervisord dans mon container Nginx pour lancer php-fpm et nginx, oui je persiste et combine le serveur web et php dans le même container.

Voici nouveau Dockerfile :

FROM nginx
MAINTAINER niclange
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y php5-fpm php5
RUN sed -i 's/;extension=gd.so/extension=gd.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=iconv.so/extension=iconv.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=mcrypt.so/extension=mcrypt.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=mysql.so/extension=mysql.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=sqlite3.so/extension=sqlite3.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=pgsql.so/extension=pgsql.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=ldap.so/extension=ldap.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=openssl.so/extension=openssl.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=pdo_pgsql.so/extension=pdo_pgsql.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=pdo_mysql.so/extension=pdo_mysql.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=pdo_sqlite.so/extension=pdo_sqlite.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/listen.owner = www-data/listen.owner = nginx/g' /etc/php5/fpm/pool.d/www.conf
RUN sed -i 's/listen.group = www-data/listen.group = nginx/g' /etc/php5/fpm/pool.d/www.conf
RUN sed -i 's/;listen.mode = 0660/listen.mode = 0660/g' /etc/php5/fpm/pool.d/www.conf
RUN touch /etc/supervisor/conf.d/supervisord.conf
RUN echo "[supervisord]" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "nodaemon=true" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "[program:nginx]" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "command = /usr/sbin/nginx" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "user = root" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "autostart = true" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "[program:php5-fpm]" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "command = /usr/sbin/php5-fpm" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "user = root" >> /etc/supervisor/conf.d/supervisord.conf
RUN echo "autostart = true" >> /etc/supervisor/conf.d/supervisord.conf
COPY nginx.conf /etc/nginx/nginx.conf
COPY users /etc/nginx/conf/users
COPY toto.crt /etc/ssl/private/
COPY titi.key /etc/ssl/private/
EXPOSE 80 443 442
CMD ["/usr/bin/supervisord"]



En suite j'ai mis en place cAdvisor, ceci juste en ajoutant un container Docker en suivant la documentation, soit une ligne de commande (à ajuster un peu) et bien entendu je l'ai mis derrière le nginx pour l'exposer en toute sécurité en https et tout. A noter que les liens internes ne semblent pas toujours bien gérés derrière le revers proxy mais on s'en sort quand même.
Et oui les petits containers se reproduisent déjà...
Les interfaces de cAdvisor sont très sympa mais ça m'a l'air d'être assez consommateur en CPU...


Sans remplacer Monit, auquel je tiens accord un peu, j'ai n'ai pas encore décidé de son abandon, et ce billet me donne un espoir.

Après une petite pensée pour Docker, on m'a fait remarquer ceci boycottdocker. Et tout cela m'a fait prendre conscience de toute un mouvement anti docker qui semble porté par des personnes très compétente, plus que moi en tout cas et cela a du sens. Mais je vais continuer avec Docker... parce que justement je n'ai pas besoin d'être un crack de l'admin système et que l'écosystème porté par Docker me plait par ça richesse et ça simplicité. Et je suis bien certain qu'en remontant mes manches avec LXC ou KVM je n'aurais pas de souci avec Monit ou pas...


mardi 4 août 2015

Le voyage du Kimsufi en Docker (Etape 1)

J'ai un petit serveur kimsufi avec quelques applications sympa et puis ça me permet de bidouiller un peu, de m'ouvrir à de nouveaux aspects de l'informatique qui dépassent ce que je réalise professionnellement.

J'ai donc un petit Nginx en frontal de divers applications comme Seafile, Subsonic, un Monit pour voir si tout tourne bien et réaliser un monitoring des ressources.

Et là je me dis pourquoi pas dockeriser tout ce petit monde.
On se demande bien pourquoi ? Quel est l'intérêt de consacrer de l'énergie pour tout mettre dans des containers Docker ?
Le premier est tout personnel : apprendre à utiliser cet outil et voir si ça vaut le coup de le mettre en place sur des projets professionnels avec un peu d'architecture en microservices.
En suite le serveur est sous Debian et réaliser une montée de version n'est pas si évident ainsi je peux créer des container dans un version plus récente de Debian sans modifier mon système hôte.
Cela peut faciliter la monté de version de Debian, la migration vers une autre machine, chez un autre hébergeur ou dans une infrastructure cloud...

Après que vais-je perdre ? A priori Monit ne permettra pas de manager les différents services dans les containers, ou à payer mmonit. Il va falloir passer à supervisord installé dans chaque container et un container pour supervisorctl et peut-être un cAdvisor en prime... De plus supervisord semble la solution préconisée pour lancer plusieurs processus dans le même container.
Et pas mal de temps... visionner les vidéos pour survoler les concepts et l'utilisation de Docker. Du temps pour installer Docker (et une petite montée de kernel pour que ça marche). Du temps pour faire les Dockerfiles et les commandes docker run... Du temps pour tester, modifier les conf et un peu d'astuce pour ne pas avoir une indisponibilité trop longue des divers services de mon kimsufi.

La stratégie de migration en Docker, là on a deux options un marathon de 48h ou y aller progressivement, container par container valider puis tous les containers.
Je prends la seconde option car je n'ai pas de fenêtre de 48h dans mon emploie du temps, juste une heure par-ci par-là. Donc le principe créer une image pour chaque service, et réaliser un run de chaque container puis réaliser les liens au travers d'un fichier docker-compose.yml
J'ai réalisé la 1er étape :



Sans trop de difficultés l'astuce est de réaliser le run du container nginx avec les options suivantes
--privileged=true --net=host 
Ainsi il n'y a pratiquement pas de modification à faire le la configuration de nginx. Par contre le processus nginx ne peut plus être supervisé par Monit... il reste les stats du container : 

CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O 
nginx               0.00%   10.22 MB/2.08 GB      0.49%     0 B/0 B

Tranquille tout ça.

J'oubliais ça peut-être intéressant les Dockerfile :

FROM nginx
MAINTAINER niclange
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y php5-fpm php5
RUN sed -i 's/;extension=gd.so/extension=gd.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=iconv.so/extension=iconv.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=mcrypt.so/extension=mcrypt.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=mysql.so/extension=mysql.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=sqlite3.so/extension=sqlite3.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=pgsql.so/extension=pgsql.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=ldap.so/extension=ldap.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=openssl.so/extension=openssl.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=pdo_pgsql.so/extension=pdo_pgsql.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=pdo_mysql.so/extension=pdo_mysql.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/;extension=pdo_sqlite.so/extension=pdo_sqlite.so/g' /etc/php5/fpm/php.ini
RUN sed -i 's/listen.owner = www-data/listen.owner = nginx/g' /etc/php5/fpm/pool.d/www.conf
RUN sed -i 's/listen.group = www-data/listen.group = nginx/g' /etc/php5/fpm/pool.d/www.conf
RUN sed -i 's/;listen.mode = 0660/listen.mode = 0660/g' /etc/php5/fpm/pool.d/www.conf
COPY nginx.conf /etc/nginx/nginx.conf
COPY users /etc/nginx/conf/users
COPY toto.crt /etc/ssl/private/
COPY titi.key /etc/ssl/private/
EXPOSE 80 443 442
Et oui j'ai ajouté php5-fpm mais je ne suis pas certain que cela soit pertinent.

vendredi 5 juin 2015

Combiner BitTorrentSync et Seafile

J'ai en place un serveur avec seafile, ça fonctionne bien, même très bien avec des fonctionnalités pertinentes. Bref c'est très pratique, mais BitTorrentSync est arrivé et le concept est aussi intéressant et peut répondre à une problématique : la synchronisation de 2 postes sur le même réseau local sans passer par le serveur sur internet.

Mais peut-on combiner les 2 produits pour synchroniser le même répertoire et bénéficier ainsi de tous les avantages :
  • BitTorrentSync :
    • utilisation du réseau local
    • pas de dépendance à un serveur central
  • Seafile :
    • un serveur central qui est presque toujours disponible (chez un hébergeur)
    • versioning et snapshot 
    • création de liens sécurisés pour partager accessibles tout le temps
    • interface web accessible
    • chiffrage côté serveur & coté client (option)

La réponse est oui, il peut y a voir quelques collisions de fichier mais Seafile semble bien s'en sortir en réalisant une duplication des fichiers qui lui posent problème. Mais le plus simple semble de mettre en pause la synchro Seafile lorsque que le répertoire se synchronise avec BitTorrent Sync.

Configuration des répertoires :


Ici le but est de synchroniser le répertoire "Ma Bibliothèque", le répertoire "save" est une sauvegarde de sécurité car les manipulations divers peuvent entraîner quelques pertes. "Seafile" est le répertoire de base de Seafile il n'est pas direchttp://seafile.com/en/help/ignore/tement synchronisé.

Voici les étapes :

  1. Mettre en place seafile et synchroniser 2 PC clients
  2. Ajouter un fichier seafile ignore : http://seafile.com/en/help/ignore/ avec le contenu suivant : .sync/
  3. Désactiver la syncho automatique
  4. Sur un premier PC installer BitTorrent Sync et partager le répertoier Ma Bibliothèque
  5. Installer BitTorrent Sync sur le second PC
  6. Vider le répertoire "Ma Bibliothèque" sur le second PC
  7. Là j'ai dû installer l'application Sync sur mon téléphone portable pour lier les 2 PC c'est le plus simple finalement
  8. Synchroniser avec BitTorrent Sync le second PC avec le répertoire "Ma Bibliothèque", là il devrait rapidement se synchroniser
  9. Activer la synchronisation de Seafile et vérifier que le répertoire .sync n'est pas synchronisé sur le serveur
Si tout marche cela devrait se stabiliser et aucune notification n’apparaît, si des notifications de synchronisation apparaissent c'est qu'un répertoire .sync/ est synchronisé, il peut aussi y avoir quelques collisions mais les fichiers sont faciles à identifier.

mercredi 28 janvier 2015

Logger les performances avec l'AOP dans une application n-tiers (Java)

La perf, un sujet incontournable, il sera mis tôt ou tard sur la table. Il faudra comprendre, améliorer, supprimer les points de contentions. Pour cela il est indispensable de réaliser des mesures. Un panel de solutions permettent de réaliser des mesures avec plus ou moins de finesse, dans diverses conditions.
Du temps d'exécution d'un test unitaire à un test de charge avec SoapUi ou JMeter, à une analyse de la jvm avec VisualVM ou Java Mission Control . Enfin en combinant tout ça on est certain d'arriver à une mesure fine et à identifier les axes d'optimisation. Mais à quel prix, ces outils on un coup non négligeable de mise en œuvre, et la traque prend du temps.

Une solution simple permettant de réaliser des rapports est la mise en place d'un logger par AOP s'appuyant sur l'architecture en couche (oui votre application est architecturée en couche). L'architecture en couche permettra l'utilisation de l'AOP de façon assez simple en interceptant les interfaces de chaque couche, et cela permettra de structurer le rapport. Cette approche est assez rapide et simple à mettre en oeuvre.

Pour cela j'ai développé un mini projet Log4Tiers (https://github.com/niclange/Log4Tiers) pour réaliser ces logs de performance, oui il est très simple et probablement beaucoup l'ont déjà implémenté. Il s'appuie sur Spring pour la mise en œuvre de l'AOP. On se place dans un contexte web, on va donc réaliser un log en tentant de suivre chaque appel au travers d'un identifiant (en rapport avec le thread), puis on identifiera chaque couche appelée et chaque méthode et les temps consommées.
Le plus complexe pour la mise en oeuvre est la configuration Spring de l'AOP.

Attention le fait de logger à un coût, et aura une impacte non négligeable, surtout si on log les éléments ayant une fine granularité, il faut donc en tenir compte, configurer la configuration AOP Spring en conséquence.

Vous trouverez un exemple complet dans la partie test unitaire du projet.
Je vais finir en ajoutant comment traiter le résultat du logger avec Excel.
On ouvre le fichier csv avec excel et on ajoute les entêtes des colonnes
En suite on peut réaliser un tableau croisé dynamique pour faire ressortir par exemple chaque appel :
Ou les couches de l'application :

A partir de là on peut réaliser toutes sortes de graphiques.


Sinon j'ai mis à jour le projet pour activer/désactiver les loggers par JMX.


jeudi 20 novembre 2014

Application N-Tiers et Frameworks

Voyons un peu ce que certains framworks, que l'on peut qualifier de standard apportent à l'architecture N-Tiers.


     IOC : Springframwork, Guice
THE framework, limite on ne peut plus s'en passer, il permet beaucoup de choses et surtout d'intégrer et configurer d'autres frameworks... bref c'est souvent la pierre angulaire du projet. Mais c'est tout simplement un framework IoC ou d'injection de dépendances. Il permet de mieux découpler les couches.  Ainsi on code avec les interfaces et c'est Spring qui se chargera (par la configuration ou les annotations) d'injecter l'implémentation. Point de factory, de singleton à implémenter soi-même.
Il n'a pas d'impact sur le nombre de couches mais il apporte une méthode élégante pour réaliser le couplage faible (par interface) entre les couches.

JEE permet aussi de réaliser l'injection avec une facilité équivalente (annotations)

Coté .NET on trouve des frameworks équivalents mais peut-être pas aussi bien aboutis avec le ServiceLocator et/ou les frameworks Unity, SimpleIOC et Castle. Encore que springframework.net semble palier à cela (promis prochain projet .net je le tente).

     ORM : JPA, Hibernate, Entity Framework 
Aujourd'hui les ORMs sont matures et permettent de masquer l'accès aux bases de données. Là on voit deux méthodes : ceux qui tiennent à la couche de DAO traditionnelle, cette dernière est alors triviale pour tout ce qui est CRUD, mais elle permettra d'isoler le code spécifique pour réaliser des fonctionnalités non prises en charge par l'ORM (rares).
Une approche plus moderne est de faire disparaître cette couche, de s'appuyer directement sur l'ORM depuis la couche métier, et de faire porter le CRUD et les requêtes complexes par le modèle (les classes d'entités de persistance) lui même.
Ainsi si on a une utilisation standard de la persistance dans une base de données relationnelle ou non (certaines base NoSql supportent les standard JPA ou JDO), l'ORM permet de remplacer la couche de DAO et simplifie grandement la structure du projet. C'est ce que l'on voit mis en oeuvre avec les approche de type Rails de Grails par exemple.

    Web Service : CXF (java), WCF (.net)
Les web service sont générés par des framework tiers. De même que les ORM, on peut piloter la mise en forme du message du service par des annotations sur le modèle d'échange (qui peut être ou non celui de persistance). Ce qui réduit l'implémentation d'un service à son strict minimum, seule l'interface est rédigée, l'implémentation est un passe plat qui appelle la couche métier.

     AOP : Spring AOP
L'Aspect Oriented Programing est un paradigme de programmation qui se place au dessus de la programmation orientée objet.
La mise en oeuvre de l'AOP dans une architecture en couche permet d'implémenter des responsabilités transverses aux couches d'architecture ou spécifique à une couche, une classe, une méthode. Bref cette technique est très flexible et elle permet élégamment de mettre en place une fonctionnalité transverse de type :
  • réalisation des logs
  • sécurité
  • gestion de caches
Cela permet de mettre un peu d'huile entre les différentes couche de l'application. En respectant un couplage faible par l'utilisation d'interface, grâce à ces dernières,  l'AOP se met en place avec un moindre coût.

     MVC : Struts, Spring MVC...
Les frameworks MVC our MVVM et autre permettent de réaliser la couche de présentation, mais même si eux même ont un découpage Modèle Vue Contrôleur, ou Modèle Vue VueModel, bref un découpage en 3 catégories il ne faut pas prendre ces dernières comme des couches d'architecture applicative. Peut-être qu'avec un peu de chance le Modèle du MVC correspondra au domaine de l'application. C'est typiquement ce qui arrive dans les architecture Rails ou par convention le domaine est afficher directement, le contrôleur semble être la couche métier et la vue la présentation... mais c'est du Rails. Dans les applications qui ont un peu d'historique et de complexité ce n'est pas le cas, le modèle du MVC est différent du modèle métier de l'application et appartient intégralement à la couche de présentation.

     DOZER :
Cet outil permet de recopier récursivement une grappe d'objet dans une autre grappe par réflexion et en utilisant un fichier de mapping, c'est un outil TRÈS PUISSANT... trop ? J'en parle car je l'ai vu mis en dans le but de découpler les couches logiques d'une application. OK ils disent que c'est un usage possible. Cela ne me semble pas une bonne pratique :
  • surcoût en terme de mémoire et CPU
  • maintenance complexe du code : une propriété doit être ajoutée à plusieurs classes et si son nom change un mapping spécifique dozer doit-être mis en place et testé.
Bref il ne faut mettre un tel outil que s'il apporte une valeur ajoutée importante sur un projet et dans le cadre d'une architecture en couche logique, je ne vois pas sa valeur ajoutée. Sauf dans des cas particuliers, avec un historique lourd... et alors c'est le dernier espoir...