Menu

LDAP Connection Pool

2013-11-26
2013-11-28
  • Oscar Golden L.

    Oscar Golden L. - 2013-11-26

    Hello,
    Thanks for sharing that piece of software. It is really appreciated.
    I am fairly new to the SDK. I've been experimenting with the FailOverServerSet (v2.3.5) to implement a pool with some specific requirements. I am kind of stuck and I was wondering if the SDK allows me easily to manage my pool with the rules below.

    The set-up is made of 3 LDAP servers.
    * Primary server : S1 (highest priority)
    * Secondary servers: S2, S3 (S3 having a lower priority than S2)

    Pool Management Rules:

    1. If S1 is up
      • all connections should be directed to S1
    2. If S1 goes down

      • After N=3 failed attempts to S1, the system should failover to S2 occurs (N must be configurable)
      • After the failover to S2, I want S1 to be put in quarantine for Tq seconds (Tq configurable)
      • After the quarantine expires, as soon as S1 recovers, all new connections should failback to S1
        • One option is to use a mechanism to check periodically (every X seconds) if S1 is back up (X configurable).
    3. If S1 does not recover

      • all connections should be directed to S2
      • If S2 goes down
        • All connections should failover to S3 after N=3 failed attempts
        • S2 should be put in quarantine for Tq seconds, and so on ...

    Here is what I've come up with so far.

    1. Create a LDAPConnectionPool with a FailoverServerSet.
    2. I was not able to figure out how to configure
      • N, number of failed attempts before the failover
      • Tq, the quarantine duration. Setting maxFailoverConnectionAge = Tq did not work.
      • X, the frequency of the periodic checks. autoReconnect does not work with pooled connection
      • Any idea how to periodically check the availability of the failed server. How to use the LDAPConnectionPoolHealthCheck class is not clear to me.

    Any pointers (even to existing code) would be greatly appreciated.
    Thanx.

     
  • Neil Wilson

    Neil Wilson - 2013-11-26

    The LDAP SDK connection pool implementation can't do exactly what you're asking because I don't think that it works the way you expect. However, I do think that it can do something close enough to meet your needs, especially if you're using the latest 2.3.5 version, which was released last week.

    The LDAP SDK connection pool really does load balancing on a per-connection basis rather than a per-operation basis. Whenever the connection pool needs to establish a connection (e.g., when the pool is being created, when it needs to replace a connection that is no longer valid, when a connection has been established for the maximum connection age, etc.), the ServerSet associated with the pool will decide which server should be used to establish that connection. In the case of the FailoverServerSet, it will always try the first server in the list, then if that fails it will try the second in the list, then if that fails the third, and so on. Other ServerSet implementations exhibit different behavior. But as far as the connection pool is concerned, once a connection becomes part of the pool, every connection is equally well-suited to process any operation.

    Here's what I would recommend for your configuration:

    1. Create a FailoverServerSet so that it will try S1 first, then S2, then S3.
    2. Use the FailoverServerSet.setMaxFailoverConnectionAgeMillis method to specify whatever "quarantine" time you want. If an attempt to connect to S1 fails and the server set instead creates a connection to S2 or S3, then this setting controls the length of time that the connection pool will consider that connection valid before trying to close it and establish a new one to take its place (and hopefully by that time S1 will be available again). This feature was just introduced in the 2.3.5 release.
    3. Create a new LDAPConnectionPool using the FailoverServerSet instance.
    4. Use the LDAPConnectionPool.setRetryFailedOperationsDueToInvalidConnections method to indicate that if an attempt to process an operation within the pool fails in a way that indicates the connection used was not valid, the pool will automatically use the configured server set to establish a new connection and re-try the operation on that connection (and if S1 is down, then it will automatically connect to S2 instead, or S3 if both S1 and S2 are down). This can help prevent your application from seeing a failure if a server goes down while you're trying to interact with it.

    If you use this approach then it is strongly recommended that you use the methods provided by the LDAPConnectionPool class for performing operations rather than checking out a connection, processing one or more operations on it, and then releasing that connection back to the pool (i.e., it's better to use LDAPConnectionPool.search than to use LDAPConnectionPool.getConnection, LDAPConnection.search, and LDAPConnectionPool.releaseConnection). The LDAPConnectionPool.setRetryFailedOperationsDueToInvalidConnections method only has any effect if you process operations through the pool itself rather than on connections you have checked out of the pool.

    If you want more flexibility than this with regard to which servers are used to process which operations, then an alternate approach would be to create a separate LDAPConnectionPool instance for each directory server and then have your application do its own load-balancing between those connection pools rather than trying to shoehorn a single connection pool instance into doing something that it wasn't really designed to do.

     
  • Oscar Golden L.

    Oscar Golden L. - 2013-11-27

    Thanks you very for this answer !
    I followed your suggestion and I was able to get something +/- close to what I described pretty quickly.

    I might need to get a bit more sophisticated in terms of load balancing.
    I need to introduce the concept of connection weight.

    Let's assume S1 and S2 are both primary servers (same highest priority). S3 still has a lower priority.
    S1 and S2 are now assigned a weight resp. W1 and W2, meaning if the pool has N connections available, N * W1 connects to S1 and N * W2 to S2.

    1. If S1 (or S2) goes down :
      • all new connections should go to S2 ( or S1)
      • No failover to S3 yet
    2. If S1 AND S2 go down :
      • FailOver to S3
      • Automatic failback to S1 and/or S2, as soon as they become avaialble (as described in the original post)

    I read something about defining complex configuration by combining different types of ServerSet. I was wondering if this particular example is implementable with a combination of RoundRobin and failOver ServerSet. Do you have any clue how this may be done ? Is is as simple as creating a ConnectionPool with a FailOverServerSet(RoundRobinServet(S1,S2), S3) ?

    Again your feedback was greatly appreciated

     

    Last edit: Oscar Golden L. 2013-11-27
  • Oscar Golden L.

    Oscar Golden L. - 2013-11-28

    Follow-up: I think I figured out the case explained in my previous post.
    The connection should be created with a servetSet that looks like something like FailOverServerSet( RoundRobinServet(S1,S2), SingleServerSet(S3) ).

    Back to the case with only one primary server.
    In the original post, I mentioned something about trying N times a connection before failing over to the secondary server. Let's say N=3.
    Do you think a pool created with the following ServerSet will do it ?
    FailOverServerSet( RoundRobinServet(S1,S1), RoundRobinServet(S2,S2), RoundRobinServet(S3,S3) ).

     
    • Neil Wilson

      Neil Wilson - 2013-11-28

      Using a RoundRobinServerSet inside of a FailoverServerSet is the correct way to try to have a number of servers with equal priority, with failover to another server or set of servers if all of the initial set of servers are down.

      The example you gave in the second paragraph would cause the SDK to first try to create a connection to S1, then if that fails try again to create a connection to S1, then if that fails try to create a connection to S2, then if that fails try again to create a connection to S2, then if that fails try to create a connection to S3, then if that fails try again to create a connection to S3, then if that fails throw an exception.

      If that's what you wanted to accomplish (multiple attempts to connect to the same server, rather than multiple attempts to process an operation in a server), then I apologize for misunderstanding your original intent. The approach you have outlined should accomplish that. And if you wanted S1 and S2 to have the same priority but make two attempts to each of them before failing over to S3, then you could do:

       FailoverServerSet(
            RoundRobinServerSet(S1, S2),
            RoundRobinServerSet(S1, S2),
            RoundRobinServerSet(S3, S3))
      

      This would try one each to S1 and S2 before making a second attempt at either server, and only if all four attempts fail would it make up to two attempts to connect to S3.

      And of course if none of the existing ServerSet implementations do exactly what you want, you're free to create your own.

       

Log in to post a comment.