While I was troubleshooting a misbehaving application for one of our customer I found out the session stickiness was not working as expected on the Apache acting as a load balancer. I consider Apache to be pretty solid product so I was quite surprised by the finding.
The simplistic configuration could look like this:
ProxyPass / balancer://mycluster stickysession=lbcookie
<Proxy balancer://mycluster>
BalancerMember http://<backend1>:8080 route=01
BalancerMember http://<backend2>:8080 route=02
</Proxy>
It looks trivial: I define locations of the backend servers, enable the sticky sessions and specify the name of the cookie to be used to maintain the stickiness.
On the first request the cookie "lbcookie" is not present therefore Apache will choose the server itself. The application will process the request and include its nodeId (01 or 02) in the cookie sent with the response. Now all the subsequent request will contain the cookie and Apache should pick the backend1 or backend2 depending on the cookie value as specified by the route parameter. Except it doesn't!
The documentation also says:"Some back-ends use a slightly different form of stickyness cookie, for instance Apache Tomcat. Tomcat adds the name of the Tomcat instance to the end of its session id cookie, separated with a dot (.) from the session id. Thus if the Apache web server finds a dot in the value of the stickyness cookie, it only uses the part behind the dot to search for the route."
It says it's looking for a member worker with route equals to the cookie value unless the cookie contains dot. Unfortunately it will not consider the content of the cookie at all if there is no dot in the cookie value! I believe it's caused by this line:
https://github.com/apache/httpd/blob/2.2.x/modules/proxy/mod_proxy_balancer.c#L287
It's searching a dot and if no dot is found than the *route is set to NULL. Therefore the condition on the line 289 is false and the content of the cookie is not taken into a consideration! It effectively disabled the session stickiness.
PS: The bug has been reported to httpd development team.
Follow @jerrinot
Scenario
Let's assume I have a web application deployed on two application servers: backend1 & backend2. Both servers are listening on the port 8080. I want to access the application under a single URL and I use the Apache balance load between the servers. The backend servers don't support session replication therefore I would like to use sticky sessions.The simplistic configuration could look like this:
ProxyPass / balancer://mycluster stickysession=lbcookie
<Proxy balancer://mycluster>
BalancerMember http://<backend1>:8080 route=01
BalancerMember http://<backend2>:8080 route=02
</Proxy>
It looks trivial: I define locations of the backend servers, enable the sticky sessions and specify the name of the cookie to be used to maintain the stickiness.
On the first request the cookie "lbcookie" is not present therefore Apache will choose the server itself. The application will process the request and include its nodeId (01 or 02) in the cookie sent with the response. Now all the subsequent request will contain the cookie and Apache should pick the backend1 or backend2 depending on the cookie value as specified by the route parameter. Except it doesn't!
Problem analysis
To quote the documentation:"The balancer extracts the value of the cookie and looks for a member worker with route equal to that value."The documentation also says:"Some back-ends use a slightly different form of stickyness cookie, for instance Apache Tomcat. Tomcat adds the name of the Tomcat instance to the end of its session id cookie, separated with a dot (.) from the session id. Thus if the Apache web server finds a dot in the value of the stickyness cookie, it only uses the part behind the dot to search for the route."
It says it's looking for a member worker with route equals to the cookie value unless the cookie contains dot. Unfortunately it will not consider the content of the cookie at all if there is no dot in the cookie value! I believe it's caused by this line:
https://github.com/apache/httpd/blob/2.2.x/modules/proxy/mod_proxy_balancer.c#L287
It's searching a dot and if no dot is found than the *route is set to NULL. Therefore the condition on the line 289 is false and the content of the cookie is not taken into a consideration! It effectively disabled the session stickiness.
How to workaround it?
It should be clear by now: Changing the backend server configuration to return node.01 and node.02 will do the trick!PS: The bug has been reported to httpd development team.
Follow @jerrinot