websocket连接的后台反向代理问题
今天要介绍的问题,是一个相对来说比较经典的问题,问题表面看不是很复杂的问题,但是反映出的背后通信逻辑,其实还是比较有意义的。
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连接的后台反向代理问题的更多相关文章
- websocket使用nginx作为反向代理
需要nginx作为websocket的反向代理,没有nginx反向代理时候没有问题,通过nginx反向代理后会报400错误,查后台调试信息: tornado.general – DEBUG – Can ...
- Nginx支持WebSocket反向代理-学习小结
WebSocket是目前比较成熟的技术了,WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择.其为HTML5的一部分,WebSocket相较于原来开发这类app的 ...
- Nginx反向代理WebSocket(WSS)
1. WebSocket协议 WebSocket 协议提供了一种创建支持客户端和服务端实时双向通信Web应用程序的方法.作为HTML5规范的一部分,WebSockets简化了开发Web实时通信程序的难 ...
- Nginx支持WebSocket反向代理
WebSocket是目前比较成熟的技术了,WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择.其为HTML5的一部分,WebSocket相较于原来开发这类app的 ...
- 配置 Nginx 反向代理 WebSocket
用Nginx给网站做反向代理和负载均衡是广泛使用的一种Web服务器部署技术.不仅能够保证后端服务器的隐蔽性,还可以提高网站部署灵活性. 今天我们来讲一下,如何用Nginx给WebSocket服务器实现 ...
- 负载均衡DNS和反向代理优缺点
负载均衡 (Load Balancing) 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 负载均衡(又 ...
- nginx反向代理时保持长连接
·[场景描述] HTTP1.1之后,HTTP协议支持持久连接,也就是长连接,优点在于在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟. 如果我们使用了nginx去作为 ...
- Nginx配置WebSocket反向代理(Tomcat+Nginx)
@toc WebSocket 和HTTP协议不同,但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade协议头将连接从HTTP升级到WebSocket.这使得WebSo ...
- 使用ssh正向连接、反向连接、做socks代理的方法
ssh -L 219.143.16.157:58080:172.21.163.32:8080 用户名@localhost -p 10142 在 219.143.16.157机器执行 将ssh隧 ...
随机推荐
- 下载从网页里面提取出来的图片(将url指向的图片下载并保存、从命名)
import os #创建文件夹 from urllib import request #下载图片 if not os.path.exists('文件夹名字'): #创建文件夹名字 os.mkdir( ...
- Java学习笔记31(IO:Properties类)
Properties类,表示一个持久的j集,可以存在流中,或者从流中加载 是Hashtable的子类 map集合的方法都能用 用途之一:在开发项目中,我们最后交给客户的是一个编译过的class文件,客 ...
- python 1-10考试
- Semaphore计数信号量
ExecutorService exec = Executors.newCachedThreadPool(); final Semaphore semp = new Semaphore(5); for ...
- [转]C++智能指针简单剖析
C++智能指针简单剖析 https://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看<C++ Primer Plus>第六版 ...
- 数据库和redis的一致性
之前的讲解,主要是在讲解redis如何支撑海量数据.高并发读写.高可用服务的架构 从这一讲开始,正式开始做业务系统的开发 商品详情页,缓存架构,90%是大量的业务(没有什么级数含量),10%最有级数含 ...
- asm磁盘组,asm磁盘状态学习
说明:在数据库中巡检,发现,数据库某个磁盘组状态为mount,其余磁盘组均为CONNECTED状态,排除是否异常 文档流程: 1.实际环境查询校验 2.官方文档视图中对磁盘组,磁盘状态的解释说明 3. ...
- Angular 插值字符串
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- angular的点击添加
首先是在js里面我们可以用clone来点击添加一些东西比如列表或者其他的div之类的,但是在angular里面怎么实现点击添加呢? 类似这种: 这样就尴尬了,最少我这样的菜鸟是不知道怎么去写的,网上好 ...
- YIT-CTF—Web
一:背后 打开传送门——>查看网页源代码——>1b0679be72ad976ad5d491ad57a5eec0——>用MD5解密 二:一种编码 [][(![]+[])[+[]]+([ ...