Forum Discussion

Dbow_21284's avatar
Dbow_21284
Icon for Nimbostratus rankNimbostratus
May 19, 2011

More efficient iRule needed

Hello,

 

 

I have a Virtual Server that I just setup for SharePoint. SharePoint hosts about 15 sites which the business lines all want Load Balanced. The challenge for me was that I did not want to setup a virtual server for every site. So I consulted DEVCENTRAL and looked for solutions to this. What I read about and came up with is a single virtual server that would use an iRule to direct traffic to pools for each site. Meaning that a pool would be setup for each site. This sounded great because it would allow me to have a separate monitor for each site.

 

 

Here goes an example of the iRUle:

 

 

when HTTP_REQUEST

 

 

{ if { [HTTP::host] equals "AAA.mydomain.org" } {

 

if {[active_members SP_AAAA] > 0} {

 

pool SP_AAAAA }

 

else {

 

HTTP::redirect "http://maintenance.mydomain.org"

 

event disable all

 

}

 

}

 

 

elseif { [HTTP::host] equals "BBB.mydomain.org" } {

 

if {[active_members SP_BBBB] > 0} {

 

pool SP_BBBB }

 

else {

 

HTTP::redirect "http://maintenance.mydomain.org"

 

event disable all

 

}

 

}

 

elseif ..... YADA YADA YADA...

 

 

This goes on for 13 other sites!!! So I realize this is very inefficient. Everytime the user makes a request it has to pass this iRule and therefore performance sucks. If I remove it it works fine. And looking at this now, it make sense why I see these results.

 

 

 

So my question is ... how do I make this better? Should I just make a virtual server for each site? iRules seem like it would be very inefficient in this case. Or is there a way to do this on a connection basis instead of each HTTP request basis?

 

 

 

Your assistance and enlightenment is appreciated!!!

 

 

Thanks!!!

 

 

Dbow
  • Hi Dbow,

     

     

    If the pool name can be determined from the host header value you could parse the host header, verify the format of the name matches some pattern and then try to assign a pool based on it. You can use catch to handle pools that don't exist.

     

     

    Else, if you can't map the host to pool by pattern, you could create a datagroup with the hostname to pool name mappings. For 9.x you'd use findclass for the datagroup lookup. For 10.x, you'd want to use the class command.

     

     

    Here's a recent example from Naladar for this:

     

    http://devcentral.f5.com/Community/GroupDetails/tabid/1082223/asg/50/aft/1172969/showtab/groupforums/Default.aspx

     

     

    Aaron
  • Hi Hoolio,

     

    I am already doing the examination of the host header and assigning to a pool. This is the iRule I have above. Or maybe I am misunderstanding? So right now my iRule looks at the host header, and based on that directs it to a pool (while checking availability of the pool members).

     

     

    This works!! However, my issue is that it is very inefficient. This especially comes into play with an intranet site where people download docs. When they download a 25MB doc, I am guessing that the inspection of every single packet to determine the pool, is causing latency in the user experience. When I remove the iRule and have a single pool the speed is good. When I put the iRule back, the sluggishness reappears.

     

     

    Does this make sense that this would be the case? I thought F5 would inspect each packet regardless of an iRULE. So I was not expecting this and a little stumped.

     

     

    Thanks,

     

     

    Dbow
  • The optimal method for selecting a pool would be a check of the host header and mapping that to a corresponding pool name without going through all possible pool names (whether in an if/elseif/.../else chain, a switch statement or a datagroup). The logic would be something like this:

    when CLIENT_ACCEPTED {
        Save the name of the default pool 
       set default_pool [LB::server pool]
    }
    when HTTP_REQUEST {
    
        Check if Host header ends with my domain
       if {[string tolower [HTTP::host]] ends_with ".example.com"}{
    
           Try assigning a pool in the format of subdomain1_http_pool
           from a host header value of subdomain1.example.com
          if {[catch {pool [getfield [HTTP::host] "." 1]_http_pool} result]}{
             log local0. "[IP::client_addr]:[TCP::client_port]: Error assigning pool [getfield [HTTP::host] "." 1]_http_pool for [HTTP::host]"
     pool $default_pool
          }
       }
    }
    

    If you can't create a pool based just on the subdomain of the Host header value, you could create a datagroup which maps the host names to pool names and then use the class command to do the lookup.

    Just to clarify, every TCP packet is not inspected with any of these iRules. LTM will only collect enough TCP packets to parse the HTTP headers of the requests. This happens when you have an HTTP profile on the virtual server--regardless of whether an iRule is used or not.

    Aaron