我可以通过身份验证与 HAProxy 和 socket.io 进行粘性会话吗?
Posted
技术标签:
【中文标题】我可以通过身份验证与 HAProxy 和 socket.io 进行粘性会话吗?【英文标题】:Can I have sticky sessions with HAProxy and socket.io with authentication? 【发布时间】:2011-12-30 05:55:02 【问题描述】:我有几个在 HAProxy 下运行身份验证的 socket.io 实例,我需要强制身份验证请求和套接字连接转到同一个实例。我已经基于this answer to a SO question 设置了 HAProxy,并进行了一些修改:
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
我尝试了 url_param(其中 sessionId 是在身份验证调用和 websocket 连接中传递的查询字符串参数)和 source 作为平衡选项,但似乎 HAProxy 只允许这些选项用于 HTTP 连接,因此忽略它们实际的 websocket 连接。结果是有时auth请求和socket连接会在不同的服务器上结束,这对我们的应用来说是不可接受的。
有什么方法可以实现这种期望的行为吗?
【问题讨论】:
您有没有想过最好的方法?我想做同样的事情。谢谢。 我最终使用了 IP 哈希平衡。来自同一个 IP 的所有请求都到同一个服务器 好的,但这是否意味着从服务器 A 上的用户广播的 websocket 不会到达服务器 B 上的任何用户? 您需要使用单独的数据库来存储会话。 Socket.io 支持 redis 数据库来存储跨节点的套接字会话信息,只需将不同的 socket.io 服务器指向同一个 redis db,它应该可以工作。 【参考方案1】:我以这种方式使用基于 cookie 的平衡:
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
【讨论】:
对于cookie方法,有没有办法设置cookie超时时间?【参考方案2】:为了平衡 TCP 连接,您可以使用 stick_match
或 stick on
命令并显式设置 tcp 模式在粘性表方面取得一些成功。
这是一个例子:
# 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
提供完整文档here。
【讨论】:
【参考方案3】:对于 websocket 连接使用roundrobin
平衡。由于它的双向套接字(通过 TCP)默认保持粘性。对于其他传输使用source
平衡算法是最好的选择。 (您可以使用基于 cookie 的持久性,但 socket.io 不会将 JSESSIONID 等发送回代理服务器。如果您想要基于 cookie 的持久性,可以尝试sockjs。)
例子:
#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
【讨论】:
问题是认证请求和websocket连接可能最终在不同的服务器上。有没有办法让他们总是去同一个服务器?您知道是否有其他负载均衡器提供此功能? 只要您的身份验证商店与应用程序分开,命中哪个服务器都没有关系。希望您没有将内存用作身份验证会话的存储。使用 Redis 之类的东西来存储身份验证密钥。看看我在这里处理身份验证的答案:***.com/questions/4753957/socket-io-authentication/…【参考方案4】:您正在使用 HTTP,因此插入一个 cookie 以实现持久性 - 这绝对是最佳途径。除非它关闭,否则它将坚持到他们去的第一台服务器。
您还可以配置它是否应该在它关闭时重新调度它等。
【讨论】:
【参考方案5】:就我而言,我需要使用Authorization: Bearer $ACCESS_TOKEN
对用户进行身份验证,对于这种身份验证,您可以使用stick_tables。
以下配置设置 balancer-host 端口80
跟踪并粘贴Authorization
标头相同的连接:
frontend :80
mode http
bind :80
default_backend http_servers
backend http_servers
balance roundrobin
stick-table type string len 600 size 1000m expire 5m
stick on req.hdr(Authorization)
server server81 192.168.1.1:81 weight 1 maxconn 512 check
server server82 192.168.1.1:82 weight 1 maxconn 512 check
server server83 192.168.1.2:83 weight 1 maxconn 512 check
【讨论】:
以上是关于我可以通过身份验证与 HAProxy 和 socket.io 进行粘性会话吗?的主要内容,如果未能解决你的问题,请参考以下文章