scaryguy
scaryguy

Reputation: 7950

Load balancing with nginx using hash method

I want to use nginx as a load balancer in front of several node.js application nodes.

round-robin and ip_hash methods are unbelievably easy to implement but in my use case, they're not the best fit.

I need nginx to serve clients to backend nodes in respect to their session id's which are given by first-landed node.

During my googlings, I've come up with "hash"ing method but I couldn't find too many resources around.

Here is what I tried:

my_site.conf:

http {

    upstream my_servers {
        hash $remote_addr$http_session_id consistent;
        server 127.0.0.1:3000;
        server 127.0.0.1:3001;
        server 127.0.0.1:3002;
    }

    server {
        listen 1234;
        server_name example.com;

        location / {
            proxy_pass http://my_servers;
            proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_redirect off;
            proxy_buffering off;
            proxy_set_header        X-Real-IP       $remote_addr;
            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

And at the application, I return Session-ID header with the session id.

res.setHeader('Session-ID', req.sessionID);

I'm missing something, but what?

Upvotes: 3

Views: 6355

Answers (2)

Baptiste
Baptiste

Reputation: 1759

It doesn't work out of the box because nginx is a (good) webserver, but not a real load-balancer. Prefer haproxy for load-balancing.

Furthermore, what you need is not hashing. You need persistence on a session-id header and you need to be able to persist on source IP until you get this header. This is pretty straight forward with HAProxy. HAProxy can also be used to check if the session id has been generated by the server or if it has been forged by the client.

backend myapp # create a stick table in memory # (note: use peers to synchronize the content of the table) stick-table type string len 32 expire 1h size 1m # match client http-session-id in the table to do the persistence stick match hdr(http-session-id) # if not found, then use the source IP address stick on src,lower # dirty trick to turn the IP address into a string

# learn the http-session-id that has been generated by the server stick store-response hdr(http-session-id)

# add a header if the http-session-id seems to be forged (not found in the table) # (note: only available in 1.6-dev) acl has-session-id req.hdr(http-session-id) -m found acl unknown-session-id req.hdr(http-session-id),in_table(myapp) http-request set-header X-warning unknown\ session-id if has-session-id unknown-session-id

Then you are fully secured :)

Baptiste

Upvotes: 0

Alexey Ten
Alexey Ten

Reputation: 14364

$http_session_id refers to header sent by client (browser), not your application response. And what you need is http://nginx.org/r/sticky, but it's in commercial subscription only.

There is third-party module that will do the same as commercial one, but you'll have to recompile nginx.

Upvotes: 3

Related Questions