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...