There is also a handy property for WebSphere,
jndi.LDAP.URLContextImplementation, regarding re-using existing or
creating new connections for ldap searches/lookups. Less attractive areas
to look at are java programmatic JNDI TimeKeeper thread implementation for
the actual jndi client where LDAP provider timeout mechanism already
exists and OS/TCP settings for such parameters as timewait &
keepalive.
Extracted from WebSphere 4.x Release Notes and InfoCenter:
A URL context implementation is a context that can handle arbitrary URL
strings of the URL scheme supported by the context. If the implementation
is enabled, a new connection is established for each search operation and
the connection is closed when the search is completed. If the network
dispatcher or IP sprayer in use does not support session affinity, this
needs to be enabled. Session affinity means that once a connection is
established between a client and a server, for example, WebSphere
Application Server, the LDAP client, and an LDAP server, and then all new
requests are routed to the same server. To support URL context
implementation, add the following property to the admin.config file:
jndi.LDAP.URLContextImplementation = true
*The same feature is available in 5.x under ReUse Connection setting.
Version 4.x introduced properties to support tuning the JNDI search
timeout value along with LDAP reuse connection. These two properties are
now settings in the Security Center of the Version 5 administrative
console. There is no migration of Version 4.x property values to the
Version 5 settings.
The jndi.LDAP.SearchControl.TimeLimit property is equivalent to the
Version 5 Search Timeout setting, which is 300 by default in Version 5.
The jndi.LDAP.URLContextImplementation property is equivalent to the
Version 5 Reuse Connection setting, which is true by default in Version 5.
1. let me clarify a little how "URL Context Implementation" works now in
WebSphere, and its history. This property was originally added to force
JNDI to make new connection for each search operation, by passing LDAP URL
with Base search DN. This way, JNDI will automatically open a new
connection when it sees URL, and it is supposed to close connection, as
WebSphere does not explicitly manage the new connection. Later, this
implementation was modified to initiate a new InitialDirContext instance
directly, so a new connection is also established along, and the context
and connection is closed after search or exception.
2. If JNDI does not return, the connection would not be closed until this
thread is recycled. In WebSphere 4.0, a registry call is a remote EJB
call, and after transaction timeout, this not responding call would be
abandoned, so eventually the failing InitialDirContext (and its
connection) should be recycled by JDK.
3. If proven that JDK does not recycle the abandoned InitialDirContext and
its connection the problem should go to JDK support. If the InitailContext
instance and its connection is not eventually recycled after transaction
timeout (default 10 minutes), please provide evidence and JNDI trace, so
JDK support can investigate the problem.
4. However, if maintained that it takes 10 minutes to recycle a hang
condition (no response) from LDAPsearch, this is because JNDI does not
have timeout mechanism.
As per the doc in the following Sun JNDI LDAP Connection Closure url:
http://java.sun.com/products/jndi/tutorial/ldap/connect/close.html
per the section, "Forced Implicit Closures", need to explicitly call the
NamingEnumaration.close to close the physical connection.
Sample Testcase Scenario:
Closing LDAP connections and performance on ctx.close() operations.
Bad CASE
DirContext ctx = new InitialDirContext(env);
// Search for objects with those matching attributes
NamingEnumeration answer =
ctx.search("","(objectclass=*)", ctls );
// Close the context when we're done
ctx.close();
Good CASE
DirContext ctx = new InitialDirContext(env);
// Search for objects with those matching attributes
NamingEnumeration answer =
ctx.search("","(objectclass=*)", ctls );
answer.close(); // Added to close enum instance!!!!
// Close the context when we're done
ctx.close();
This testcase illustrates that JVM closes LDAP socket very quickly with
GoodCase. In BadCase, LDAP socket remained for sometime under heavy
stress.
Sample(Bad Case): This case can not enable JVM to close LDAP socket as
soon as possible. Repeating this will be reason of LDAP socket leak with
high stress access.
<extract>
ctx = new InitialDirContext(ldapConfig);
nEnum = ctx.search(base, filter, controls);
ctx.close();
</extract>
.
Sample (Good Case): This case enable JVM to close LDAP socket as soon as
possible.
<extract>
ctx = new InitialDirContext(ldapConfig);
nEnum = ctx.search(base, filter, controls);
nEnum.close();
ctx.close();
</extract>
{Worth noting also that LDAP servers often have an idle timeout period
after which they will close connections no longer being used}
TimeKeeper JNDI Client Implementation:
*Can not implement timeout mechanism within the JNDI provider if the LDAP
itself doesn't have a timeout mechanism built-in.
To explain it further, need to have a time keeping mechanism on top of the
LDAP protocol without interfering with the normal protocol flow.
One of the complexities involved in this is, if can be imposed a timeout
on an LDAP operation (it could be using socket timeout for ex.), the
mechanism should ignore the response when the server eventually returns
back the results after the operation has timed out. This requires
book-keeping of the multiple requests sent by the client to determine
which ones have timed out.
The current and best way is to handle the timeout in the client
application is by using a time keeper thread. In a JNDI application one
can set a timer before the operation that needs a timeout, as shown below
posted on JNDI forum at:
http://forum.java.sun.com/thread.jsp?forum=51&thread=4954
...
class SimpleTimeKeeperTest {
public static void main(String args[]) throws Exception {
TimeKeeper.start(5000);
// perform the JNDI operation that needs a timeout
// In this example the while loop below requires a timeout
while(true) {
Thread.currentThread().sleep(10000);
}
}
}
class TimeKeeper extends Thread {
long timeout; // in milliseconds
long timerStart;
Thread parent;
TimeKeeper(long timeout) {
parent = Thread.currentThread();
this.timeout = timeout;
this.start();
}
public static void start(long timeout) {
new TimeKeeper(timeout);
}
public void run() {
timerStart = System.currentTimeMillis();
long waitTime = timeout;
while (waitTime > 0) {
try {
this.sleep(waitTime);
} catch (InterruptedException ie) {
// ignore and continue
}
waitTime = timeout - (System.currentTimeMillis() -
merStart); }
parent.interrupt();
}
}
PQ93851open for WAS 4.x and related. Changes necessary for this
APAR have system integrity implications. Work around for this to set
jndi.LDAP.URLContextImplementation=true
PQ96574 open for WAS 5.x and being considered for implementation
of ldap socket_timeout mechanism, possibly at jndi level.
|