1.项目背景
前几天写了一篇WebSocket推送的博客:WebSocket :用WebSocket实现推送你必须考虑的几个问题 支持的连接数大概几千个,具体数量依赖于tomcat能并发的线程数,但很多时候生产环境应用的话几千个肯定是不行的,所以本问介绍Nginx+WebSocket的实现思路及代码.
2.实现思路
依照设计模式中的 迪米特法则 外部调用模块来讲要尽量少的参与推送模块的逻辑,以达到解耦的目的,所以我们虽然通过Nginx+WebSocket做了集群策略,但是不应该让外部感知.对于外部调用模块来讲你是否应用集群与我调用你无关.
大概实现思路是这样的,推送服务要把不是本机的请求内部路由到相应兄弟服务器.很多同学有疑问了为什么要路由呢,Nginx到任意一个节点处理不是就可以了. 大家注意哈,http实现了无状态请求,但是对于ws来讲tcp长连接显然是一个有状态请求,举个例子:server A连接client a,你想通过server B给client a发消息是做不到的,因为tcp连接在server A上.
设计图:
连接过程: 所有client连接地址均为Nginx地址,但是实际tcp连接是建立在具体服务器上的.连接完成后redis中要存储对应用户的serverId和SessionId(WsSession 是ws用来标识具体连接的).
发送消息过程:外部调用模块将消息发送到Nginx,假设发送消息的请求发送到了Server B上,那么Server B需要查出具体用户当前所连接的服务器,将请求路由转发到兄弟服务器上去.
3.源码地址
下载地址
http://download.csdn.net/download/shangmingtao/9920532
4.可优化的点
1.路由转发方式: 现在实现是用http转发的,效率很低,可以采用redis PUB/SUB方式 或者 rabbitMQ等.
2.路由转发内容: 我先再路由转发的是Client的userId+platform ,为的是能复用外部调用模块访问的接口.其实这里转发sessionId就可以了.
3.redis存储用户信息当前是序列化进去的.最好用hash这种数据类型.
5.Nginx配置及说明
user nobody;
worker_processes 1;
events {
worker_connections 8192; #这个要大一些
}
http {
upstream ws{
server 127.0.0.1:18080; server 127.0.0.1:28080; } server { listen 81; server_name localhost; # 动静分离处理 # location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css)$ { # root html; # } location ~/WSPush { proxy_pass http://ws; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host:$server_port; #这个用来透传用户http请求头的,因为我代码里调用了request.getServerName()方法,如果不加个配置,取出来是http://ws proxy_read_timeout 30m;#这里一定不要忘了改,默认1分钟后nginx会断开ws } } }
转自:http://m.blog.csdn.net/shangmingtao/article/details/76639821