Sticky sessions and mod_proxy_balancer
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.
Related content
- HA-Cluster with loadbalancing for Zope (and Plone)
- This document describes an HA-Cluster solution for Zope and Plone with load-balancing over two physical machines, based on ZEO. We assume NO single point of failure, and use NO commercial software. Concepts discussed in this howto are applicable to more complex setups.
weird behaviour?
I'm testing mod_proxy balancer right now (without sticky session), but all seems working fine to me :|
Maybe it's related only to istances on different servers? (I'm using 2 ZEOclients on the same machine, but different ports)