Forum Discussion

AndrewM_4835's avatar
AndrewM_4835
Icon for Nimbostratus rankNimbostratus
Jun 11, 2008

Hash Load Balancing

Dear Forum,

 

 

I am looking at trying an iRule to persistently load balance a group of web servers.

 

 

I have found an article 'Hash Load Balancing and Persistence on BIG-IP LTM' which does pretty much what I want to do - only I am running 9.2 on a pair of 6800s and the "active_members –list" does not exist.

 

 

when HTTP_REQUEST {

 

set picked [lindex [active_members –list test_pool] [expr [md5 [findstr [HTTP::uri] "SER=" 4 2]] % [active_members test_pool]]]

 

pool test_pool member [lindex $picked 0] [lindex $picked 1]

 

}

 

 

 

- but this doesn't work on 9.2

 

 

There are 12 servers in the test_pool, and I want all requests that have the same "SER=xx" to be sent to the same backend server...

 

 

Any suggestions?

 

 

(And please don't say upgrade)

 

 

Andrew
  • Here is a piece of logic that may help.

    192.168.1.x represents all the pool members in your test_pool.

     
     . 
     . 
     . 
     set active_members { } 
     set pool_list { 192.168.1.10 192.168.1.12 192.168.1.13 192.168.1.14 ... etc.  } 
         foreach node_address $pool_list { 
             if {LB:status pool test_pool member $node_address eq "up" } { 
                lappend active_members $N 
            } 
         }  
     . 
     . 
     . 
     

    Least to say I don't like embedding IP addresses into iRule, but I thought it might get you in the right direction and hopefully the iRule pro's in this forum would jump in enhance it or simply figure out a better way. I would also investigate using classes to replace the IP address simply because it's cleaner.

    I hope this helps,

    CB

  • I got this kind of thing working nicely, however, i am on 9.4.3 so....

     

     

    http://devcentral.f5.com/Default.aspx?tabid=53&forumid=31&view=topic&postid=23963
  • The solution with checking which nodes are currently active myself seems a little slow - and I can't imagine it scales very well...

     

     

    I originally tried "persist uie", but the problem I had is that initially, should one server go down, all load would be split across the remaining servers BUT when I bring the broken server back up, it no longer gets any traffic as all '100' different values are mapped to the other servers until a timeout happens.

     

     

    This is even worse during a complete restart, because with stupid luck, 1 of the 4 servers may get ALL the traffic.

     

     

    Does persist hash not also have the same problem?
  • If you refering to the one I posted, I have already tried this on a ~100,000 connections/sec and apparently it works just fine. What doesn't scale well is adding the multiple IP addresses. However, if you see that it's slowing you down then it's possible that it's plateform dependent performance OR settings dependent. Currently, I am using it on several 8400s and 6400 LTM.

     

  • In LTM 9.2.4 md5 returns a string and not a number - is this different in 9.4?

    which is why

    set test [ [ expr [md5 {[findstr [HTTP::uri] "SRV=" 4 2]} ] % [llength $active_server_list] ]]

    doesn't work.

    where string looks like http://.../blubber?SRV=xx where xx is a number between 00 and 99.

    I also tried using crc32 - but I found that with only 100 different possibilities, it didn't spread the load evenly enough.

    My rule so far without checking for an empty string in SRV, or that they aren't numbers between 00 and 99, and that at least one server is working:

      
      when HTTP_REQUEST  
      {  
        log local0. "Request: [HTTP::uri]"  
         set search_server_list { {10.0.164.11 20001}  
                                 {10.0.164.11 20002}  
                                 {10.0.164.11 20003}  
        }  
        set active_server_list {}  
         
        foreach node_address $search_server_list  
        {  
            if { [LB::status pool search_hash_pool member [lindex $node_address 0] [lindex $node_address 1]] eq "up" }  
            {  
              lappend active_server_list $node_address  
            }  
        }  
        set picked [ lindex $active_server_list [expr {[findstr [HTTP::uri] "SRV=" 4 2]} % {[llength $active_server_list]}] ]  
        pool search_hash_pool member [lindex $picked 0] [lindex $picked 1]   
      }  
     

    I tried adding the set search_server_list to RULE_INIT, but unfortunately no longer had access to it in the event, which means I need to reset its value every HTTP_REQUEST event....

    After doing all of this, I will probably upgrade to 9.4.x as this all feels nasty - haven't had a chance to performance test it yet though.

    Any thoughts or comments?

    Thanks

    Andrew
  • Modified version with error checking

     
     when HTTP_REQUEST 
     { 
        set search_server_list { {10.0.164.11 20001} 
                                {10.0.164.11 20002} 
                                {10.0.164.11 20003} 
       } 
       set active_server_list {} 
       
       foreach node_address $search_server_list 
       { 
           if { [LB::status pool search_hash_pool member [lindex $node_address 0] [lindex $node_address 1]] eq "up" } 
           { 
             lappend active_server_list $node_address 
           } 
       } 
       if {[catch {set server_number [expr {[findstr [HTTP::uri] "SRV=" 4 2]} % {[llength $active_server_list]}] }]} 
         { 
           pool search_hash_pool 
         } 
         else 
         { 
           set picked [ lindex $active_server_list $server_number ] 
           pool search_hash_pool member [lindex $picked 0] [lindex $picked 1] 
         } 
        
     } 
     

    Now all that remains is to test the performance.

    Thanks all for your help.

    Regards

    Andrew
  • This rule has been up and running for about a month now.

     

     

    After enabling this rule on a pair of 6800s I saw NO jump in the CPU usage on the boxes -

     

     

    FYI: I have about 50 req/s on this rule.

     

     

    So the great news is - it works and is usable.

     

     

    Cheers

     

     

    Andrew
  • Patrick_Chang_7's avatar
    Patrick_Chang_7
    Historic F5 Account
    md5 produces a string. You can use the binary scan command to convert this to an integer. see the election hash iRule to see how this works.