Sticky sessions and mod_proxy_balancer

by Goldmund, Wyldebeast & Wunderliebe last modified Dec 30, 2008 03:03 PM

This document explains how-to enable sticky sessions in a Zope/Plone HA cluster so authenticated users are routed to the same back-end.

How to get Plone working with mod_proxy_balancer.

Getting Plone to work with mod_proxy_balancer is straightforward: enable the proxy modules proxy, proxy_http and proxy_balancer for Apache (usually by dynamic linking it from mods-available into mods-enabled), and configure the balancer as given in the following example.

N.B. This is the configuration without sticky sessions

<VirtualHost *>
   ServerName foo.bar.com
   #LogLevel debug 

   <Proxy balancer://lb>     
     BalancerMember http://192.168.1.10:8282     
     BalancerMember http://192.168.1.11:8282   
   </Proxy>

   # Conditional proxy pass
   ProxyPass /balancer-manager !   
   ProxyPass /admin lb://foobar/VirtualHostBase/http/foo.bar.com:80/VirtualHostRoot/_vh_admin   
   ProxyPass / lb://foobar/VirtualHostBase/http/foo.bar.com:80/myportal/VirtualHostRoot/

   CustomLog /var/log/apache2/foo.bar.com.log combined 
</VirtualHost>

Assuming that:

  • you use a virtual host named foo.bar.com, running on port 80
  • you have two back end servers on the IP-addresses 192.168.1.10 and 192.168.1.11, where Zope uses port 8282 on both machines
  • the Plone instance has an id myportal
  • the /admin/manage URL extension gives access to the ZMI

 

However, after experimenting with a more complex setup of Single Sign-On with a separate Yale CAS server, it has appeared that simple load balancing doesn't work. The reason could be that there is no session replication between Zope instances (is that necessary?), but remains somewhat unclear. The effect however is that when an authenticated user is switched between back-end nodes, weird behavior occurs.

 

The solution, according to the mod_proxy/mod_proxy_balancer documentation, is simple: you need sticky sessions

for authenticated users, so that all requests by that user are routed to the same back-end once logged in. Sadly, you need the source code to find out how it really works. Not only do you need to provide the name of the cookie holding the sticky

session: the cookie value needs a specific format as well. The cookie value must be formatted like <value>.<route id>

.

To enable sticky sessions for Zope a few things need to be in place:

  • a cookie (or session variable) that holds the routing information
  • configuration that defines this cookie id for the balancer
  • configuration that defines routing for each back-end

 

mod_proxy_balancer

will check the request for a sticky session cookie or request variable, parse the value, find the route contained in the cookie value, and find the balancer member deisgnated for this route.

 

 

Routing cookie

The routing cookie can have a random name, but the value of the cookie needs to contain one '.', where the part before the dot is irrelevant, and the part after the dot contains the route to be used. This route will be matched against the balancer members. To add a fixed route to the balancer member, append a 'route=<route id>' directive to the BalancerMember definition.

 

To add a cookie on login, customize the plone_scripts/setAuthCookie script, and add the following lines:
# Extra cookie for routing
#
remote_address = container.REQUEST.get('HTTP_HOST', '').replace('.', '-')
# strip port number from address
route = remote_address[:remote_address.index(":")]
expires_tomorrow = (DateTime() + 1).toZone('GMT').rfc822()
resp.setCookie('STICKY_ROUTE', 'route.%s' % route, path=cookie_path, expires=expires_tomorrow)

 

This would set the value of STICKY_SESSION to be "route.192-168-1-10" when the request was routed to 192.168.1.10, and obviously "route.192-168-1-11" in the other case.

Sadly, Zope sets the cookie values on the response object as double qouted values, so after parsing the cookie, the route found will be 192-168-1-10". This needs to be reflected in your configuration for Apache.

 

Relevant configuration is now:
 ...
 <Proxy balancer://lb>
    BalancerMember http://192.168.1.10:8282 route=192-168-1-10"
    BalancerMember http://192.168.1.11:8282 route=192-168-1-11"
 </Proxy>

 ...
 ProxyPass / balancer://lb/VirtualHostBase/http/foo.bar.com:80/myportal/VirtualHostRoot/ stickysession=STICKY_ROUTE
 ...

 

Notice the double quotes following the route names!

 

 

To check whether it actually works, uncomment the LogLevel debug line in your configuration, and check your Apache error log (usually /var/log/apache2/error.log) for proceedings of your balancer. Note that you need to actually restart

apache for balancing changes, reloading is not enough.