前幾天寫了一篇WebSocket推送的博客:WebSocket :用WebSocket實現(xiàn)推送你必須考慮的幾個問題 支持的連接數(shù)大概幾千個,具體數(shù)量依賴于tomcat能并發(fā)的線程數(shù),但很多時候生產(chǎn)環(huán)境應用的話幾千個肯定是不行的,所以本問介紹Nginx+WebSocket的實現(xiàn)思路及代碼.
依照設計模式中的 迪米特法則 外部調(diào)用模塊來講要盡量少的參與推送模塊的邏輯,以達到解耦的目的,所以我們雖然通過Nginx+WebSocket做了集群策略,但是不應該讓外部感知.對于外部調(diào)用模塊來講你是否應用集群與我調(diào)用你無關.
大概實現(xiàn)思路是這樣的,推送服務要把不是本機的請求內(nèi)部路由到相應兄弟服務器.很多同學有疑問了為什么要路由呢,Nginx到任意一個節(jié)點處理不是就可以了. 大家注意哈,http實現(xiàn)了無狀態(tài)請求,但是對于ws來講tcp長連接顯然是一個有狀態(tài)請求,舉個例子:server A連接client a,你想通過server B給client a發(fā)消息是做不到的,因為tcp連接在server A上.
設計圖:
連接過程: 所有client連接地址均為Nginx地址,但是實際tcp連接是建立在具體服務器上的.連接完成后redis中要存儲對應用戶的serverId和SessionId(WsSession 是ws用來標識具體連接的).
發(fā)送消息過程:外部調(diào)用模塊將消息發(fā)送到Nginx,假設發(fā)送消息的請求發(fā)送到了Server B上,那么Server B需要查出具體用戶當前所連接的服務器,將請求路由轉(zhuǎn)發(fā)到兄弟服務器上去.
下載地址
http://download.csdn.net/download/shangmingtao/9920532
1.路由轉(zhuǎn)發(fā)方式: 現(xiàn)在實現(xiàn)是用http轉(zhuǎn)發(fā)的,效率很低,可以采用redis PUB/SUB方式 或者 rabbitMQ等.
2.路由轉(zhuǎn)發(fā)內(nèi)容: 我先再路由轉(zhuǎn)發(fā)的是Client的userId+platform ,為的是能復用外部調(diào)用模塊訪問的接口.其實這里轉(zhuǎn)發(fā)sessionId就可以了.
3.redis存儲用戶信息當前是序列化進去的.最好用hash這種數(shù)據(jù)類型.
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請求頭的,因為我代碼里調(diào)用了request.getServerName()方法,如果不加個配置,取出來是http://ws proxy_read_timeout 30m;#這里一定不要忘了改,默認1分鐘后nginx會斷開ws } }}