2009-07-16 8 views
6

J'ai un serveur d'applications JBoss qui utilise LDAP pour l'authentification. Dernièrement, nous avons remarqué qu'il y a beaucoup de demandes lentes (> 15 secondes).Les requêtes LDAP suspendues pendant 15 secondes

J'ai fait quelques threaddumps du serveur et a remarqué que de nombreux threads où attente sur un verrou: [email protected]

java.lang.Object.wait(Native Method) 
com.sun.jndi.ldap.Connection.readReply(Connection.java:418) 
com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:340) 
com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:192) 
com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2637) 
com.sun.jndi.ldap.LdapCtx.(LdapCtx.java:283) 
com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175) 
com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:134) 
com.sun.jndi.url.ldap.ldapURLContextFactory.getObjectInstance(ldapURLContextFactory.java:35) 
javax.naming.spi.NamingManager.getURLObject(NamingManager.java:584) 

Toutes les demandes que j'ai vu qui ont été attendre dans cet état ont utilisé plus de 15 secondes pour terminer. Nous surveillons le serveur LDAP et toutes les requêtes de l'outil de surveillance se terminent en moins de 200 ms. Cela me fait penser que c'est un problème avec le code com.sun.jndi.ldap. Décompiler la classe com.sun.jndi.ldap.Connection (de jdk1.5.0_12) Je vois ceci:

BerDecoder readReply(LdapRequest ldaprequest) throws IOException, NamingException 
{ 
_L2: 
    BerDecoder berdecoder; 
    if((berdecoder = ldaprequest.getReplyBer()) != null) 
    break; /* Loop/switch isn't completed */ 
    try 
    { 
label0: 
    { 
     synchronized(this) 
     { 
     if(sock == null) 
      throw new ServiceUnavailableException((new StringBuilder()).append(host).append(":").append(port).append("; socket closed").toString()); 
     } 
     synchronized(ldaprequest) 
     { 
     berdecoder = ldaprequest.getReplyBer(); 
     if(berdecoder == null) 
     { 
      ldaprequest.wait(15000L); 
      break label0; 
     } 
     } 
     break; /* Loop/switch isn't completed */ 
    } 
    } 
    ... 

Il y a apparemment un délai d'attente de 15000 millisecondes hardcoded.

Quelqu'un a-t-il des idées pour un correctif/une solution de contournement?

+0

Pourquoi berdecoder serait-il nul? Une pensée associée: le délai d'attente par défaut sur de nombreux clients de résolution de noms lorsqu'un serveur DNS est indisponible est de 15 secondes. – mas

+0

Problème de réseau? Vous seriez surpris de voir à quelle fréquence un commutateur laisse tomber des paquets même sur un simple LAN – nos

Répondre

0

me semble comme si elle attend seulement si la réponse est nulle - se demandant s'il existe une sorte de non-concordance de version qui empêche votre application d'analyser la réponse de votre serveur.

Avez-vous essayé d'attacher la source, et vu que vous pouvez définir un point d'arrêt dans Eclipse.

-ACE

0

Je l'ai vu quelque chose comme ça avant lorsque vous utilisez LDAP pour se connecter à une boîte ActiveDirectory (dans un réseau où il y a plus d'un serveur). Il a fini par être un problème de DNS et nous avions juste besoin de vider notre cache DNS ("ipconfig/flushdns" sur une boîte de Windows). Cela peut ou peut ne pas être votre problème, juste pensé que ça vaudrait la peine d'essayer.

1

Semblable à this bug, avez-vous essayé d'inspecter le trafic réseau avec renifleur de paquets pour vérifier cette condition?

1

Vous utilisez un ancien jdk1.5 (jdk1.5.0_12). J'ai le même problème avec jdk1.5_16 utilisant tomcat 5.5. Nous avons un thread qui attend une réponse ldap et il bloque tous les autres threads parce que je ne connais pas JBoss mais dans tomcat au moins toutes les authentifications ldap sont faites séquentiellement.

Si vous regardez dans le code décompilé que vous avez collé, après l'attente 15 secondes, vous avez un break label0 qui est effectivement une boucle. Donc, il va boucler jusqu'à ce que ldap réponde (pas de timeout!).

Je ne suis pas sûr dans quelle version il a été fixé, mais en 1.5.0_22 le code est maintenant:

BerDecoder readReply(LdapRequest paramLdapRequest) 
    throws IOException, NamingException 
{ 
    BerDecoder localBerDecoder; 
    int i = 0; 

    while (((localBerDecoder = paramLdapRequest.getReplyBer()) == null) && (i == 0)) { 
    try 
    { 
     synchronized (this) { 
     if (this.sock == null) { 
      throw new ServiceUnavailableException(this.host + ":" + this.port + "; socket closed"); 
     } 
     } 

     synchronized (paramLdapRequest) 
     { 
     localBerDecoder = paramLdapRequest.getReplyBer(); 
     if (localBerDecoder == null) 
      if (this.readTimeout > 0) 
      { 
      paramLdapRequest.wait(this.readTimeout); 
      i = 1; 
      } else { 
      paramLdapRequest.wait(15000L); 
      } 
     else 
      break label163: 
     } 
    } 
    catch (InterruptedException localInterruptedException) { 
     throw new InterruptedNamingException("Interrupted during LDAP operation"); 
    } 

} 

Alors maintenant, si vous fournissez une valeur de délai d'attente, il attendra que le temps, et puis quittez la boucle. Un ceci devrait déverrouiller la file d'attente d'authentification.