Nginx Stateful Load Balancing
- Sample standalone nginx config to statefully load balance HTTP requests.
- Reuses Tomcat/Java JSESSIONID cookie to statefully load balance between multiple backends.
- Nginx itself is completely stateless and can be round-robin load balanced from a firewall.
Limitations/Notes
- Nginx open source does not support extensive health checking, use
varnishorhaproxyinstead. - The JVM guarantees that JSESSIONID is unique only to a single tomcat instance. To guarantee unique JSESSIONID across the Tomcat cluster, it is recommended to append the tomcat hostname to the JSESSIONID cookie.
Complete nginx config
# Nginx sample standalone config for active/active load balancing to
# a stateful backend.
# Note: nginx itself is fully stateless, therefore can be run active/active
# Note2: nginx uses JSESSIONID as the hash to statefully load balance the backend
daemon off;
error_log /dev/stderr;
events {}
http {
map $cookie_JSESSIONID $session_cookie {
"" $remote_port; # no cookie, randomly assign a backend
default $cookie_JSESSIONID; # with cookie, choose stateful backend
}
upstream tomcat_backend {
hash $session_cookie consistent;
server tomcat1:8080 max_fails=3 fail_timeout=5s; # use backend server IPs to avoid DNS failures
server tomcat2:8080 max_fails=3 fail_timeout=5s; # use backend server IPs to avoid DNS failures
}
server {
listen 80;
access_log /dev/stdout;
root /dev/null;
location / {
proxy_pass_request_headers on;
proxy_pass http://tomcat_backend;
}
}
}Testing
To test this without a Tomcat application, an easy way is to use Apache/PHP and set PHP to use the same session cookie as Tomcat. This PHP script can be hosted on backend PHP servers with the nginx as an upstream load balancer.
<?php
// index.php to change PHP use Java session ID cookie
session_name('JSESSIONID');
session_start();
echo '<h1>Welcome</h1>';
echo '<h1>SERVER_PORT: ' . 9001 . '/<h1>';
echo '<h1>count: ' . $_SESSION['count']++ . '</h1>';