LDAP请求挂起15秒

时间:2009-07-16 14:39:00

标签: java jboss ldap

我有使用LDAP进行身份验证的JBoss应用程序服务器。最近我们注意到有很多慢速请求(> 15秒)。

我做了服务器的一些threaddumps并注意到许多线程在等待锁定:com.sun.jndi.ldap.LdapRequest@54ceac

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)

我看到的所有在此状态下等待的请求都使用了超过15秒的时间来完成。我们正在监控LDAP服务器,监控工具的所有请求都在不到200毫秒内完成。这让我觉得这是com.sun.jndi.ldap代码的问题。反编译com.sun.jndi.ldap.Connection类(jdk1.5.0_12)我看到了:

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 */
    }
    }
    ...

显然有15000毫秒的硬编码超时。

有人对修复/解决方法有任何想法吗?

4 个答案:

答案 0 :(得分:1)

听起来与this bug类似,您是否尝试使用数据包嗅探器检查网络流量以检查此情况?

答案 1 :(得分:1)

您正在使用旧的jdk1.5(jdk1.5.0_12)。

我使用tomcat 5.5与jdk1.5_16有同样的问题。我们有一个等待ldap响应的线程,它会阻塞所有其他线程,因为我不知道JBoss但是在tomcat中至少所有ldap认证都按顺序完成。

如果查看粘贴的反编译代码,等待15秒后你就会有一个中断标签0,它实际上是一个循环。所以它会循环直到ldap回答(没有超时!)。

我不确定修复了哪个版本,但在1.5.0_22中,代码现在是:

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");
     }

 }

现在,如果您提供超时值,它将等待该时间,然后退出循环。这应解锁认证队列。

答案 2 :(得分:0)

对我看起来好像它只是等待回复为空 - 想知道是否存在某种版本不匹配导致您的应用无法解析来自您服务器的回复。

您是否尝试过附加源代码,并且看到您可以在eclipse中设置断点。

-ace

答案 3 :(得分:0)

在使用LDAP连接到ActiveDirectory框之前(在有多个服务器的网络中)之前,我已经看到过类似的内容。它最终成为DNS问题,我们只需要刷新我们的DNS缓存(Windows框上的“ipconfig / flushdns”)。这可能是您的问题,也可能不是,只是认为值得一试。