Forum Discussion

Jeff_43264's avatar
Jeff_43264
Icon for Nimbostratus rankNimbostratus
May 19, 2010

Hash persistence based on true-client-IP

Greetings all,

 

 

I'm working on my first iRule, because of a unique requirement I have. I am setting up load balancing for a web-based application that is very sensitive to view state, and so persistence of user sessions is essential. The application is being delivered through Akamai, and I had originally set up persistence by injecting a cookie but Akamai is either caching or removing the cookie in some cases, so I'm working on alternatives. Right now, I want to use hash persistence based on the true-client-ip header that Akamai populates.

 

 

Here is what I have so far, but I'd like some help sanity-checking the logic and the syntax since the last time I touched TCL was in about 1997. I apologize for excessive commenting, they're for my own sanity:

 

 

===================================================

 

when CLIENT_ACCEPTED {

 

check for True Client IP header:

 

if { [HTTP::header exists "True-Client-IP"] } {

 

 

chuck the value into a variable

 

set tcip_header [HTTP::header "True-Client-IP"]

 

 

or throw in a default value, if the header isn't there

 

} else { set tcip_header "1.1.1.1"

 

}

 

}

 

 

select node by hashing True-client-IP value and pulling that item from the node list from the pool

 

set picked [lindex [active_members –list app_http_pool ] [expr [md5 [$tcip_header]] % [active_members app_http_pool]]]

 

 

send traffic to the selected pool member

 

pool app_http_pool member [lindex $picked 0] [lindex $picked 1] }

 

==================================================

 

 

Most of the code came from the simple hash example posted here:

 

http://devcentral.f5.com/Default.aspx?tabid=63&PageID=150&ArticleID=135&articleType=ArticleView

 

 

I admit I'm a little baffled by the lindex commands in the last line of functional code. As far as I can tell, the code above that sets the value of $picked to one pool member - namely, the member whose index value in the list of members equals the result of the modulo expression. Why does the example call the pool command with value 0 and value 1 in $picked?

 

 

In any case, if the rule above works, I should be able to add the iRule, set up a hash persistence profile for the virtual server and attach the iRule to it, and that will override whatever load balancing algorithm I set on the pool, I believe?

 

 

Thanks in advance for all of your help.

 

Jeff

 

5 Replies

  • One update already, I need to change the first line to use HTTP_REQUEST. When I was writing this, I was confusing this application with another one I've been working on that balances Windows RDP traffic (port 3389). But this rule is absolutely for HTTP traffic.

     

     

    New code:

     

     

    ===================================================

     

    when HTTP_REQUEST {

     

    check for True Client IP header:

     

    if { [HTTP::header exists "True-Client-IP"] } {

     

     

    chuck the value into a variable

     

    set tcip_header [HTTP::header "True-Client-IP"]

     

     

    or throw in a default value, if the header isn't there

     

    } else { set tcip_header "1.1.1.1"

     

    }

     

    }

     

     

    select node by hashing True-client-IP value and pulling that item from the node list from the pool

     

    set picked [lindex [active_members –list app_http_pool ] [expr [md5 [$tcip_header]] % [active_members app_http_pool]]]

     

     

    send traffic to the selected pool member

     

    pool app_http_pool member [lindex $picked 0] [lindex $picked 1] }

     

    ==================================================

     

     

  • Hi Jeff,

    The two lindex commands are parsing the pool member IP and port from the active_members list. As you're not actually using persistence with this, you shouldn't need to add a persistence profile to the VIP. The load balancing algorithm will also be ignored as you're using the iRule to select the pool member based on the client IP address that Akamai reports the request came from.

    Also, you could make that rule just a little more efficient by eliminating the intermediate variable $picked. You can also add logic to handle the pool being down or the scan command failing to parse the IP and port output:

    
     Check if the active_members command returns an entry which can be split on a space into two variables
    if {[active_members app_http_pool]}{
       if {[scan [lindex [active_members –list app_http_pool] [expr {[md5 $tcip_header] % [active_members app_http_pool]}]] {%s %s} ip port] == 2}{
           Select the pool member IP and port
          pool app_http_pool member $ip $port
    
           Exit from this event in this rule
          return
       }
        Take some default action if the pool is down or scan didn't parse the output?
    }
    

    Aaron
  • Ah! I was working under the assumption that I would need a hash persistence profile as described here:

     

     

    http://devcentral.f5.com/Default.aspx?tabid=63&PageID=149&ArticleID=135&articleType=ArticleView

     

     

    But what you're saying is that if I apply the iRule to a virtual server, both the load balancing algorithm and the persistence profile really become irrelevant? That makes sense but operationally, I wasn't sure how I needed to configure it once I had a valis iRule.

     

     

    Just to check that I'm clear about the two lindex commands... so the "active_members -list " command is returning a list of items, each item containing an ip and a port, so the lindex/modulo combination returns one of those items. The second lindex command essentially breaks it up, "lindex $picked 0" being the IP and "lindex $picked 1" being the port?

     

     

    Thank you very much for your help so far, I appreciate it.

     

     

    -Jeff
  • Hi Jeff,

     

     

    I think you have a good understanding now. If you want to confirm your initial thoughts you can add logging of each command's output using intermediate variables and check /var/log/ltm for the output.

     

     

    One downside of this method is that if the pool membership changes (pool member removed from the pool, marked down by a monitor, etc), it can break the pool member selection.

     

     

    Aaron
  • Understood, Aaron. I'm not worried in the short term because the pool will only contain 2 nodes; in that scenario, dropping a node will not effect half of the active users, and the other half will get redistributed to the only other possible node. If we decide to scale up to three or more nodes, I may have to think about using the election style algorithm from the article I linked above.

     

     

    I'll look in the wiki for variable logging examples and give that a shot. I'll need to make sure Akamai is actually passing what I expect them to.

     

     

    Thanks again for the advice.

     

     

    Jeff