We recently had problems with load on our single sign on (SSO) server. There were 100s of open LDAP connections to our LDAP servers.
By looking at the LDAP code there are two places where we make LDAP connections, or, as they are known in Java contexts.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://hostname.com");
LdapContext ctx = new InitialLdapContext(env,null);
// do something with ctx
ctx.close()
The contexts were always closed and this is where LDAP connection pooling came into the picture.
env.put("com.sun.jndi.ldap.connect.pool", "true");
This turns on connection pooling. The following code is for your reference
DirContext ctx=null;
NamingEnumeration answers=null;
Properties env = new Properties();
//Bind the context
env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
env.put( Context.PROVIDER_URL, "ldap://" + bundle.getString("LDAP_SERVER") + ":" +
bundle.getString("LDAP_PORT") + "/");
env.put( Context.SECURITY_PRINCIPAL, bundle.getString("ROOTDN") );
// env.put( Context.SECURITY_CREDENTIALS, bundle.getString("ROOTPASS") );
env.put( Context.SECURITY_CREDENTIALS,password);
//LDAP connection pooling is implemented
env.put("com.sun.jndi.ldap.connect.pool", "true");
ctx = new InitialDirContext(env);
StringBuffer uidBuffer = new StringBuffer();
//pass the logged in username from portal to query and fetch the attributes from LDAP Server
uidBuffer.append("uid="+LoggedInUser);
//System.out.println(LoggedInUser);
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
answers = ctx.search("",uidBuffer.toString(), ctls);
while(answers.hasMore()) {
SearchResult sr = (SearchResult)answers.next();
Attributes attrs = sr.getAttributes();
//get all the required values
Attribute givenname=attrs.get("givenname");
Attribute middlename = attrs.get("middlename");
Attribute sn = attrs.get("sn");
//format all the fetched attributes to get the exact values & add all the formatted values to the array list and
return
if(givenname !=null)
{
formattedGivenname=formatGivenname(givenname.toString());
list.add(formattedGivenname);
}else
{
formattedGivenname=" ";
list.add("");
}
if(middlename !=null)
{
formattedMiddlename=formatMiddlename(middlename.toString());
list.add(formattedMiddlename);
}else
{
formattedMiddlename=" ";
list.add("");
}
if(sn !=null)
{
formattedSn=formatSn(sn.toString());
list.add(formattedSn);
}else
{
formattedSn=" ";
list.add("");
}
}
}catch (NamingException ne)
{
System.err.println(ne.toString());
}
finally
{
if(answers !=null)
{
answers.close();
}
if(ctx != null)
{
ctx.close();
}
}
Although in theory the connection pooling was working, it was still creating a lot of connections.
Then, upon closing all NamingEnumerations (Marked in Red), we finally got the perfect results. 100s of requests a minute & only around 10–15 LDAP connections open at any one time.
LDAP API Programming Best Practices
I. When creating contexts, share the factory to use pooling
II. Make sure you close everything. If it has a close(), use it.
No comments:
Post a Comment