In my role as an ADC I often get to run customer labs – this is where we take a customers application, install it on the hardware we have in Reading, and then exercise a number of load tests against it to see what opportunities there are for performance and scalability tweaking.
Just before Christmas I was in the labs with one of my customers who have a high-profile site due to go live in a few months. I’ve been working with them for about 18 months and they now have a really scalable architecture which, based on the numbers we got in the labs, should deal with all the load likely to be chucked at it.
Anyhow, one of the new bits of kit I got to play with this time was a Big-IP box from F5. It’s a hardware load balancer and I must say I was very impressed with its capabilities so thought I should blog about it.
First off, a picture of the architecture :-
At the top we have our load injectors – there were 8 of these during testing. Each request goes through the Big-IP box which executes code against the request (known as an iRule, more on those in a bit), and then the request ends up on one ‘node’ or another – here ‘node’ applies to a group of servers, in our case containing four physical servers and a local database server. Then we have the main database behind the scenes – we were using SQL Service Broker for communication between the node database and the back-end database.
Now, the reason we were using this load balancer wasn’t just to balance load – based on the way the system was setup we wanted to partition requests based on some criteria, as in actuality we had partitioned user data across the nodes. A simplistic example would be all users with surnames ‘A’ - ‘M’ would be redirected to node 1, all others to node 2. Originally we had some code on the nodes which would decide if the request was appropriate for the node it had come in to, and if not pass it on to the appropriate node. However, with the Big-IP box we were able to make this choice on the load balancer itself, thus minimising the code on the nodes and also simplifying any changes that might need to be made into one place. It’s possible to partition load based on any criteria you can think up – maybe geographical (load from South Africa goes to a server in Johannesburg, load from the UK goes to a node in Manchester), maybe based on availabilty (the last request to node1 timed out, so try node 2 for now), or a host of other criteria.
In order to do our partitioning scheme we had to write an iRule. An iRule is some code that is executed on the Big-IP box on a given event – it uses a fairly simple yet powerful syntax (based on a version of TCL) which is tailored to suit the environment. There are custom commands that have been added to the language by F5, and some standard TCL commands have been removed too. The language is targeted to do one thing well – and this it does! The iRule is compiled and is then executed based on the particular event or events it has been defined for. For a definition of the events you can handle see here.
The rule we came up with was as follows :-
when HTTP_REQUEST { log local0. "in HTTP_REQUEST" if {[HTTP::uri] starts_with "/node1"} { pool Pool1; log local0. "pool1 selected" #Remove node1 from the uri set uri [string range $uri 4 end] HTTP::uri $uri } elseif {[HTTP::uri] starts_with "/node2"} { pool Pool2; log local0. "pool2 selected" #Remove node1 from uri set uri [string range $uri 4 end] HTTP::uri $uri } }