Forum Discussion

Tony_Jarvis_132's avatar
Tony_Jarvis_132
Icon for Altostratus rankAltostratus
Jun 25, 2014

Use iRules to query number of active connections against a node

I am currently trying to automate a lot of the "out of the box" behaviour available on the BIG-IP using iRules which is, to say the least, quite a task. The reason for doing this is that we have an environment using DNS hostnames instead of IP addresses and because of that, we cannot configure nodes as pool members since this hard codes the node IP address as the pool member. I know there are other options like using iCall and GTM, but there's a whole lot of history and I'm trying to make the background short.

 

In a nutshell, I am trying to program the Least Connections (Member) load balancing algorithm using iRules, and resolving each hostname to an IP address as part of the HTTP_REQUEST event. Not pretty, I know.

 

My question is simple, but I'm not sure if the answer will be. I need a way to code the least connections algorithm. In order for that to work, I need to programatically query the number of active connections (for a virtual server and specific port...not including connections made from other virtual servers or other ports) against specific nodes.

 

I know this can be done using the TM shell by looking at the connection table, but I need it to be wrapped up in code that can be put inside an iRule.

 

Is there any way at all to do this using iRules?

 

  • Not sure what you're looking for here.

     

    • The client connects to the virtual server
    • Instead of a pool you have a group of host names you use
    • For each request the client makes you want to choose the hostname with the least connections, resolve it again, and send the request to the resolved.

    Is this correct? If it is you're looking at additional latency for every query and I believe overhead in terms of new tcp connections for every request (unless you're using NAT and can re-establish only the server side connection). But I guess you're aware of that already? :)

     

    /Patrik

     

  • If I may add, it doesn't sound like you need to worry about load balancing algorithms, although this can be done with the LB::mode command. If you're doing a DNS resolution on each HTTP request, then the returned value is presumably going to be a single IP address. To Patrik's point though, this can be expensive. It might make more sense to manage a local table entry and cache a response for at least as long as the TTL in the response. If the table entry exists, use it, otherwise query and insert the value into the table for later use.

     

    I suppose it's possible, but do the returned IP addresses change wildly? If not, it may also make sense to just automate the update of the pool members using a perpetual script, and subsequently monitor these members in case an IP goes away between script calls.

     

  • Thanks for the replies, both very helpful!

     

    I am aware of the overhead incurred with DNS lookups, but at least the RESOLV::lookup command caches queries. Unfortunately it is a requirement given to us and we have to play ball (it's a very customised environment that necessitates this flexibility as the servers can be passed around between locations using VMotion etc and the IP addresses can change).

     

    Very interested in the possibility of using a perpetual script to update the pool members...how might this be done?

     

    I don't think I can use the LB::mode option as that only applies to pools with pool members. With this setup, I cannot add pool members in, because by doing this it will save the IP addresses of those members and it will not allow the DNS lookups to be acted upon. My solution is currently doing DNS lookups via iRules and sending the requests to the approporiate node programatically with no pool members defined.

     

    Kevin, just one final note - the resolution for each hostname will be a single IP address, but we are load balancing across multiple hostnames. So basically we have a simple setup of two hostnames, each of these need to be resolved to their own IP addresses, and it's the load balancing across each of these resolved IP addresses that I want to match up with a least connections type of algorithm. Hope that makes sense.

     

  • The idea of a perpetual script is to, on some regular and frequent basis, query for the DNS records of a given site, and then update a pool. That pool would have a regular load balancing algorithm applied, and a reasonable monitor to make sure requests don't fail somewhere in between the asynchronous DNS queries. It's not as real-time as using RESOLV::lookup, but it's a lot less expensive.

     

  • Have you considered using iControl to change the pool members? If you have any control over the "floating" members you could possibly write a script which was triggered when the member moves changing it's member IP as well.

     

    /Patrik

     

  • Okay, so give this a shot:

    Shell script:

    !/bin/bash
    
     user-defined: dns_server
    dns_server="10.80.0.200"
    
     user-defined: host to resolve
    host="tester.mydomain.com"
    
     user-defined: host port
    host_port="80"
    
     user-defined: pool to update
    pool="tester-pool"
    
    lookup=($(dig @$dns_server $host +short))
    
     pre-define host_list
    host_list=""
    
    for x in ${lookup[@]}
    do
        host_list="$host_list $x:$host_port"
    done
    
    if [ "$host_list" != "" ]
    then
        tmsh modify ltm pool $pool members replace-all-with { $host_list }
    fi
    

    Create a cli script to point to the shell script:

    > tmsh create sys icall script update-pool
    
    create script update-pool {
        app-service none
        definition {
            set update [catch {exec /config/dev/archive/update-pool.sh}]
        }
        description none
        events none
    }
    
    ** modify the above to point to your shell script
    

    Create a periodic iCall:

    create sys icall handler periodic update-pool script update-pool status active interval 300
    

    This will create a periodic (I know I said "perpetual" but I meant periodic) script to completely update the given pool with the returned DNS values.

  • Appreciate all the help thus far, but just curious...I've searched around and honestly can't find an answer to the original question:

     

    Is there any way to use an iRule to query how many active connections are currently on a node using the node IP and destination port as the query value (I mean, if the same node is also listening on other ports I don't want those connections to count).

     

    Any way to do this using iRules?

     

  • Is there any way to use an iRule to query how many active connections are currently on a node using the node IP and destination port as the query value (I mean, if the same node is also listening on other ports I don't want those connections to count).

     

    i understand irule sits in data plane but stats you are looking for is in control/management plane. i do not think there is straight way to get that stats in irule. of course, there is a tricky way such as icall, external script, etc.

     

  • A few additional things to consider:

     

    1. A "node" is simply an IP address, while a (pool) "member" is defined by an IP and port/service. If you wanted to know the number of connections to a node on a given port, then you'd be specifying a pool member.

       

    2. There is no functionality, currently, within iRules to see the number of connections to a given node or member, so any solution would likely require diving into the management plane from the iRule.

       

    3. There are a number of ways to do the above, from iStats, to some method of updating a session table entry. In any case, you would need some asynchronous management plane process to update that data, which means it would never be "real time", and probably not so effective given that you're looking for a number of active, transient TCP connections.

       

    4. While this is certainly possible, I would never recommend it. Reaching into the management plane from an iRule for a piece of information, randomly and seldomly may be okay, but doing so in every HTTP request would probably decimate the memory usage of the management plane.