Loadbalancing WebSphere-Servers with URI-sensitivity and sticky sessions: Apache vs. IBM Edge

Posted
Comments None

Today, most users will probably use hardware-loadbalancers. However, the rising use of virtual server farms does make software-loadbalancing convenient.

Some sites disallow the use of hardware-loadbalancers in serverfarm-installations (once traffic passes the outter rim of the installations, it may not leave it again within the same request). Thus, more sophisticated balancing will have to be done within the serverfarm. Using a multitude of worker nodes, it is convenient to have the nodes as similar as possible. In an ideal world, workers are aware of their peers and pass traffic on to their neighbors that can handle them. However, COTS or custom built software may have that kind of sophisticated session handling. A software-balancer on each node that handles all incoming traffic can do this job even if the application can not.

There are two widespread possibilities to do software loadbalancing on AIX: the IBM Caching-Proxy/Edge-Component with Context-Based-Routing, and Apache Webserver. This article compares the two required configurations for Java applications running in WebSphere servers.

Prerequisites

Three jobs need to be implemented and properly coordinated to balance traffic content-aware and session-aware:
A load-balancing component that distributes all non-aware traffic evenly across the nodes
Session-stickiness so sessions maintain on a node once the session has been initiated
Content-awareness that overrides the above so that requests that require particular nodes will be routed there independent from a current session (a new session on a different node will be required).
For Java applications, session-stickiness is best done via JSESSIONID. This is called a passive cookie configuration, because the application server sets the cookies, the load balancer just reads them. The advantage of this method is that you can react on whatever the application server does. If it deletes the cookie, you’re back to a round-robin situation. However, different JVMs use different ways of attaching the node to session cookies. Tomcat appends its node ID separated with a dot (”.). IBM WebSphere servers append their CloneIDs with a colon (), and if several WebSphere servers may handle the same request that path may even stack with additional colons as the session passes those nodes. We will not cover that scenario in this article.

In an active cookie configuration on the other hand, the load balancer sets its own cookies, no matter what the application server does. Thus clients usually stay sticky within a whole browser session, if no URI-dependent rerouting is done (or any other span of time you want the cookie to be valid). Conveniently, you can decide on the cookie and its values within the load balancer configuration.

Apache (2.4) Configuration

For apache httpd loadbalancer configuration with URI sensitivity and session stickiness one needs mod_proxy, mod_proxy_balancer and mod_rewrite. Using WebSphere server, you should prepare the CloneIDs of your server instances. This can be done in the WebSphere admin console:

Middleware servers —> —> Web container —> custom properties.

Add one custom property for each host. This example uses nodes appnode1, appnode2 and appnode3:

Name: HttpSessionCloneId
Value: appnode1
Comment: Second part of JSESSIONID: CloneId

Passive Cookie Configuration

Here is a sample proxy configuration in httpd.conf:

Listen 80
ServerName http://www.ourapp.com
UseCanonicalName=on

RewriteEngine On

# Rewrite Requests # RewriteCond %{QUERY_STRING} ^.*useNode=1.*$ RewriteRule (.*) http://www1.ourapp.com%{REQUEST_URI} [P,L] RewriteCond %{QUERY_STRING} ^.*useNode=2.*$ RewriteRule (.*) http://www2.ourapp.com%{REQUEST_URI} [P,L] RewriteCond %{QUERY_STRING} ^.*useNode=3.*$ RewriteRule (.*) http://www3.ourapp.com:1234%{REQUEST_URI} [P,L] ProxySet stickysession=JSESSIONID stickysessionsep=: BalancerMember http://www1.ourapp.com route=appnode1 BalancerMember http://www2.ourapp.com route=appnode2 BalancerMember http://www3.ourapp.com:1234 route=appnode3

SetHandler balancer-manager Order deny,allow Allow from all # You may want to restrict this to your local subnet

ProxyPass /balancer-manager !

ProxyPass /ourapp balancer://mycluster:/ourapp
ProxyPassReverse /ourapp balancer://mycluster/ourapp

Step 1: Sending URI requests directly to target hosts

In this example, rewrite rules will send all URIs containing tag/value useNode=1 in their query string to host http://www1.ourapp.com on port 80. Server 3 listens on port 1234 in this example just to make a difference. The RewriteRule option [P] (proxy request) already includes [L] (last request), so this L is redundant and just for the sake of illustration. No further rules are being processed. So any requests that contain the above pattern will never be balanced but proxied prematurely.

Step 2: Balancing the requests

By adding the BalancerMembers and with the ProxyPass statement below, apache httpd will send any requests that do not satisfy one of our RewriteConds through the balancer. It will do so in a round-robin fashion and based on the number of requests already sent, as no other arguments have been specified. There are more modes you may want to check out.

Step 3: Adding sticky sessions

By naming each BalancerMember with route=appnodeX the balancer can decide which route to take. How to make that decision is specified by the stickysession tag in the ProxySet command. Stickysession reacts on cookies. In this example BalancerMembers use cookie JSESSIONID. For use with WebSphere servers, specify stickysessionsep=:

Apache httpd will then only use the part behind a colon to obtain the route. This route is compared with the contents of the route argument in the BalancerMember statement. If the cookie contents after the separator match the value of the route argument, then this BalancerMember is selected. Otherwise the requests are routed via default distribution mechanism. So this configuration satisfies all three above prerequisites.

Setting a server name and using the canonical name can be handy, especially if a balancer is running behind a gateway server that might terminate HTTPS requests, authenticaiton host, maybe even another shared load balancer within a serverfarm setting, or all of the above.

Active Cookie Configuration

An active cookie configuration with WebSphere may look like this. In this case the CloneID does not need to be changed, as it is not used anywhere in this configuration.

Header add Set-Cookie “ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/” env=BALANCER_ROUTE_CHANGED
RewriteEngine On

# Rewrite Requests # RewriteCond %{QUERY_STRING} ^.*useNode=1.*$ RewriteRule (.*) http://www1.ourapp.com%{REQUEST_URI} [P,L,CO=ROUTEID:.appnode2:;] RewriteCond %{QUERY_STRING} ^.*useNode=2.*$ RewriteRule (.*) http://www2.ourapp.com%{REQUEST_URI} [P,L,CO=ROUTEID:.appnode2:;] RewriteCond %{QUERY_STRING} ^.*useNode=3.*$ RewriteRule (.*) http://www3.ourapp.com:1234%{REQUEST_URI} [P,L,CO=ROUTEID:.appnode3:;] ProxySet stickysession=ROUTEID BalancerMember http://www1.ourapp.com route=appnode1 BalancerMember http://www2.ourapp.com route=appnode2 BalancerMember http://www3.ourapp.com:1234 route=appnode3

SetHandler balancer-manager Order deny,allow Allow from all # You may want to restrict this to your local subnet

ProxyPass /balancer-manager !

ProxyPass /ourapp balancer://mycluster:/ourapp
ProxyPassReverse /ourapp balancer://mycluster/ourapp

In this example, we have to set cookies on our own. This is done (in Apache 2.4) with the “CO” option of the RewriteRule statement. Cookies will be valid for the duration of the browser session by default, unless you want to specify otherwise. Also, we deliberately add a leading “.” just for the sake of demonstration (and to never obtain an empty ROUTEID cookie via the Header statement). Apache httpd will only use the part after the dot. The rest of the httpd configuration is equal to the passive configuration example. There is no need to set a stickysession-separator as a separator can be chosen deliberately, and apache httpd already uses a dot by default.

One more statment is needed in this configuration. When the server sends requests to BalancerMembers by default distribution rule, a cookie needs to be set. The server indicates this route selection by setting environment variable BALANCER_ROUTE_CHANGED. The actual route is written in BALANCER_WORKER_ROUTE. A Header add Set-Cookie statement is added to the server configuration to set that cookie. Subsequent requests will thus be sent to the same node as long as that cookie is not deleted (for example by evil users in their browser).

IBM Edge Configuration

The same configuration can be done with IBM Edge with content based routing (CBR). This example only provides a passive cookie configuration following the example above (the one the author really has seen in a working live server configuration …).

Again, you need to setup your CloneIds in WebSphere configuration as described above for appnode1, appnode2, and appnode3. Secondly, you need to setup a stub in ibmproxy.conf to tell the caching proxy, that hosts the cbr component, to proxy its requests.

proxy     /*    http://www.ourapp.com/*    www.ourapp.com

The actual rewriting is done in the configuration of the cbr component:

# Start executor
#
cbrcontrol set loglevel 5
cbrcontrol executor start
cbrcontrol executor set nfa 10.0.0.1

This sets loglevel to its highest setting, starts an executor, and sets the non-forwarding address of the server to 10.0.0.1. Set this to the interface your proxy runs on. You may want to do this if your first network interface is some admin LAN and you don’t want to bind your proxy there.

# Add the cluster
#
cbrcontrol cluster add www.ourapp.com
cbrcontrol cluster set www.ourapp.com proportions 49 50 1 0

The names in this configuration must be real hostnames and addresses, they are not symbolic names. I recommend using the FQDN for your host you want your proxy to be reachable at. The cluster needs a port where your users can reach it. This port needs to be defined in your config next.

# Define a port for the cluster
#
cbrcontrol port add www.ourapp.com@80
cbrcontrol port set www.ourapp.com@80 stickytime 0

In a passive cookie configuration, the stickytime on cluster ports needs to be set to 0 by convention. If you set a stickytime on the cluster port, you will immediately enter a sticky round-robin setting, ignoring cookie configurations, which does not solve the above prerequisites.

Next, worker bees need to be added. In this example, all worker bees are running on the same host, for example, when.distributing requests between several instances of a JVM that share the same host. You can define the worker bees in /etc/hosts with their IP address, if you don’t want to add them to a DNS:

Sample /etc/host entry:
10.0.0.2   www1 www2 www3

Then, define the balanced nodes in your cbr configuration. This example assumes that the WebSphere servers are listening on ports 10000, 10001 and 10002:

# Define the balanced nodes
#
cbrcontrol server add www.ourapp.com@80@www1 address 10.0.0.2 mapport 10000 weight 9 cookievalue appnode1
cbrcontrol server add www.ourapp.com@80@www2 address 10.0.0.2 mapport 10001 weight 9 cookievalue appnode2
cbrcontrol server add www.ourapp.com@80@www2 address 10.0.0.2 mapport 10002 weight 9 cookievalue appnode3

This setting now should already do round robin distribution between the nodes (non-sticky). Now add rules for content based routing:

# Define rules on the cluster
#
cbrcontrol rule add www.ourapp.com@80@rule1 type content pattern "URI=*useNode=1*" priority 1
cbrcontrol rule add www.ourapp.com@80@rule2 type content pattern "URI=*useNode=2*" priority 2
cbrcontrol rule add www.ourapp.com@80@rule3 type content pattern "URI=*useNode=3*" priority 3

The syntax of attribute pattern is proprietary. Please consult IBM WebSphere documentation (see links below). You can basically match against http headers with =…, wildcard with asterisk (*), and do some Bracketing with (), & and |. As these commands are shell commands, quoting is essential. With these rules, all direct links are sent to their respective hosts once rules are bound to them. However, all URIs that do not match will still be distributed round robin. Therefore, a default rule needs to be added that is always true and implements session stickiness.

cbrcontrol rule add www.ourapp.com@80@rule4 type true priority 4 affinity passivecookie cookiename JSESSIONID

As apache httpd knows about the dot-separator that tomcat uses, IBM EDGE CBR components already know about the colon that WebSphere servers use.

# Map rules to the nodes
#
cbrcontrol rule useserver www.ourapp.com@80@rule1 appnode1
cbrcontrol rule useserver www.ourapp.com@80@rule2 appnode2
cbrcontrol rule useserver www.ourapp.com@80@rule3 appnode3
cbrcontrol rule useserver www.ourapp.com@80@rule4 appnode1+appnode2+appnode3

Next, it is advisable to start manager and advisor on your cluster for better balancing and to check for non-responding sites. However, advisors are optional.

# start manager and advisor
#
cbrcontrol manager start manager.log 10004
cbrcontrol advisor start http www.ourapp.com@80 advisor_80.log

Now you should be all set. You can check the fire ratios of your rules:

cbrcontrol rule report www.ourapp.com@80@rule1
cbrcontrol rule report www.ourapp.com@80@rule2
cbrcontrol rule report www.ourapp.com@80@rule3
cbrcontrol rule report www.ourapp.com@80@rule4

Some useful links and references:

  • apache 2.4 mod_proxy: http://httpd.apache.org/docs/current/mod/mod_proxy.html
  • apache 2.4 mod_proxy_balancer: http://httpd.apache.org/docs/current/mod/mod_proxy_balancer.html
  • Edge components documentation: http://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.edge.doc/lb/welcome_edge.html
  • CBR documentation: http://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.edge.doc/concepts/concepts28.html%23cbr
  • CBR part in load balancer documentation: http://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.edge.doc/lbip4/nd6mst19.html%23configcbr
  • Advanced features of dispatcher, CBR and site selector: http://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.edge.doc/lbip4/nd6mst34.html%23advcon
  • Command reference for dispatcher & CBR: http://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.edge.doc/lbip4/nd6mst41.html%23crnd

Good luck!

Author
Categories

Comments

Commenting is closed for this article.

← Older Newer →