How to Handle Session Sharing with Nginx Load Balancer

1) Use Cookies Instead of Sessions

Replacing sessions with cookies helps avoid some of the inherent drawbacks of sessions. A J2EE book I read years ago also pointed out that sessions should not be used in clustered systems, or you risk creating hard-to-resolve issues. If the system is not overly complex, prioritize removing sessions entirely. If that proves too cumbersome to refactor, then consider the methods below.

2) Application Server Self-Implemented Session Sharing

For example, PHP can use a database or Memcached to store sessions, effectively creating a session cluster within PHP itself. This approach ensures session stability—even if a node fails, the session is not lost. It is suitable for scenarios with strict requirements but low request volumes. However, its efficiency is not very high, making it unsuitable for high-performance use cases.

The two methods above have little to do with Nginx. Here is how to handle it using Nginx:

3) ip_hash

Nginx’s ip_hash technique can direct requests from a specific IP to the same backend server, thus establishing a stable session between a client under that IP and a specific backend. ip_hash is defined within the upstream configuration:

upstream backend {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
ip_hash;
}

ip_hash is easy to understand, but since it distributes backends based solely on the IP factor, it has limitations and cannot be used in certain situations:

1/ Nginx is not the frontmost server. ip_hash requires Nginx to be the frontmost server; otherwise, Nginx cannot get the correct IP and thus cannot hash based on it. For instance, if Squid is used as the frontmost server, Nginx will only get Squid’s server IP address when fetching the IP, leading to chaotic request distribution.

2/ There are other load balancing methods behind Nginx. If there is another load balancer behind Nginx that distributes requests differently, a client’s requests will certainly not land on the same session application server. In this regard, the Nginx backend should only point directly to the application server, or to a Squid instance which then points to the application server. The best approach is to use a location block to split traffic once, directing the requests that require sessions through ip_hash, while the rest go to other backends.

4) upstream_hash

To solve some of the problems with ip_hash, you can use the third-party module upstream_hash. This module is often used for url_hash, but it can also be employed for session sharing:

If Squid is the front end, it adds the IP into the x_forwarded_for HTTP header. Using upstream_hash, you can use this header as the factor to direct requests to the designated backend:

See this document:

http://www.oschina.net/discuss/thread/622

The document uses $request_uri as the factor. Modify it slightly:

hash   $http_x_forwarded_for;

This changes it to use the x_forwarded_for header as the factor. In newer versions of Nginx, reading cookie values is supported, so you could also change it to:

hash   $cookie_jsessionid;

If PHP is configured to use cookieless sessions, you can combine it with Nginx’s own userid_module to have Nginx issue a cookie. See the English documentation for the userid module:

http://wiki.nginx.org/NginxHttpUserIdModule

Leave a Comment

Your email address will not be published.