简体   繁体   中英

Can I have sticky sessions with HAProxy and socket.io with authentication?

I have several instances of socket.io with authentication running under HAProxy and I need to force that the authentication request and the socket connection go to the same instance. I've set up HAProxy based on this answer to a SO question with some modifications as so:

global
    maxconn     4096 # Total Max Connections. This is dependent on ulimit
    nbproc      2

defaults
    mode        http

frontend all 0.0.0.0:80
    timeout client 86400000
    default_backend www_backend
    acl is_websocket hdr(Upgrade) -i WebSocket
    acl is_websocket hdr_beg(Host) -i ws

    use_backend socket_backend if is_websocket

backend www_backend
    balance url_param sessionId
    option forwardfor # This sets X-Forwarded-For
    timeout server 30000
    timeout connect 4000
    server server1 localhost:8081 weight 1 maxconn 1024 check
    server server2 localhost:8082 weight 1 maxconn 1024 check
    server server3 localhost:8083 weight 1 maxconn 1024 check

backend socket_backend
    balance url_param sessionId
    option forwardfor # This sets X-Forwarded-For
    timeout queue 5000
    timeout server 86400000
    timeout connect 86400000
    server server1 localhost:8081 weight 1 maxconn 1024 check
    server server2 localhost:8082 weight 1 maxconn 1024 check
    server server3 localhost:8083 weight 1 maxconn 1024 check

I've tried url_param (where sessionId is a querystring parameter passed in both the authentication call and the websocket connection) and source as the balance options but it seems as if HAProxy only allows these options for HTTP connections and so ignores them for the actual websocket connection. The result is that sometimes the auth request and the socket connection end up in different servers, which is unacceptable for our application.

Is there some way to have this desired behavior?

I use cookie based balancing in this way:

backend socketio
    mode http
    cookie SIO insert
    server sock1 127.0.0.1:8001 cookie 001
    server sock2 127.0.0.1:8002 cookie 002

To balance TCP connection, you may have some success with a stickiness table using the stick_match or stick on commands and explicitly setting tcp mode.

Here is an example:

# forward SMTP users to the same server they just used for POP in the
# last 30 minutes
backend pop
    mode tcp
    balance roundrobin
    stick store-request src
    stick-table type ip size 200k expire 30m
    server s1 192.168.1.1:110
    server s2 192.168.1.1:110

backend smtp
    mode tcp
    balance roundrobin
    stick match src table pop
    server s1 192.168.1.1:25
    server s2 192.168.1.1:25

Full documentation available here .

For websocket connections balance using roundrobin . Since its a Bidirectional socket (over TCP) stickyness is maintained by default. For other transports using source balancing algorithm is the best bet. (You can use cookie based persistence but socket.io doesn't send a JSESSIONID or the like back to the proxy server. You can try sockjs if you want cookie based persistence.)

Example:

#do the same for other transports. [Note in 0.6.x resource was mounted at path: /socket.io/[transport]
acl is_JSONPolling path_beg /socket.io/1/jsonp-polling
use_backend non_websocket if is_JSONPolling


backend non_websocket
  balance source
  #rest same as the one for websocket backend

You're using HTTP so insert a cookie for persistence - that's definitely the best route. That'll stick it to the first server they went to unless it's down.

You can also configure whether it should redispatch it if it is down etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM