Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API standards et tierces Java Discussion :

Pb de MultiThread Callable et JSCH


Sujet :

API standards et tierces Java

  1. #1
    Membre confirmé
    Pb de MultiThread Callable et JSCH
    Bonsoir

    J'ai un programme java qui effectue sue 30 serveurs different la commande "ls" grace à l'API JSCH. Afin d'accelerer ces traitements j'ai ajouté du Threading avec du "callable"
    Je constate que lorsque je lance le War depuis mon tomcat7 sous Windows7, cela met 3 secondes pour tous les serveurs alors que sur la machine Linux en kernel 2.6.32 cela met 30*3 secondes
    Les threads ne sont pas parallelisé,chaque commande attend la fin du précedent pour se lancer ?
    Pourquoi une difference alors que c'est le meme programme ?
    C'est du Java7/Tomcat7

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
     
        public String sendCommandWithouthSecurityCheck(String hostname,String command,boolean forceExit) throws MyDomainException{
            publicKeyValidThrowException();        
     
            Session session = null;
            ChannelExec channel=null;        
            try(ByteArrayOutputStream outputStreamErr = new ByteArrayOutputStream()) {
                session = jsch.getSession(USER_MM, hostname);
                session.setConfig("StrictHostKeyChecking", "no");  
                session.setConfig("PreferredAuthentications","publickey,keyboard-interactive,password");//Permet de ne pas bloquer a l'attente du mot de passe de la session
                session.connect(); //NoTimeout
     
                channel= (ChannelExec)session.openChannel("exec");            
     
                channel.setInputStream(null);
                channel.setErrStream(outputStreamErr);
     
                channel.setCommand(command);
     
                channel.connect();
     
                String resultOut,resultErr;
                try (InputStream is = channel.getInputStream()) {
                    resultOut = toString(is);
                }
     
                if(outputStreamErr.size()==0){
                    resultErr = null;
                }else{
                    resultErr = outputStreamErr.toString();
                }            
     
                //il faut deconnecter le channel avant de recuperer le retour code
                channel.disconnect();
                session.disconnect();
     
                int nbRetry = 0;
                while(!channel.isClosed() && !forceExit){
                    if(nbRetry>=NB_RETRY_CLOSE){
                        throw new MyDomainRollbackException("Impossible de fermer la connexion SSH de la '" + command + "' sur l'hote " + hostname+" apres "+NB_RETRY_CLOSE+" tentatives");
                    }
                    nbRetry++;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException ex) {
                        log.error("Timeout connexion SSH de la '" + command + "' sur l'hote " + hostname);
                        forceExit=true;
                    }
                }
     
                if(nbRetry!=0){
                    log.warn("Fermeture de la connexion SSH de la '" + command + "' sur l'hote " + hostname + "  apres " + nbRetry+" tentatives");
                }
     
                int exitStatus = channel.getExitStatus();
     
                if (exitStatus == 0) {
                    log.info("Command '" + command + "' execute sur l'hote " + hostname + " : '" + resultOut+"'");
                    return resultOut;
                } else { 
                    if(exitStatus == -1){
                        log.error("Le canal SSH n'a pas ete correctement ferme avant la recuperation du retour code de la commande '" + command + "' sur l'hote " + hostname + " (test canal ferme via API : " + channel.isClosed() +", nombre de retry : "+nbRetry+", force exit : "+forceExit+")");
                    }
                    if (resultErr == null) {
                        throw new MyCommandException("Une erreur est survenue lors de l'execution de la commande '" + command + "' sur l'hote " + hostname + " (exit code " + exitStatus + ")",exitStatus,resultErr);
                    } else {
                        throw new MyCommandException("Une erreur est survenue lors de l'execution de la commande '" + command + "' sur l'hote " + hostname + " : '" + resultErr + "' (exit code " + exitStatus + ")",exitStatus,resultErr);
                    }
                }
            } catch (JSchException | IOException ex) {
                throw new MyDomainRollbackException(ex);
            } finally {
                if (channel != null && !channel.isClosed()) {
                    channel.disconnect();
                }
                if (session != null && session.isConnected()) {
                    session.disconnect();
                }
            }
        }
     
     
    -------------
    Je n'ai pas tout mis
            ExecutorService      executor = Executors.newFixedThreadPool(NTHREDS);
            List<Future<String>> list     = new ArrayList<Future<String>>();
     
            for (int cpt = 0; cpt < max; cpt++) {
                Callable<String> worker = new MyCallableB(cpt, show, s);
                Future<String>   submit = executor.submit(worker);
     
                list.add(submit);
            }
     
        for (Future<String> future : list) {
     
                       try {
                    rt = future.get();
     
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }

  2. #2
    Expert éminent sénior
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    ExecutorService      executor = Executors.newFixedThreadPool(NTHREDS);


    La première chose que je vérifierais, c'est si NTHREDS vaut 1 ou plus.
    David Delbecq Java developer chez HMS Industrial Networks AB. &#12288;&#12288;&#12288;LinkedIn | Google+

  3. #3
    Membre confirmé
    Bonjour

    Oui NTHREDS vaut 15

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    En serveur recette LINUX vers la base de recette
    2017-11-02 08:03:59,737 INFO [http-bio-xx.xx.x.xx-10587-exec-2] service.ApplicationRSImpl.checkAndAddAllLinks (ApplicationRSImpl.java:320) - checkAndAddAllLinks() - date Debut 2017-11-02 08:03:59, nbThread=15
    2017-11-02 08:04:01,090 INFO [pool-2-thread-9] sshj.CommandUSImpl.sendCommandWithouthSecurityCheck (CommandUSImpl.java:68) - Command 'ls -ld /tech/prod/client/TOTO' execute sur l'hote serveur01 : 'lrwxrwxrwx 1 zorro zorro 21 Sep 8 2015 /tech/prod/client/TOTO -> /tech/prod/8.0.0.2'
    2017-11-02 08:04:03,979 INFO [pool-2-thread-7] sshj.CommandUSImpl.sendCommandWithouthSecurityCheck (CommandUSImpl.java:68) - Command 'ls -ld /tech/prod/client/TOTO' execute sur l'hote serveur02 : 'lrwxrwxrwx 1 zorro zorro 21 Sep 8 2015 /tech/prod/client/TOTO -> /tech/prod/8.0.0.2'
     
     
    En serveur localhost windows tomcat7 vers la base de recette
    2017-11-02 09:05:32,484 INFO [pool-2-thread-4] sshj.CommandUSImpl.sendCommandWithouthSecurityCheck (CommandUSImpl.java:68) - Command 'ls -ld /tech/prod/client/TOTO' execute sur l'hote serveur02 : 'lrwxrwxrwx 1 zorro zorro 21 Sep 8 2015 /tech/prod/client/TOTO -> /tech/prod/8.0.0.2'
    2017-11-02 09:05:32,499 INFO [pool-2-thread-6] sshj.CommandUSImpl.sendCommandWithouthSecurityCheck (CommandUSImpl.java:68) - Command 'ls -ld /tech/prod/client/TOTO' execute sur l'hote tlszz02 : 'lrwxrwxrwx 1 zorro zorro 21 Oct 13 2015 /tech/prod/client/TOTO -> /tech/prod/8.0.0.2'
    2017-11-02 09:05:32,504 INFO [pool-2-thread-3] sshj.CommandUSImpl.sendCommandWithouthSecurityCheck (CommandUSImpl.java:68) - Command 'ls -ld /tech/prod/client/TOTO' execute sur l'hote tlszz01 : 'lrwxrwxrwx 1 zorro zorro 21 Oct 13 2015 /tech/prod/client/TOTO -> /tech/prod/8.0.0.2'
    2017-11-02 09:05:32,511 INFO [pool-2-thread-9] sshj.CommandUSImpl.sendCommandWithouthSecurityCheck (CommandUSImpl.java:68) - Command 'ls -ld /tech/prod/client/TOTO' execute sur l'hote serveurx01 : 'lrwxrwxrwx 1 zorro zorro 21 Sep 8 2015 /tech/prod/client/TOTO -> /tech/prod/8.0.0.2'
     
    depuis mon ordinateur avec le meme programme le multi-rhreading fonctionne alors que sur le serveur linux cela donne l'impression qu'on attend la fin de la commande précédente


    Je viens de faire un test simple en mode bash et le temps est correct. C'est donc lié à la configuration du tomcat7 !!

  4. #4
    Expert éminent sénior
    Ok, il faudrait le code complet de ta classe Callable et l'output complet sous linux (pas juste la première exécution)

    ensuite, rajouter des logs à différentes étapes de l'opération (création du job, entrée dans la méthode call du callable, initialisation de la connection ssh, ...) permettrait de voir quel composant pose problème. Pas impossible que ton serveur de production aie simplement une limitation sur le nombre de session ssh autorisées en parallèle.

    Note qu'on voie clairement dans ton output que les deux commandes ssh sortent de deux threads différents, donc peu de chance que le pool soit en tord. A moins que ton Callable aie un verrou dont tu ne nous aie pas parlé.
    David Delbecq Java developer chez HMS Industrial Networks AB. &#12288;&#12288;&#12288;LinkedIn | Google+

  5. #5
    Membre confirmé
    Bonsoir

    Comme je le disais j'ai copié les deux classes de thread et d'envoi dans un jar a part que j'ai lancé depuis le même serveur LINUX ou se trouve mon projet et la les temps de réponses sont très correct !
    J'ai demandé l'ouverture des ports JMX sur la machine de "recette" qui à les même symptômes afin de voir si le projet complet ne "mange" pas la mémoire ce qui expliquerait pourquoi mon tomcat local lie à eclipse fonctionne bien.

    je vous met le code demain

  6. #6
    Membre confirmé
    Bonsoir

    JMX me donne effectivement du LOCK de THREAD uniquement sur le tomcat de la machine LINUX/REDHAT avec le JDK 1.7.51
    at net.schmizz.sshj.transport.random.SingletonRandomFactory.<init>(SingletonRandomFactory.java

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    "pool-2-thread-14" - Thread t@84
       java.lang.Thread.State: BLOCKED
                    at sun.security.provider.NativePRNG$RandomIO.implGenerateSeed(NativePRNG.java:218)
                    - waiting to lock <58e758ca> (a java.lang.Object) owned by "pool-2-thread-9" t@79
                    at sun.security.provider.NativePRNG$RandomIO.access$300(NativePRNG.java:125)
                    at sun.security.provider.NativePRNG.engineGenerateSeed(NativePRNG.java:119)
                    at java.security.SecureRandom.generateSeed(SecureRandom.java:517)
                    at net.schmizz.sshj.transport.random.BouncyCastleRandom.<init>(BouncyCastleRandom.java:44)
                    at net.schmizz.sshj.transport.random.BouncyCastleRandom$Factory.create(BouncyCastleRandom.java:36)
                    at net.schmizz.sshj.transport.random.BouncyCastleRandom$Factory.create(BouncyCastleRandom.java:31)
                    at net.schmizz.sshj.transport.random.SingletonRandomFactory.<init>(SingletonRandomFactory.java:27)
                    at net.schmizz.sshj.DefaultConfig.initRandomFactory(DefaultConfig.java:117)
                    at net.schmizz.sshj.DefaultConfig.<init>(DefaultConfig.java:93)


    java.security.properties=/share/scripts/etc/java.security ne contient pas de ligne securerandom.source=file:/dev/urandom

  7. #7
    Membre confirmé
    La solution etait dans le demarrage de Tomcat
    JAVA_OPTIONS=" -Djava.security.egd=file:/dev/./urandom"

  8. #8
    Expert éminent sénior
    Bien vu

    attention que urandom est moins sur que random
    David Delbecq Java developer chez HMS Industrial Networks AB. &#12288;&#12288;&#12288;LinkedIn | Google+

  9. #9
    Membre confirmé
    Oui, mais mon appli Web est une appli interne qui sert à la gestion de l'infrastructure technique interne basé sur MQ-SERIES
    Merci