Dans un précédent billet, je vous ai présenté les solutions mises en œuvre sur un projet pour paralléliser un batch d’indexation alimentant un moteur de recherche d’entreprise. Utilisée pour initialiser l’index de recherche puis le resynchroniser quotidiennement, la technique d’intégration par batch ne permet cependant pas d’indexer les données au fil de l’eau. Ce billet aborde précisément cet aspect. En effet, le fil de l’eau ou le quasi temps réel fut dès le départ une exigence forte du métier. Recherches instantanées et auto-complétion révolutionnent le traditionnel formulaire de recherche mettant plusieurs secondes à renvoyer les résultats. Mais au prix de faire des recherches sur des données pouvant dater de J-1 ? Ce n’était pas acceptable ! Un middle d’indexation fut la réponse apportée. Continuer la lecture
Archives de l’auteur : Antoine
Une bien mystérieuse UnknownHostException
Après un précédent billet relatant un bug lié à la version du driver Oracle utilisé, voici un nouveau billet portant sur bug lié, cette fois ci, à la version de la JVM utilisée. Ce bug nous a été révélé très tardivement dans le cycle de développement de l’application Java incriminée. En effet, PV de recette en poche, les tests de charge menés avec JMeter sur l’environnement de pré-production ne nous avaient rien révélé. Seuls les tests de robustesse nous ont alertés d’une mystérieuse java.net.UnknownHostException survenant 4 à 5 minutes après l’arrêt volontaire d’une application tierce. Continuer la lecture
Oracle : dis-moi quelle heure est-il ?
Récemment, je suis tombé sur un bug lié à l’utilisation d’une version de driver JDBC pour Oracle plus récente que la version de la base Oracle attaquée en SQL via JDBC.
Les symptômes
Dans notre contexte applicatif, la date et l’heure des données lues en base sont utilisées pour détecter des conflits de version, d’une manière similaire au versioning Hibernate. Concrètement, cela nous permet d’éviter qu’une donnée traitée par batch quotidien écrase une donnée plus fraiche provenant d’un système tiers. Ce mécanisme permet notamment d’exécuter un batch sans interruption de service de l’application web associée. Le bug que je vais vous décrire nous a été révélé tardivement. Sous certaines conditions, nous avons en effet constaté que le batch ne rattrapait jamais des données. C’est comme si l’heure n’était jamais prise en compte dans le code Java. Continuer la lecture
Isoler le classloader de son EAR sous JBoss
Lors de la migration d’une application d’un serveur d’application vers un autre, il est fréquent d’être confronté à des problématiques de conflits de librairies. C’est par exemple le cas lorsqu’une application initialement déployée sur un Websphere Application Server 6.1 doit migrer sur JBoss 5.1 EAP (version commerciale de JBoss AS).
Pour rappel, WAS 6.1 implémente J2EE 1.4 et s’exécute donc sur Java 5. Quant à JBoss 5.1 EAP, il implémente la norme Java EE 5, embarque donc de nombreuses implémentations des standards tels que JPA 1, JSF 1.2 et JAX-WS 1, et tourne sur Java 6. Continuer la lecture
Ma petite usine logicielle
Suite à une question qui m’a récemment été posée sur Github, j’ai réalisé que ce que j’avais mis en place pour des besoins personnels pouvait intéresser d’autres développeurs.
Dans ce billet, je vais donc vous expliquer comment créer votre propre usine logicielle. Déployée à cheval sur GitHub et l’offre DEV@Cloud de CloudBees, vous y retrouverez les briques les plus classiques : SCM, intégration continue, dépôt de binaires, bug tracker, wiki …
Le gain : à chaque commit poussé dans GitHub, votre code est compilé, testé unitairement puis déployé dans un repository maven public dédié aux Snapshots. Par ailleurs, vous pourrez effectuer des releases maven en local depuis votre poste de développement ; les artefacts construits seront mis à disposition dans un repository maven dédié. Tout développeur pourra librement référencer l’un ou l’autre de ces repository et utiliser votre code.
En bonus, si vous développez des projets open source, vous n’aurez même pas à sortir votre carte bancaire.
Continuer la lecture
Parallélisation de traitements batchs
Contexte
Récemment, j’ai participé au développement d’un batch capable d’indexer dans le moteur de recherche Elasticsearch des données provenant d’une base de données tierce. Développé en Java, ce batch s’appuie sur Spring Batch, le plus célèbre framework de traitements par lot de l’écosystème Java
Plus précisément, ce batch est décomposé en 2 jobs Spring Batch, très proches l’un de l’autre :
- le premier est capable d’initialiser à partir de zéro le moteur de recherche
- et le second traite uniquement les mouvements quotidiens de données.
Problématique
Au cours du traitement batch, l’exécution de la requête par Oracle pour préparer son curseur a été identifiée comme l’opération la plus couteuse, loin devant la lecture des enregistrements en streaming à travers le réseau, leur traitement chargé de construire les documents Lucene à indexer ou leur écriture en mode bulk dans ElasticSearch. A titre d’exemple, sur des volumétries de production, la préparation côté serveur Oracle d’une requête SQL ramenant 10 millions d’enregistrement peut mettre jusqu’à 1h30.
Avec pour objectif que le batch passe sous le seuil de 2h à moindre coût, 2 axes d’optimisations ont été étudiés : diminuer le temps d’exécution par Oracle et diminuer le temps de traitement.
Solutions étudiées
Les optimisations d’un DBA consistant à utiliser des tables temporaires et des procédures stockées n’ont pas été concluantes : trop peu de gains (10 à 20%) pour une réécriture partielle de notre batch, et avec le risque d’engendrer des régressions.
Après mesures et calculs, l’utilisation de la pagination sur des plages de 100, de 1 000 ou même de 10 000 enregistrements a également été écartée. Dans notre contexte, cela aurait dégradé les performances. Le choix de rester sur l’utilisation d’un curseur JDBC a été maintenu.
A cette occasion, nous avons remarqué que les temps de mise en place d’un curseur Oracle pour préparer 1 millions ou 10 millions d’enregistrements étaient du même ordre de grandeur.
Utilisant déjà l’une des techniques proposées par Spring Batch pour paralléliser notre traitement batch, pourquoi ne pas refaire appel à ses loyaux services ?
Continuer la lectureEnterprise Spring Integration Certification Mock Exam
Last month, I passed the Enterprise Integration with Spring exam (EIwS 1.x) with a score of 90%. This test is also known as Certified Enterprise Integration Specialist exam. Before passing this exam, you have to attend Enterprise Integration with Spring training from SpringSource or a Certified Partner.
In my last blog entry, I have published a french study guide / notes to the exam. Since, I received a few emails asking me some materials in English.
Opposed to the Spring Core Certification, I didn’t find any mock exams for the . So I decided to create a mock exam like I did in my Core Spring 3.0 Certification Mock Exam blog entry. The questions are close to the real Enterprise Integration with Spring exam and I hope will help you in practicing for the test or to test your Spring Integration proficiently. I have tried to keep my exam accurate, based on my real exam-experience. Continuer la lecture
Certified Spring Enterprise Integration Specialist Study Notes
En l’espace de 8 mois, me voici doté d’une deuxième certification Spring. Après la certification Spring Core dont je vous ai fait écho dans mon tout premier billet, j’ai eu l’opportunité de préparer la certification Spring Integration Specialist.
Comme à l’accoutumée avec les certifications Spring, la formation officielle Spring Enterprise Integration est pré-requise. Elaborée par SpringSource et dispensée par Zenika, cette formation couvre de nombreux sujets basés sur Spring Framework 3 et différents projets du Portfolio Spring : Continuer la lecture
Délimiteurs de filtre maven sur plusieurs caractères
Contexte
Chez mon client, les fichiers de configuration sont variabilisés (ex : fichiers de configuration logback, hosts des différents référentiels et back office, paramétrage applicatif, configuration ehcache …). Cette technique permet d’avoir le même gabarit quel que soit l’environnement sur lequel est déployée l’application (ex : intégration, recette, production). Charge à l’outil de déploiement de générer le fichier de configuration final à partir du gabarit et du fichier de variables spécifiques à l’environnement cible sur lequel le déploiement s’effectue.
Continuer la lecture
Spring Batch s’auto-nettoie
Lorsque vous mettez en œuvre Spring Batch pour réaliser des traitements par lots, vous avez le choix d’utiliser une implémentation de JobRepository soit en mémoire soit persistante. L’avantage de cette dernière est triple :
- Conserver un historique des différentes exécutions de vos instances de jobs.
- Pouvoir suivre en temps réel le déroulement de votre batch via, par exemple, l’excellent Spring Batch Admin.
- Avoir la possibilité de reprendre un batch là où il s’était arrêté en erreur.
La contrepartie d’utiliser un JobRepository persistant est de devoir faire reposer le batch sur une base de données relationnelles. Le schéma sur lequel s’appuie Spring Bath est composé de 6 tables. Leur MPD est disponible dans l’annexe B. Meta-Data Schema du manuel de référence de Spring Batch. SpringSource faisant bien les choses, les scripts DDL de différentes solutions du marché (ex : MySQL, Oracle, DB2, SQL Server, Postgres, H2 …) sont disponibles dans le package org.springframework.batch.core du JAR spring-batch-core-xxx.jar
Qui dit base de données, dit dimensionnement de cette dernière. L’espace disque requis est alors fonction du nombre d’exécutions estimé, de la nature des informations contextuelles persistées et de la durée de rétention des données. Cette démarche prend tout son sens lorsqu’une instance de base de données est dédiée au schéma de Spring Batch. En faisant quelques hypothèses (ex : sur le taux d’échec) et en mesurant le volume occupé sur plusieurs exécutions des batchs, il est possible de prévoir assez finement l’espace occupé par les données.
A moins de disposer de ressources infinies ou de n’avoir qu’un seul batch annuel, il est fréquent de fixer une durée de rétention de l’historique. Première option : demander à l’équipe d’exploitation de régulièrement lancer un script SQL de purge. Deuxième option : utiliser Spring Batch pour purger ses propres données !!
Continuer la lecture