今天要介绍的问题,是一个相对来说比较经典的问题,问题表面看不是很复杂的问题,但是反映出的背后通信逻辑,其实还是比较有意义的。

websocket协议是当前绝大部分浏览器都支持的长连接协议,是HTTP协议的升级版协议,解决HTTP协议的单向通信的弊端,WS(websocket协议的简写)协议,基于长连接,实现客户端和服务端之间的双向通信,这个技术在我们项目里面,主要用来解决客服系统问题,即客户发送的消息以及坐席回复的消息之间,可以实时交互。关于这个协议的更多介绍,请参考官方网站,这里不多做介绍。

下面说下我们项目中,研究websocket连接,在集群环境下,如何解决后端tomcat上只有一个连接实例问题。我们的实验环境,topo架构如下:

结合上面的topo架构,客户端的请求,只有在涉及到websocket的连接的时候,才会从Client LB一直走到Server LB的后面tomcat上。除此之外,其他的客户端请求,只会到client app对应的tomcat即停止。

0.环境信息
1).客户端后台nginx,充当Client LB 
这里的客户端,主要指类似聊天窗的渲染以及基本的和客户端相关的逻辑主体。我们的实验中,客户端,主要就是一个聊天窗口和附着在这个上面的辅助应用。

[root@localhost sbin]# ./nginx -V
nginx version: openresty/1.11.2.2
built by gcc 4.1. (Red Hat 4.1.-)
built with OpenSSL 0.9.8e-fips-rhel5 Jul
TLS SNI support disabled
configure arguments: --prefix=/usr/local/nginx --with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3. --add-module=../echo-nginx-module-0.60 --add-module=../xss-nginx-module-0.05 --add-module=../ngx_coolkit-.2rc3 --add-module=../set-misc-nginx-module-0.31 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.06 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10. --add-module=../ngx_lua_upstream-0.06 --add-module=../headers-more-nginx-module-0.32 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.17 --add-module=../redis2-nginx-module-0.13 --add-module=../redis-nginx-module-0.3. --add-module=../rds-json-nginx-module-0.14 --add-module=../rds-csv-nginx-module-0.07 --with-ld-opt=-Wl,-rpath,/usr/local/luajit/lib --with-http_realip_module --with-pcre --add-module=/usr/local/openresty-1.11.2.2/bundle/ngx_cache_purge-2.3 --add-module=/usr/local/openresty-1.11.2.2/bundle/nginx_upstream_check_module-0.3. --with-http_ssl_module

2)服务端后台nginx,充当Server LB
这里主要指websocket消息的通信处理逻辑,即客户端收到客户的消息后要通过客户端后台反向代理推送给的目的服务地址。

[root@bogon nginx]# ./sbin/nginx -V
nginx version: openresty/1.11.2.2
built by gcc 4.8. (Red Hat 4.8.-) (GCC)
built with OpenSSL 1.0.1e-fips Feb
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3. --add-module=../echo-nginx-module-0.60 --add-module=../xss-nginx-module-0.05 --add-module=../ngx_coolkit-.2rc3 --add-module=../set-misc-nginx-module-0.31 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.06 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10. --add-module=../ngx_lua_upstream-0.06 --add-module=../headers-more-nginx-module-0.32 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.17 --add-module=../redis2-nginx-module-0.13 --add-module=../redis-nginx-module-0.3. --add-module=../rds-json-nginx-module-0.14 --add-module=../rds-csv-nginx-module-0.07 --with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib --add-module=/opt/nginx-rtmp-module-master --with-http_ssl_module

1.客户端应用对应的后台nginx的反向代理配置

upstream ims_client {
server 10.90.9.20:;
server 10.90.9.20:;
}
upstream ims_svr {
server 10.90.7.10:;
}
server {
listen ;
server_name localhost;
default_type text/html;
proxy_send_timeout ;
proxy_read_timeout ; location /IMS_SVR/websocket {
proxy_pass http://ims_svr;
proxy_set_header Host $host:$server_port;
proxy_set_header Remote_Addr $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"
;
}

location /IMS {
proxy_pass http://ims_client;
proxy_set_header Host $host:$server_port;
proxy_set_header Remote_Addr $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
}

对应的客户端应用,在我本地开发机器上,启动了两个tomcat,一个端口7080,另外一个8080,也就是上面nginx配置中的ims_client部分,当客户端请求IMS这个客户端应用时,客户端的界面渲染以及在客户端本地能完成的工作,都在这个应用里面。只有客户端涉及到和websocket连接有关的请求,会被反向代理到ims_svr对应的服务入口上。如上面的nginx配置,ims_svr对应的服务入口,其实就是websocket后端服务端的负载均衡入口地址,这里10.90.7.10:9091其实就是另外一个nginx服务的入口地址。

2. 服务端应用对应的后台nginx的反向代理配置

upstream ims_svr {
server 10.90.9.20:;
server 10.90.9.20:;
#hash $query_string;
#hash $request_uri;
#hash $arg_userId;
}
server {
listen ;
server_name localhost;
default_type text/html; location /IMS_SVR/websocket {
proxy_pass http://ims_svr;
proxy_set_header Host $host:$server_port;
proxy_set_header Remote_Addr $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

这里,主要是将websocket的请求反向代理到后端具体的tomcat服务器上,websocket的对应tomcat服务器有2个,也是本地基于不同端口启动的9080和9081两个tomcat应用。

这次实验的目的,主要是想知道,nginx配置的轮询的方式做反向代理,WS连接,是否也会在后端服务器之间不停的切换,造成后端tomcat上存在多个连接实例peer,因为长连接通信,是存在两个对端实例的。若出现tomcat端出现多个客户端的连接对端peer,那么,就不符合我们业务的需要了,即浪费资源,又不便于逻辑管理。

我们的测试过程中,发现,不论客户端HTML5页面如何刷新,最终websocket总是在同一个tomcat上。这个是非常重要的结论。另外,当Server 端的tomcat停掉一个,比如9080对应的app停掉,客户端HTML5,因为websocket页面js里面添加心跳机制,实现重连,客户在无感知的情况下,websocket重新连接上来,接到了server app 9081上面来了。

客户端聊天界面如下:

通过这次实验得出如下结论:

1. 基于websocket长连接的通信,可以不用通过客户id等指定唯一字段信息进行hash来锁定客户端和websocket服务端之间的peer到peer的映射关系,这个映射关系,应该是在websocket的配置,即nginx中配置代码段中红色部分指定的。

2. 基于websocket的长连接的反向代理,客户端和服务端的反向代理nginx配置逻辑要一致,保证连接正常通信。

3. 基于websocket的长连接的通信,前端的业务层面的heartbeat心跳机制,是非常有用的,这个保证某个websocket后端服务出现异常的时候,客户可以无感知的继续得到服务。

websocket连接的后台反向代理问题的更多相关文章

  1. websocket使用nginx作为反向代理

    需要nginx作为websocket的反向代理,没有nginx反向代理时候没有问题,通过nginx反向代理后会报400错误,查后台调试信息: tornado.general – DEBUG – Can ...

  2. Nginx支持WebSocket反向代理-学习小结

    WebSocket是目前比较成熟的技术了,WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择.其为HTML5的一部分,WebSocket相较于原来开发这类app的 ...

  3. Nginx反向代理WebSocket(WSS)

    1. WebSocket协议 WebSocket 协议提供了一种创建支持客户端和服务端实时双向通信Web应用程序的方法.作为HTML5规范的一部分,WebSockets简化了开发Web实时通信程序的难 ...

  4. Nginx支持WebSocket反向代理

    WebSocket是目前比较成熟的技术了,WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择.其为HTML5的一部分,WebSocket相较于原来开发这类app的 ...

  5. 配置 Nginx 反向代理 WebSocket

    用Nginx给网站做反向代理和负载均衡是广泛使用的一种Web服务器部署技术.不仅能够保证后端服务器的隐蔽性,还可以提高网站部署灵活性. 今天我们来讲一下,如何用Nginx给WebSocket服务器实现 ...

  6. 负载均衡DNS和反向代理优缺点

    负载均衡 (Load Balancing) 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 负载均衡(又 ...

  7. nginx反向代理时保持长连接

    ·[场景描述] HTTP1.1之后,HTTP协议支持持久连接,也就是长连接,优点在于在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟. 如果我们使用了nginx去作为 ...

  8. Nginx配置WebSocket反向代理(Tomcat+Nginx)

    @toc WebSocket 和HTTP协议不同,但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade协议头将连接从HTTP升级到WebSocket.这使得WebSo ...

  9. 使用ssh正向连接、反向连接、做socks代理的方法

     ssh -L 219.143.16.157:58080:172.21.163.32:8080 用户名@localhost -p 10142  在 219.143.16.157机器执行   将ssh隧 ...

随机推荐

  1. HDU 6095 17多校5 Rikka with Competition(思维简单题)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  2. 中国网建提供的SMS短信发送

    一个简单的发送短信的小demo 第一步: 兄弟们,首先你们去中国网建的官网去注册一个账户:网址http://sms.webchinese.cn/reg.shtml 第二步: 注册完成之后会有免费的测试 ...

  3. m3u8编码视频webgl、threejs渲染视频纹理demo

    <!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>fz-live< ...

  4. 限定某个目录禁止解析php 、限制user_agent 、php的配制文件、PHP的动态扩展模块

    1. 限定某个目录禁止解析php(有些目录用户可以上传文件或图片,可能会被恶意者上传其它文件):编辑:/usr/local/apache2.4/conf/extra/httpd-vhosts.conf ...

  5. NET Core 实战 Dapper 扩展数据访问

    NET Core 实战:基于 Dapper 扩展你的数据访问方法 一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实 ...

  6. web四则混合运算3

    一.程序要求: 可以控制下列参数: 是否有乘除法: 是否有括号(最多可以支持十个数参与计算): 数值范围: 加减有无负数: 除法有无余数!   二.设计思路 要求能够通过参数来控制有无乘除法,加减有无 ...

  7. Version Control 版本控制

    一.version control是什么: version control版本控制,是指对软件开发过程中各种程序代码.配置文件及说明文档等文件变更的管理,是软件配置管理的核心思想之一. 二.versi ...

  8. php基础-2

    php的逻辑运算 &&符号 <?php function tarcrnum() { for ($i = 0; $i <= 100; $i++) { if ($i % 2 = ...

  9. c#接口与虚函数的实验报告

    1)定义Student类,用string型变量name存储学生姓名,用int型变量age存储学生年龄.Student类实现IComparable接口.要求从键盘输入学生的姓名和年龄,并注意可能出现的异 ...

  10. Mybatis(七)-- LRU LFU 算法

    这篇博客主要介绍LRU LFU 算法,因为在Mybatis的缓存中会用到,所以放到这个系列中了.此外,这是我翻译的一篇文章,觉得原文已经写的很好了,所以就直接翻译一下,留作知识整理. 英文原文出处如下 ...