目錄
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
}
}
}