JQM, un serveur de batchs asynchrones en Java

Posté par  . Édité par Benoît Sibaud, Sebastien, palm123 et claudex. Modéré par Ontologia. Licence CC By‑SA.
Étiquettes :
19
24
déc.
2013
Java

JQM (Job Queue Management) est un gestionnaire de batch sous licence Apache qui permet de traiter sur des noeuds de traitement répartis toutes les tâches potentiellement longues qui ne sont pas désirables dans un serveur d'application à travers un système de files d'attente. Ce logiciel s'adresse à toute application qui souhaite gérer l'exécution de ses tâches hors du serveur d'application.

Une tâche peut être déclenchée depuis un appel Web Service ou une API par une application web, un ordonnanceur ou un flux d'interface.

L'outil propose de nombreuses fonctionnalités comme l’arrêt d’une tâche, la récupération de fichiers générés, la priorisation d’une tâche et bien d’autres. JQM a été développé en Java SE 1.6, utilise Hibernate/JPA 2.0 comme ORM, et une base de donnée comme référentiel de configuration et file d'attente des traitements. JQM est compatible avec les bases HSQL, MySQL et Oracle, les serveurs d’application WebSphere et Glassfish (prochainement Tomcat) pour l'API cliente et gère les ressources JNDI pour les bases de données et les brokers de messages.

L'outil est compatible avec les projets Maven et tout particulièrement la gestion des dépendances et des projets parents.

Architecture

JQM est composé de trois grandes parties :

  • les moteurs de traitements (des JVM standalone) qui exécutent les tâches. Il est possible de déployer plusieurs moteurs (ou noeuds) de traitements pour des raisons de performance ou de haute disponibilité
  • une base de données qui joue le rôle de file de traitement et de référentiel de configuration
  • les clients (une application Web dans un serveur d'application, une ligne de commande, un ordonnanceur, une autre tâche (job) JQM etc.) qui soumettent des tâches à JQM

Les noeuds de traitement sont reliés à des files de traitement en base de données et ont chacun un intervalle de polling et un nombre défini de tâches pouvant tourner simultanément.

Par exemple:

  • VIPqueue = 10 tâches en simultané + intervalle de polling de 1 seconde
  • SLOWqueue = 3 tâches en simultané + intervalle de polling de 15 min

schema_JQM

Cycle de vie d'une tâche

Le cycle de vie d'une tâche passe par quatre états différents.

Après avoir été ajoutée à la file d'attente, la tâche prend le status SUBMITTED. Une fois que la tâche est "attrapée" par un noeud, son statut passe à l'état ATTRIBUTED suivi de RUNNING une fois que l'exécution de celle-ci a commencé.

La tâche à la fin de son exécution a deux états possibles, CRASHED si la tâche n'a pas fonctionné correctement ou ENDED si tout le processus s'est déroulé correctement.

Cycle_de_vie_d'une_tache

Fonctionnalités

Pour les développeurs

  • Pour les développeurs de traitement :
    une tâche est définie comme telle une fois qu'elle étend (extends) la classe JobBase de l'API jqm-api.
    Au sein d'une tâche, il est possible de récupérer des ressources via JNDI (base de données, broker de message, répertoire de traitement…), d'envoyer une progression, un message de log ou de mettre en file une autre tâche.

  • Pour les clients des traitements :
    Il existe plusieurs moyens d'utiliser
    JQM.

    • Par le biais de l'API jqm-clientapi qui permet d'avoir toutes les fonctionnalités existantes, à savoir la possibilité de mettre une tâche en file, de regarder son état, de l'annuler, de le changer de file et bien d'autres ;
    • Par le biais d'un web service ;
    • Par une interface en ligne de commande ;
    • Par une IHM web (très frustre à l'heure actuelle).

Pour les administrateurs

Un administrateur a la possibilité de consulter les logs, de gérer les connexions JNDI, de paramétrer les associations entre les tâches et les files.

Exemple de tâche

public class Caller extends JobBase
{
    @Override
    public void start()
    {
        Map<String, String> params = new HashMap<String, String>();
        p.put("myParam1", "Pouet");
        p.put("myParam2", "tut tut");
        // enQueue is a JobBase method.
        // It is used to enqueue a Job, here “Called”.
        enQueue("CalledJob", "Bob", null, null, null, null, null,          
                        null, null, null, null, params);
        }
}

Exemple d'intégration de JQM dans un SI

Dans cet exemple, JQM est utilisé pour gérer une intégration au fil de l'eau de message dans un ERP qui ne possède qu'une interface d'entrée de type table / prodédure stockée.

JQM joue un rôle de « joint de dilatation » entre un système événementiel qui gère des pics à 200 000 messages par heure et une interface de type procédure stockée qui traite des données en masse mais ne se prête pas à de nombreuses exécutions simultanées.

Chaque message est traité par un thread d'un conteneur MDB (Message Driven Bean) et déclenche une tâche JQM. La file de tâches JQM est paramétrée pour n'exécuter qu'une seule tâche à la fois et annuler les lancements surnuméraires. La tâche lance la procédure stockée de l'ERP qui traite toutes les données en attente dans la table d'interface.

En pic, plusieurs centaines de messages n'occasionneront qu'un ou deux lancement de la procédure stockée qui traitera en masse les données. Le système permet ainsi de rester très réactif en période creuse (au contraire des systèmes de type batch cyclique) tout en permettant la montée en charge lors des pics.

integration_JQM

Origine du projet

Le projet a été développé par la société Enioka dans le cadre d'un projet pour l'un de ses clients pour l'intégration d'un ERP.

Suite à la réalisation de ce projet, il a été convenu que JQM deviendrait open source afin de combler le manque actuel de ce type d'outils libres dans un contexte java SE/EE 6.

Le code source et la documentation sont disponibles sur Github.

Aller plus loin

  • # Soucis de mise en page

    Posté par  (site web personnel) . Évalué à 1.

    Tout à partir de la section "Exemple d'intégration de JQM dans un SI" est pris dans le bloc de code juste au-dessus. Merci les modérateurs de rattraper ça.

    • [^] # Re: Soucis de mise en page

      Posté par  . Évalué à 3.

      Corrigé, merci. (c'est un soucis de rendu entre la rédaction/modération et la publication)

      « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

  • # Questions

    Posté par  . Évalué à 3.

    Merci pour cette dépêche.

    Ce logiciel s'adresse à toute application qui souhaite gérer l'exécution de ses tâches hors du serveur d'application.

    Quelles sont les raisons qui poussent à ce qu'une tâche ne soit pas dans un serveur d'application ?

    […] les serveurs d’application WebSphere et Glassfish (prochainement Tomcat) pour l'API cliente […]

    Je ne comprends pas bien ce que ça signifie.

    […] gère les ressources JNDI pour les bases de données et les brokers de messages.

    Il y a quelque chose de particulier pour l'aider ou c'est juste que les tâches peuvent aller chercher dans un annuaire JNDI des infos ?

    Les noeuds de traitement sont reliés à des files de traitement en base de données et ont chacun un intervalle de polling et un nombre défini de jobs pouvant tourner simultanément.

    Ça marche avec du polling des nœud de traitement ? Donc toute la capacité de monté en charge est déportée sur la base de données et on prend une charge importante même quand on a rien à faire (si on a beaucoup de nœuds de traitement), non ?


    Plus généralement, j'ai du mal à voir l'intérêt face à JMS. Il est tout à fait possible de gérer des traitements de ce genre via des files JMS distribuée. Un avantage des MDB c'est la possibilité de placer les traitements (envoi d'autres messages JMS et accès en base de données) dans une transaction. Il est possible de manipuler les files via JMX.

    Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

    • [^] # Re: Questions

      Posté par  . Évalué à 2.

      Je me permets de rajouter une question : Qu'en est-il de l'intégration avec Spring Batch, ou encore Java Batch (introduit dans Java EE 7, JSR 352) ? JQM vient redéfinir des concepts de la spec, ou peut-il s'interfacer avec ? Est-il prévu de se conformer à la spec, s'il n'est pas prévu de s'interfacer ?

      • [^] # Re: Questions

        Posté par  . Évalué à 3.

        Spring Batch et JavaBatch définissent surtout une structure de batch (gestion des paramètres, découpage en sous tâches, normalisation des codes retours…) mais ni un conteneur ni une file batch ; ce qui est l'objet de JQM.

        Nous étions sur un projet avec une stack EE6, donc ni spring ni EE7, Néanmoins l'étude la JSR352 a été une source d'inspiration et il y aurait intérêt à se rapprocher le plus possible de la norme. Néanmoins une implémentation complète de la JSR352 représentait trop de boulot dans le délai imparti. Mais c'est une reflexion intéressante à inscrire dans la roadmap de JQM. Tout en se rappelant que JQM fait des choses que JSR352 ne propose pas.

    • [^] # Re: Questions

      Posté par  . Évalué à 3.

      Beaucoup de questions intéressantes :-). Je vais essayer de répondre dans l'ordre.

      Quelles sont les raisons qui poussent à ce qu'une tâche ne soit pas dans un serveur d'application ?

      Un serveur d'application permet de gérer beaucoup de tâches courtes et rapidement. Il possède un nombre de thread limité. Prenons par exemple une édition PDF un peu lourde qui demande 5 minutes de génération. Dès qu'un utilisateur clic dessus un thread du serveur est scotché. Plusieurs utilisateurs et le serveur d'appli est bloqué. Sans parler du fait que l'utilisateur, devant son écran en cours de chargement pendant 5 minutes va rappuyer plusieurs fois et accélérer la course vers la catastrophe.

      […] les serveurs d’application WebSphere et Glassfish (prochainement Tomcat) pour l'API cliente […]

      L'API cliente pour soumettre des jobs a été testée avec GlassFish et Websphere. Pour Tomcat il y a encore des petits pépins pour récupérer la connexion à la base de donnée. Les déclarations JNDI diffèrent entre ces serveurs d'applications. Merci Java, write once, debug everywhere :-)

      […] gère les ressources JNDI pour les bases de données et les brokers de messages.

      JQM est un serveur JNDI pour les batch afin de leur fournir l'accès à des bases de données, des broker de message ou même des répertoires (ce qui est classique pour des batch qui créés des fichiers.

      Ça marche avec du polling des nœud de traitement ? Donc toute la capacité de monté en charge est déportée sur la base de données et on prend une charge importante même quand on a rien à faire (si on a beaucoup de nœuds de traitement), non ?

      Oui, cela fonctionne par polling. Cela ne pose pas de problème pour monter en charge dans la plupart des cas. Chaque moteur possède plusieurs slots de traitement. Il y a donc un polling par moteur (=1 JVM).
      Clairement, JQM n'est pas fait pour faire du grid computing pour faire un serveur batch d'une application. Une installation typique comporte 4 à 6 moteurs avec une fréquence de polling entre 1 sec pour les plus courts et 1 minute pour les plus lents. Pas de quoi faire éternuer une base de données :-)

      Plus généralement, j'ai du mal à voir l'intérêt face à JMS. Il est tout à fait possible de gérer des traitements de ce genre via des files JMS distribuée. Un avantage des MDB c'est la possibilité de placer les traitements (envoi d'autres messages JMS et accès en base de données) dans une transaction. Il est possible de manipuler les files via JMX.

      C'était une autre possibilité. Mais les MDB sont toutefois peu adaptés aux traitements long et ne permettent pas de gérer certaines fonctionnalités comme l'annulation de lancements mulitples. Quant à la gestion des transactions avec les MDBs… ok, pas de troll.

      • [^] # Re: Questions

        Posté par  . Évalué à 2.

        Quant à la gestion des transactions avec les MDBs… ok, pas de troll.

        Dommage c'etait la question qui m'interessait le plus et est absolumment necessaire dans un contexte JavaEE :)

        Par ailleurs, Spring Batch est tout a fait utilisable dans du JavaEE.
        Il faut juste lui dedier un thread pool qui peut s'etendre sur tout un cluster (attention au cout des licences/du support tout de meme).

        • [^] # Re: Questions

          Posté par  . Évalué à 2.

          Le fonctionnement des MDB pousse à utiliser JTA, faire des transactions XA entre plusieurs ressources manager (base de données et broker de message).
          Dans les faits, c'est une galère pas possible à mettre en marche et de plus c'est horriblement lent. Il est préférable de gérer deux transactions séparés, manuellement (bean managed) et de gérer au niveau applicatif le cas d'un crash entre les deux commits (c'est à dire un doublon si les commits sont dans le bon ordre).

          SprintBatch est compatible EE… cela veut dire deux framework de dév pour les développeurs. Et quid d'un morceau de code qui est utilisé à la fois en batch et en interactif ? C'est un peu mélanger l'eau et le feu.

          • [^] # Re: Questions

            Posté par  (site web personnel) . Évalué à 2.

            Dans Weblogic l'inscription dans une transaction distribuée est réalisée par la "connection factory", c'est une case à cocher dans la console (pour JDBC il faut aussi s'assurer que l'on utilise un pilote compatible).

            Pour les performances il y a forcément un coût, tu ne peux pas établir un consensus dans un environnement distribué de manière simple mais avec des "file stores" sur des disques dédiés ça marche très bien et avant de se dire que l'on va réinventer la roue il suffit de connaître la complexité des problématiques de consensus (flp ,paxos..) pour laisser faire les gens qui maîtrisent le sujet surtout dans des environnements JEE rodés qui offrent cette possibilité.

            Coté fiabilité ça fait plusieurs années qu'on fait du commit à 2 phases sur plusieurs millions de transactions par jour (avec en moyenne 3 ressources participantes) et on a eu un seul cas d'heuristique suite à une erreur d'exploitation.

            • [^] # Re: Questions

              Posté par  . Évalué à 2.

              Non, c'est une illusion… XA coûte réellement en mise en place, tests, debug et en perf. De plus, dès qu'on traite un peu de volume on va avoir envie de gérer plusieurs transactions. Enfin, une application se doit bien souvent de traiter les cas de doublons applicatifs en cas de réémission par l'expéditeur. Alors autant avoir un seul mécanisme fiable au niveau applicatif avec des statuts d'exécution et des identifiants fiables que (trop) se reposer sur les middlewares.

              • [^] # Re: Questions

                Posté par  . Évalué à 3.

                Non, c'est une illusion… XA coûte réellement en mise en place, tests, debug et en perf.

                La question est est-ce que c'est plus chère ou pas que de gérer la cohérence manuellement (là aussi en prenant le coût de la mise en place, du test et du debug).

                Comme tu le dis quand tu dois faire des vérifications métier ça peut être moins chère (parce que ça peut faire doublon), mais pas toujours (par exemple la gestion des doublons peut être géré à un autre endroit de l'application soit avant soit après).

                Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                • [^] # Re: Questions

                  Posté par  . Évalué à 1.

                  Quand tu as deux transactions avec deux resources managers, l'algo n'est pas du tout diabolique. En particulier dans le cas de la lecture d'un message JMS et l'écriture en base. En gros :
                  - début transaction JMS, lecture du message
                  - début transaction base de données
                  - traitement…
                  - si tout va bien : commit base de données puis commit broker JMS
                  - si tout va mal : rollback des deux.

                  Bon, maintenant, le pire cas, que se passe-t-il quand, pas de pot (cas rare, mais qui peu exister) ton serveur meurt lamentablement entre les deux commits. Cela fait que ta transaction en base est validée, mais ta transaction avec ton broker est en rollback. Donc, à la prochaine exécution ton code lira pour la seconde fois le même message. Soit ce n'est pas gênant (youpi), soit c'est un problème, dans ce cas il faut pouvoir le gérer (identifiant fonctionnel, etc.).

                  Simple à coder, simple à débugguer. Pas de dépendance sur des trucs compliqués. Pas de risque de tout casser lors d'un patch ou d'une montée de version (du moins pas à ce niveau :-)).

                  • [^] # Re: Questions

                    Posté par  . Évalué à 3.

                    Quand tu as deux transactions avec deux resources managers

                    Et quand tu as plus ? (des messages JMS envoyé et des commits en base par exemple)

                    Bien sûr que quand tout est simple, tout est simple.

                    Simple à coder, simple à débugguer. Pas de dépendance sur des trucs compliqués. Pas de risque de tout casser lors d'un patch ou d'une montée de version (du moins pas à ce niveau :-)).

                    AMHA la maintenance est plus complexe parce qu'il faut garder en tête la manière dont tu fait ta transaction et gérer le commit/rollback pour chaque nouvelle action alors que lorsque tu utilise le gestionnaire du middleware il suffit d'ajouter chaque action à la transaction (sauf cas particulier). Grosso modo il faut s'assurer que tu garde ta cohérence d'un coté il s'agit d'ajouter ou non des action dans la transaction de l'autre il faut vérifier que l'équivalent des commits/rollback fonctionne bien. Ça peut même déborder sur le reste de l'application selon la manière que tu as de le gérer. Ce qui augmente le couplage.

                    C'est quelque chose qui s'évalue au cas par cas.

                    Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                    • [^] # Re: Questions

                      Posté par  . Évalué à 1.

                      Et quand tu as plus ? (des messages JMS envoyé et des commits en base par exemple)

                      Cela fait toujours deux ressources managers :-)

                      Blague à part, tant que tu es dans une logique tout ou rien, le code reste simple. Si de toute façon tu veux commencer à gérer finement les transactions en fonction des cas d'erreur, tu devras passer en mode manuel.

                      De plus, si tu as beaucoup (>>2) de ressources managers à coordonner, le coût du XA va également augmenter… et il faut sans doute se demander s'il est bien raisonnable de gérer autant de ressources synchronisées dans une seule transaction. En cas de pépin, la resynchro sera pénible (et XA ou pas, il y a toujours des cas ou on doit le faire, donc autant avoir un système robuste…).

                      Je ne dis qu'XA est inutile dans l'absolu (et mettre en place du XA aujourd'hui est moins aléatoire qu'il y a 10 ans) ; cela s'évalue au cas par cas comme tu le soulignes, mais dans 99% des cas c'est un réel overkill qui amène son lot de bug et de complexité car les gens ont peur de gérer deux malheureuses transactions à la main ou font du XA par conformisme (2 transactions=>XA…). Heureusement, cela n'est pas une fatalité.

                      • [^] # Re: Questions

                        Posté par  . Évalué à 2.

                        et il faut sans doute se demander s'il est bien raisonnable de gérer autant de ressources synchronisées dans une seule transaction.

                        Un peu comme faire 15 000 actions dans un batch ? :)

                        Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

              • [^] # Re: Questions

                Posté par  (site web personnel) . Évalué à 1.

                Sauf que sur un système d'information même modeste des applicatifs qui échangent en JMS tu vas en avoir à la pelle.
                Si j'ai un bug sur la couche XA c'est juste un patch à pousser sur mes domaines Weblo, développer les fonctionnalités dont tu parles sur toutes les applications qui veulent assurer la cohérence de leurs données c'est me retrouver avec autant de mécanismes à tester et à maintenir et non pas un seul, dans notre contexte (nombre d'équipes de dev, turn-over…) je ne veux même pas imaginer :)
                J'ai l'impression que l'on est pas confronté aux mêmes problématiques, d'où le désaccord.

          • [^] # Re: Questions

            Posté par  . Évalué à 3. Dernière modification le 31 décembre 2013 à 19:29.

            Dans les faits, c'est une galère pas possible à mettre en marche et de plus c'est horriblement lent.
            Comme dit dans un commentaire ci-dessous, le mettre en marche, c'est juste un case a cocher avec WebLogic ou WebSphere. Je ne sais pas pour JBoss.
            Oui il y a un surcout a l'execution et c'est une des raisons pour lesquelles certains abandonnent XA pour revenir a l'architecture que tu decris ci-dessous.

            Il est préférable de gérer deux transactions séparés, manuellement (bean managed) et de gérer au niveau applicatif le cas d'un crash entre les deux commits (c'est à dire un doublon si les commits sont dans le bon ordre).

            Oui si tu as beaucoup de temps a passer pour gerer absolument tous les cas d'erreurs de ton application de maniere propre.
            Bon dans les entreprises qui ont aussi d'autres choses a faire, on fait du XA et il n'y a pas de code supplementaire a ecrire, et ca marche tres bien. Il y a une perte de perf mais si ton appli passe son temps a rappatrier des donnees de la Bd, le surcout d'X est negligeable.

            SprintBatch est compatible EE… cela veut dire deux framework de dév pour les développeurs.

            C'est pas la mer a boire quand tu geres 30 librairies "tirees" depuis maven central.

            Et quid d'un morceau de code qui est utilisé à la fois en batch et en interactif ? C'est un peu mélanger l'eau et le feu.

            Ca, ca peut etre un probleme en effet. Mais toute appli un peu complexe va avoir du batch est de l'interactif.
            Si je me souviens bien, la ou Spring Batch n'etait pas tres bon c'etait pour demarrer un batch paramétré de maniere interactive.

             

            En tout cas merci de tes reponses, c'est interessant car ca donne a reflechir.

            • [^] # Re: Questions

              Posté par  . Évalué à 2.

              le surcout d'XA est negligeable

              Tu comptes le surcoût de temps de réponse lors de l'exécution du traitement, et juste ce surcoût là j'imagine.
              Non parce qu'il y a le surcoût de complexité, de maintenabilité (pas seulement de l'appli mais aussi de toute la stack middleware), etc. et ceux-là ne sont pas négligeables. Ou du moins ils ne le sont pas dès que tu as passé les 8 semaines après la première livraison de ton appli en prod.

              De plus envisager d'utiliser XA en batch de façon automagique dans un MDB, c'est faire l'hypothèse que tout le traitement tient dans une transaction. Et en général pour un batch c'est impossible. Sans parler du fait que même quand ça rentre (par miracle) dans les ressources allouables sur la base et ailleurs, c'est une mauvaise idée d'avoir un scope de transaction énorme.

              • [^] # Re: Questions

                Posté par  . Évalué à 2.

                Traitement en batch ne veut pas forcément dire traitement long et/ou couteux. Du moins pas aussi long que tu ne semble l'imaginer.

                Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

              • [^] # Re: Questions

                Posté par  . Évalué à 3.

                Tu comptes le surcoût de temps de réponse lors de l'exécution du traitement, et juste ce surcoût là j'imagine.

                Tout a fait.

                Non parce qu'il y a le surcoût de complexité, de maintenabilité (pas seulement de l'appli mais aussi de toute la stack middleware), etc. et ceux-là ne sont pas négligeables. Ou du moins ils ne le sont pas dès que tu as passé les 8 semaines après la première livraison de ton appli en prod.

                Oui, oui, mais puisqu'il faut tester toute la stack de toute maniere…

                De plus envisager d'utiliser XA en batch de façon automagique dans un MDB, c'est faire l'hypothèse que tout le traitement tient dans une transaction. Et en général pour un batch c'est impossible. Sans parler du fait que même quand ça rentre (par miracle) dans les ressources allouables sur la base et ailleurs, c'est une mauvaise idée d'avoir un scope de transaction énorme.

                Ca commence souvent en parvenant a tenir dans une seule transaction, puis au cours du temps, les volumes augmentent, les requirements changent et/ou s'amoncellent finissant par provoquer des incidents de production P1 dans des cas patologiques. Il faut alors changer l'architecture du logiciel sur cette partie.
                Je suis d'accord qu'avoir une scope de transaction enorme est une mauvaise idee en theorie, mais en pratique si ton appli fait 15000 choses (progiciel metier bien complexe) et que tu n'a pas le temps d'etudier la facon dont elle est utilisee, et bien tu pares au plus presse et tu fait le pompier de temps en temps. Bref je suis d'accord en theorie, mais selon l'environnement dans lequel tu travailles et selon les contraintes que tu as, ca n'est pas faisable en pratique.

                 

                Mais je trouve la discussion interessante. Merci beaucoup.

                • [^] # Re: Questions

                  Posté par  . Évalué à 2.

                  Je suis d'accord qu'avoir une scope de transaction enorme est une mauvaise idee en theorie, mais en pratique si ton appli fait 15000 choses (progiciel metier bien complexe) et que tu n'a pas le temps d'etudier la facon dont elle est utilisee, et bien tu pares au plus presse et tu fait le pompier de temps en temps.

                  Je te comprends, mais c'est là qu'il faut à mon avis penser à séparer les actions en composants éventuellement réutilisables. Ça permet d'avoir des parties plus petites et donc plus simples à tester (c'est pas forcément simple à faire à cause de pleins de choses). C'est là que tu commence à multiplier le nombre d'envois JMS d'ailleurs et donc que la transaction devient importante.

                  Au passage ça permet de gérer assez facilement la monté en charge (les actions sont découpées comme dans un pipeline et chaque étape peu être parallélisée).

                  Après des batch aussi énormes que ce dont tu parle ça n'est pas forcément très courant.

                  Mais je trouve la discussion interessante. Merci beaucoup.

                  Idem (pour l'ensemble des commentaires d'ailleurs).

                  Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                  • [^] # Re: Questions

                    Posté par  . Évalué à 2.

                    Après des batch aussi énormes que ce dont tu parle ça n'est pas forcément très courant.

                    Ça va vite même sans être la NSA… dès que tu as plusieurs centaines de milliers de lignes à insérer ou mettre à jour, tu vas avoir très très envie de gérer des commits intermédiaires pour des raisons de perf. Et donc de te passer de la gestion des transactions des middlewares pour gérer tes points de reprise. C'est donc à adapter en fonction de chaque type de batch et de sa volumétrie.

                    • [^] # Re: Questions

                      Posté par  . Évalué à 1.

                      Ça va vite même sans être la NSA…
                      Oui ce fut le cas pour nous avec un modele de donnees comme suivant ou l'on a un pipe line qui contient de plus en plus de donnees (chaque D represente le volume de donnees):

                      D => DD => DDD => DDDD => DDDDD
                      1 => 1000 -> 10000 -> 100000

                      sachant que la premiere etape (geree par JMS) les volumes etaient aussi en train d'exploser, et il a fallu commencer a dedupliquer les donnees en entree.
                      Le modele etait ainsi fait que plus l'on avancait dans le pipeline et plus les donnees etaient volumineuses et complexes a gerer avec des regles metiers parfois completement opposees selon le type de donnees.
                      Hyper interessant, mais pas top quand tes collegues ne sont pas au niveau du challenge :(

                      dès que tu as plusieurs centaines de milliers de lignes à insérer ou mettre à jour, tu vas avoir très très envie de gérer des commits intermédiaires pour des raisons de perf. Et donc de te passer de la gestion des transactions des middlewares pour gérer tes points de reprise. C'est donc à adapter en fonction de chaque type de batch et de sa volumétrie.

                      Le probleme etait:

                      1. l'architecture pas adaptee au volume de donnees
                      2. la difficulte a casser les sacro saintes transactions en devant convaincre l'humain (en particulier lorsque les requirements faisaient que ca ne tiendrait plus jamais dans une seule transaction) 1.1. les analystes metiers 1.1. les clients

                      Les analaystes metiers etaient de maniere suprenante les plus difficiles a convaincre. Il y a aussi eu un testeur qui faisait des tests automatiques qui n'a pas aime le changement, mais j'ai du le rembarrer en lui disant que l'on n'avait pas le choix. Le pauvre gars avait pousse sa gueulante a un tres mauvais moment.

                      Bref assez stressant quand un P1 nous tombait sur le coin de la gueule toutes les semaines.

  • # de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

    Posté par  . Évalué à 5.

    Je trouve assez discutable techniquement le fait de faire tourner une JVM serveur/démon/serveur d'appli pour y faire tourner des batches lourds alors qu'il est beaucoup plus sûr techniquement de lancer une JVM pour chaque instance de batch lourd (pas de risque d'exploser le tas ou une autre ressource) et que le coût de démarrage d'une JVM en 2013 est juste ridicule (au regard d'un batch de plusieurs secondes ou plusieurs heures).

    Sans parler de la souplesse que peut donner au développeur le fait d'être seul dans sa JVM (un commentateur parlait de SpringBatch plus haut, faire un batch avec SpringBatch dans une JVM dédiée c'est facile, ne pas se marcher sur les pieds quand plusieurs sont dans la JVM il faut réfléchir et se parler entre développeurs voire équipes).

    Sinon bravo c'est super intéressant de gérer ce parent pauvre du monde Java qu'est le batch !

    • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

      Posté par  . Évalué à 2.

      Le coût de démarrage a certe réduit, mais il n'est pas négligeable pour autant. De plus il faut toujours un élément actif pour lancer le process, donc une JVM qui lance une JVM heu… Par ailleurs, il est plus facile de manager un thread qu'un process en java (ce n'est pas le cas avec d'autres langages…).
      De plus, il y a tout de même un impact mémoire qui n'est pas nul.

      • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

        Posté par  . Évalué à 0.

        Le coût de démarrage a certes réduit, mais il n'est pas négligeable pour autant

        Euh…. Tu dis pas ça sérieusement pour un batch ?

        $ cat Hello.java
        public class Hello {
          public static void main(String[] args) {
            System.out.println("Hello");
          }
        }
        $ javac Hello.java
        $ time java Hello
        Hello
        real    0m0.137s
        user    0m0.062s
        sys     0m0.028s
        $ java -version
        java version "1.6.0_18"
        OpenJDK Runtime Environment (IcedTea6 1.8.8) (fedora-51.1.8.8.fc13-i386)
        OpenJDK Client VM (build 14.0-b16, mixed mode)
        $ cat /proc/cpuinfo
        processor       : 0
        vendor_id       : GenuineIntel
        cpu family      : 6
        model           : 37
        model name      : Intel(R) Core(TM) i5 CPU       M 560  @ 2.67GHz
        stepping        : 5
        cpu MHz         : 2667.000
        cache size      : 3072 KB
        (...)
        
        • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

          Posté par  . Évalué à 2.

          Pour des batchs long, le coût CPU est négligeable, tu as raison même si le coût que tu indiques est pour une JVM « vide ». Charge quelques lib et le temps s'allonge… Depuis quelques temps la JVM ne charge plus tout le rt.jar, ce qui donne un temps à vide plutôt sympa. Malheureusement les développeurs ne sont pas économes en chargement de lib :-).
          De plus, dans notre cas d'usage, nous devons gérer à la fois des batchs longs et des batch courts voir très courts (1 à 2 sec) mais nombreux (>100 000 par heure en pic).
          Dans un pur cas de batch long, nous aurions sans doute opté pour une JVM externe. La gestion d'un pool de thread avec un classloader spécifique n'a pas été la partie la plus facile du dév :-)

          • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

            Posté par  . Évalué à 1.

            L'objet de mon commentaire est bien de parler des "tâches longues et gourmandes".

            Je ne discute pas du bien fondé d'avoir un démon pour exécuter les tâches courtes et fréquentes, je trouve ça pertinent pour tous les arguments que tu développe et même probablement pour d'autres encore.

            Je discute le fait d'imposer ce mode de fonctionnement aux traitements lourds, car je pense que c'est une hypothèque sur la robustesse. En effet, les traitements lourds, à un moment ou un autre du cycle de vie des applications, explosent (mémoire/gc, nombre de file descriptors, nombre de connexions base de données, etc.) donc je préfère en terme d'exploitation que quand ils explosent ils n'emportent pas leur petits copains avec eux.

            Après, c'est possible dans une certaine mesure d'isoler les traitements lourds mis dans la même JVM mais d'une part c'est dur (affecter des JVM d'exec à certains modules applicatifs, dédiés certaines aux traitements légers et d'autres aux traitements lourds, voire limiter à 1 traitement lourd à la fois dans une JVM, dès que t'as des équipes de dev qui ne se parlent pas ou des versions différentes d'une même appli il faut des class loaders différents par batch, etc.) d'autre part ce n'est pas complètement possible (le nombre de file descriptors et le tas java sont globaux, même avec des class loaders différents et des gestionnaires de sécurité). Du coup la seule façon d'être tranquille c'est de dédier une JVM à un traitement lourd et la façon la plus simple de le faire c'est de lancer la JVM à chaque traitement lourd.

            Ça n'empêche pas de traiter les petits/moyens traitements très répétitifs autrement, je ne cherche aucunement à dire le contraire.

            • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

              Posté par  . Évalué à 1.

              Pour des tâches longues et gourmandes, tu as parfaitement raison. Nous avons cherché une seule solution pour l'ensemble. Au risque qu'elle ne soit parfaite pour personne.
              Nous avons en effet du gérer un class loader par batch et avoir un filet pour attraper les exceptions. Par contre, les bêtises comme l'explosion des fd restent une faiblesse.
              Rien n'empêche d'avoir un job JQM qui lance une JVM externe, ce n'est pas l'esprit mais rien ne l'empêche. Nous le faisons déjà pour le PL/SQL par exemple (ce qui représente sans doute 1/3 de nos jobs JQM pour l'instant d'ailleurs).

              • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

                Posté par  . Évalué à 1.

                Rien n'empêche d'avoir un job JQM qui lance une JVM externe, ce n'est pas l'esprit mais rien ne l'empêche.

                Je pense qu'il y a une certaine valeur ajouté à ce qu'un framework de batches java prévoit et organise réellement le cas et ne se contente pas de laisser le développeur forker une JVM s'il en a envie en lui précisant que ce n'est pas l'esprit.

                Tu tiens quelques lignes plus pas dans un commentaire à l'apologie de la beauté de Python les propos suivants, ils sont un peu excessifs mais ont le mérite d'assez bien exprimer les limiter de "ce n'est pas l'esprit mais rien ne l'empêche":

                c'est peu brut de décoffrage en Java pour par exemple gérer une communication inter process ou gérer un verrou etc. Il faut tout se refaire à la main

              • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

                Posté par  . Évalué à 3.

                Pour des tâches longues et gourmandes, tu as parfaitement raison. Nous avons cherché une seule solution pour l'ensemble. Au risque qu'elle ne soit parfaite pour personne.

                Vous avez regarderzsur qu'elle brique d'infra vous pourriez greffer votre truc ?

                Tu as une partie métier spécifique mais tous les problèmes d'infra autours sont assez courants. En partant de 0 tu vas au final te prendre dans la face tout les problèmes du monde réel qu'ont les job scheduler et calcul distribué:
                - Fork et surveillance des processus
                - IPC
                - Gestion du réseau
                - Tolérance au panne, restart
                - Haute dispo

                Et ca, c'est juste un travail monstrueux. À partir de 0, je regarderais si il est pas possible de réutiliser un truc comme Hadoop YARN ou autre pour se concentrer sur le métier plutôt que de partir sur une version très simple qui va fatalement se retrouver à tout réimplémenter.

      • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

        Posté par  . Évalué à 1.

        une JVM qui lance une JVM heu… Par ailleurs, il est plus facile de manager un thread qu'un process en java

        Je suppose que tu veux dire avant java.lang.ProcessBuilder qui a été introduit en Java 5, c'est bien ça ?

        • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

          Posté par  . Évalué à 1.

          C'est mieux que cela n'a été oui :-). Mais ça ne fait toujours pas rêver, surtout quand on pense au passage d'arguments ou à la communication inter-process. Le batch a tout de même des interactions avec le moteur : reporting d'état d'avancement, gestion de l'arrêt (kill), etc.
          Pour le confort du lancement de process, je pensais plutôt à http://docs.python.org/2/library/subprocess.html et http://docs.python.org/2/library/multiprocessing.html
          Il reste encore un peu de chemin :-).

          • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

            Posté par  . Évalué à 1.

            Bah depuis Java 5 tu peux killer, avoir les 3 flux (in, out, err) séparément et en nio, et poller ou attendre un fils. Si t'arrives pas à faire du reporting d'avancement et du kill avec ça, c'est que t'as pas lu la doc… ;-)

            En fait je n'ai pas trouvé une seule fonctionnalité du module subprocess Python qui ne soit supporté par Java 5. Ce qui n'est d'ailleurs pas bien surprenant, Python comme Java offrant grosso modo 100% des possibilités systèmes communes aux différents OS sur lesquels ils tournent, du coup à part ne pas occulter des fonctionnalités (comme le faisait Java < 5) je ne vois pas bien ce qu'ils peuvent proposer.

            Surtout juste pour lancer une JVM depuis une autre JVM et savoir où elle en est (on n'est pas en train de parler de faire du calcul parallèle à la MPI/PVM avec, non plus).

            • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

              Posté par  . Évalué à 1.

              En me relisant, mon message était peu clair. Je parlais de l'avancement interne du batch (pour annoncer je suis à 30% des lignes traitées par exemple) et non du process. JQM permet également d'enregistrer les résultats du job (un fichier PDF généré par exemple) pour ensuite servir le résultat en http.

              Sinon, l'API de base est la même, bien entendu, c'est celle de l'OS. Mais ensuite c'est peu brut de décoffrage en Java pour par exemple gérer une communication inter process ou gérer un verrou etc. Il faut tout se refaire à la main. Il y a peut-être des lib tierces qui font ce boulot, je ne les connais pas. C'est là que le module multiprocess de Python rend les choses sympas. La gestion d'un process ressemble à celle d'un thread (même si le développeur a intérêt à comprendre la différence !).

            • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

              Posté par  . Évalué à 4.

              Bah depuis Java 5 tu peux killer, avoir les 3 flux (in, out, err) séparément et en nio, et poller ou attendre un fils. Si t'arrives pas à faire du reporting d'avancement et du kill avec ça, c'est que t'as pas lu la doc…

              NIO sur les stream d'un process ? Depuis quand un FileChannel est Selectable ? Non non ton "nio" c'est juste implémenté un bon gros pooling à la main si tu veux pas te retrouver avec 4*N threads pour chaque process. (et au passage c'est bufferisé aussi).

              Pour avoir souffert pendant quelques années à maintenir un truc massivement basé sur du fork/exec en Java 5/6 j'étais arrivé exactement à la même conclusion que Charles Nutter (je me souviens encore du code qu'il donne en exemple plus des Windowseries…). Le mec qui dit que c'est facile de faire un truc production ready avec la pauvreté du ProcessBuilder c'est qu'il l'a pas fait lui même.

              • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

                Posté par  . Évalué à 1.

                Merci pour le lien. Cela ne donne pas envie en effet…

              • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

                Posté par  . Évalué à 0.

                L'article que tu cites dit que l'API ProcessBuilder est moche et pleine de pièges. C'est vrai. Mais elle est utilisable quand on est obligé de lancer un fils en Java. Même si je reconnais préférer le faire en C qu'en Java.

                Depuis Java 5 c'est possible avec un thread par fils. Les flux sont pas selectables mais on peut faire des i/o avec timeout dessus alors on s'en sort. D'ailleurs c'est pas on peut mais il faut, pour les raisons cités dans ton article (pour pas se le faire bourrer d'un coup en mémoire à la mort du process) et pour d'autres (pour pas freezer le fils).

                Ok un thread par fils c'est beaucoup si tu comptes avoir des centaines ou des milliers de fils mais dans le cas présenté ici (lancer quelques batches en parallèle) je continue à trouver que c'est un moindre mal par rapport à se retrouver avec un batch qui OOM la JVM et et plante les autres batches. Quand c'est pas pire qu'un OOM (parce qu'encore un OOM c'est la roulette russe, t'as de grande chance de pas tomber sur une balle et que l'exception libère masse mémoire ou les autres batches).

                Après si les flux étaient selectables ont pourrait mutualiser un fils sur plusieurs processus, ou au moins éviter l'inélégance de faire des read avec timeout alternativement sur out et err. Certes. Ça ne serait pas pour me déplaire.

                Perso j'ai fait en Java 4 et en Java 5 (ou 6 je sais plus mais ça n'a pas d'importance de ce point de vue 6 = 5).

                Avant Java 5, tu pouvais pas lire les flux avec timeout du coup t'avais le choix entre ne pas lire les flux et prier pour que le fils ne remplisse pas les buffers et ne se freeze pas, ou bien ne pas pouvoir tuer le fils s'il est trop long car tu étais bloqué dans la lecture des flux, ou encore avoir 3 ou 4 threads (je sais plus) juste pour gérer un flux.

                • [^] # Re: de la pertinence d'une JVM permanente pour y exécuter les tâches longues et gourmandes

                  Posté par  . Évalué à 3.

                  Depuis Java 5 c'est possible avec un thread par fils. Les flux sont pas selectables mais on peut faire des i/o avec timeout dessus alors on s'en sort.

                  • On pouvait le faire avant avec un bête available() (bon qui lui même était buggé dans certains cas mais j'ai oublié les corner cases depuis le temps et si ils existent toujours).
                  • Tu peux tout mutualiser sur un seul thread. De toute facon quitte a écrire du code complexe que tu vas passer 10 plombes à stabiliser alors que ca devrait être dans le JDK… Il te reste le reaper, mais effectivement ca ne va te poser problème que si tu fork pas mal.

                  je continue à trouver que c'est un moindre mal par rapport à se retrouver avec un batch qui OOM la JVM et et plante les autres batches

                  Je suis entièrement d'accord avec ca.

                  Mon point était juste de tempérer l'enthousiame qui pouvait sembler naïf sur le ProcessBuilder. C'est juste une API de merde qui te masque presque tout ce dont tu as besoin pour faire ton job avec une implémentation bien pourrie aussi.

                  On arrive à faire des trucs qui marchouillent en lisant tout le code des VM et quand tout va bien. Quand tu forks des processus non controllés sur plusieurs systèmes différents c'est bien plus "rigolo".

  • # Comment JQM se positionne-t-il par rapport à Quartz par exemple ?

    Posté par  (Mastodon) . Évalué à 2.

    et donc quels sont ses avantages par rapport à un "bête" scheduler de tâches comme l'est Quartz ?

    • [^] # Re: Comment JQM se positionne-t-il par rapport à Quartz par exemple ?

      Posté par  . Évalué à 2.

      JQM n'est pas un scheduler. C'est une file d'attente de job et un conteneur d'exécution distribué.

      Les jobs soumis à JQM peuvent provenir d'un scheduler, d'un flux (arrivée d'un fichier, un message…) ou une action utilisateur sur l'écran d'une application.

      Ces deux produits sont donc différents et répondent à deux besoins différents (et potentiellement complémentaires).

  • # Intéressant

    Posté par  (site web personnel) . Évalué à 3.

    Je sais que c'est facile de faire des commentaires du genre « comment se positionne X par rapport à Y », mais c'est aussi ce qui permet de faire connaître un éco-système et présenter les différentes solutions possibles…

    Dans notre entreprise, on a choisi d'utiliser camel (exemple). Le but initial de camel n'est pas de faire du batch, mais de faire passer des messages entre deux points. Les différents protocoles d'entrées et de sortie permettent de créer différentes combinaisons (ftp->mail, MQ->fichier, MQ->MQ) et de laisser la couche de transfert de message à une librairie externe.

    Une fois que l'on sait faire passer des messages, faire du batch n'est pas trop difficile (c'est le principe de l'Enterprise Integration Pattern)

    Je me rend compte que ce genre de librairie est vraiment nécessaire dès que l'on cherche à faire du batch, ça ne sert à rien de chercher à le réinventer la roue, c'est comme utiliser un ORM, on peut faire sans, mais c'est plus compliqué…

    • [^] # Re: Intéressant

      Posté par  . Évalué à 1. Dernière modification le 01 janvier 2014 à 23:36.

      Ça dépend ce que t'appelles faire du batch.

      Si c'est avoir des centaines de traitements d'informatique de gestion toutes les nuits avec des points de reprise pour que des exploitants puissent les relancer le matin (voire des pilotes la nuit) avec des consignes d'exploitation simples (j'ose pas écrire en français simplifié mais je le pense, ah bah si tiens je l'ai écrit), bah comment te dire que je me demande bien comment on peut faire ça avec Camel…

      Je préfère de loin avoir le bidule JQM que le bidule Camel pour faire des batches, au sens que je viens de donner à batch. Malgré tous les défauts que j'ai cités plus haut.

      Et le bouquin que tu cites il est cool à feuilleter, il présente des jolies briques de lego qu'on peut assembler pour faire des applications qui ressemblent à The Incredible Machine: c'est trop cool à regarder, c'est assez cool à construire, faut pas trop avoir à le maintenir plus d'un an et surtout, surtout, faut jamais avoir à l'exploiter quand un grain de sable rentre dans un rouage.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.