测试通过一切准备就绪,放到QA的集群环境上面就发现,很多报错的请求。大概长这样子:
前端
后端
“Unauthorized client with sessionId”两次xhr请求发送到了两个服务器导致其中一台在尝试用过sessionId获取client信息时获取不到,从而主动断开了连接。
什么原因呢?这就要从socket.io的原理说起。
刚开始并没有websocket,只有http,我们要实现数据的实时展示该怎么办呢?那就不断的发http请求,模拟一个“实时”的数据传输,就是polling(轮询)模式。
是可以勉强达到目的,但是,很显然http是无状态的,而且每次轮询的时间间隔的长短决定了数据的“实时”度,毕竟啥时候服务器有数据产生,客户端是不知道的,为了标记同一类交互,还加了个sessionId,直到有了websocket也一样用了sessionId。
后来有了websocket模式代替了模拟长连接,做到了真正的实时推送数据。客户端发送连接请求,服务器恢复连接成功,握手成功。直到没有数据推送到超时。
nginx默认的负载均衡策略是轮询,所以有可能同一个sessionId的请求会被转发到不同的机器上去,这个时候会收到错误的response也就不奇怪了。当天如果运气好,请求都转到同一台机器,当请求升级为websocket后连接就成功了。
当然我们不可能碰运气。
- server {
- listen 80;
- listen 443 ssl;
- server_name example.domain;
- root "/project/path";
- index index.html index.htm index.php; // 配置负载的后端
-
- upstream socket_nodes {
- ip_hash;
- server server1.app:5000 weight=5;
- server server2.app:5000;
- server server3.app:5000;
- server server4.app:5000;
- }
-
- location /socket.io/ {
- proxy_pass http://socket_nodes;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
- proxy_http_version 1.1;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header Host $host;
- }
-
- // 其他配置项
- // ...
- }
客户端和服务端都指定使用websocket模式一次性握手成功,不存在轮询,问题不就解决了
客户端:
socket = io.connect('192.168.x.x:10086/remoteWeb?token=stj2htu5qznutlngk48n9j98kz8r2m6d&lang=en',{path:'/localPath/socket.io',transports:['websocket']});
服务端:
在创建配置的时候加上
config.setTransports(Transport.WEBSOCKET);
我们在开发过程中要时刻注意产品化,在开发环境上单机开发可能没问题,但一上集群环境就各种问题。很尴尬,当然,这也是因为开发环境和生产环境不对等导致的。
在有websocket之前,实时数据的请求是http请求使用polling模式模拟的,握手的过程可能要好几个polling请求升级到websocket模式