用websocket搭個聊天室實時互動小遊戲,確實很是方便,但在線人數多了 就沒那麼簡單了。一到300人在線就開始掉了。後來通過調整 終於好多了。如下是改進的方案記錄:html
websoket.io Socket.IO 是一個功能很是強大的框架,可以幫助你構建基於 WebSocket 的跨瀏覽器的實時應用。支持主流瀏覽器,多種平臺,多種傳輸模式。
關於傳輸模式主要有兩種1.polly 輪詢模式, 2.websocket 模式。
默認爲先輪詢握手鍊接後再升級爲websocket。 輪詢的效率確定是低下的,修改配置參數直接用websokect 的方式傳輸。發現很效果差不少,滿意!node
var io = require('socket.io')({ "transports":['websocket', 'polling']})
判斷傳輸方式的源碼位置:nginx
https://github.com/socketio/e...git
能夠區分不一樣的命名空間來特定針對性的發消息,對於一些不是全局須要接受的消息就加上命名空間,能夠極大的節約資源的傳輸。github
//建立 server命名空間 var ServerIo = io.of('/server').on('connection', function(socket){ socket.on('ready',function(roomId,data) { pub.publish(roomId, JSON.stringify({ "event": 'ready', "data": '', "namespace" : '/user' })) }) socket.on('button-start',function(id){ pub.publish(id, JSON.stringify({ "event": 'button-start', "data": '', "namespace" : '/user' })); }) //針對namespace發送消息 io.of(namespace).emit('message', message)
經過nodeJS的process模塊,能夠實現多進程運行程序,最大限制的提升cpu的利用率。web
多進程啓動:redis
var fork = require('child_process').fork; var cupNum = require('os').cpus().length, workerArr = [], connectNum = 0 ; for (var i = 0; i < cupNum; i++) { workerArr.push(fork('./shake_server.js', [8000 + i])); process.on('uncaughtException', function(e) { console.log('捕獲到進程異常:',e); }); }
而後經過nginx作負載瀏覽器
upstream io_nodes { ip_hash; server 127.0.0.1:8000; server 127.0.0.1:8001; server 127.0.0.1:8003; server 127.0.0.1:8002; } server { listen 8080; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location /html { alias /Users/snail/Documents/myworks/weihuodong/shake; index index.html index.htm; } location / { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_http_version 1.1; proxy_pass http://io_nodes; proxy_redirect off; keepalive_timeout 300S }
1.修改系統參數:服務器
http.Agent
官網說明:
agent.maxSockets
By default set to 5. Determines how many concurrent sockets the agent can have open per host.
(爲了http請求能複用connection鏈接,Nodejs在http.Agent建立了一個默認大小爲5的鏈接池)
修改後以下:require("http").globalAgent.maxSockets = Infinity; 若是使用WebSocke.iowebsocket
2.ulimit 調整
若是出現自動掉線可調整nginx的各類timeout參數,有太多配置參數,具體根據須要去查文檔配置
如: keepalive_timeout 的調整,默認75秒
還能夠經過程序代碼判斷,掉線會觸發disconcent 事件,監聽它 自動再建立socket鏈接便可。
心跳檢查爲定時發送一次消息,保持鏈接狀態。
nodeJs的進程間通訊是沒問題的,但要共享數據仍是用redis來的簡單有效。
直接建立一個redisClient實例來用便可。
var client = redisClient(35050, '127.0.0.1') var redisObj = { get:function(id,cb){ client.hgetall(id, function (err, obj) { if(err){ console.log(err) }else{ cb(obj) } }) }, set:function(id,o){ if(typeof o === 'undefined' || typeof Object.keys(o)[0] == 'undefined'){ return } var key = Object.keys(o)[0] var value =JSON.stringify(o[key]) client.hset(id,key,value) }, del:function(id,uid){ if(id && uid){ client.hdel(id,uid) } }, flushdb:function(roomId){ client.del(roomId) } }
socket在各個進程間也是不共享的,那麼咱們能夠利用redis的訂閱發佈系統實現。
詳細看代碼註釋:
var redis = require("redis"); var sub = redis.createClient(35050, '127.0.0.1'), pub = redis.createClient(35050, '127.0.0.1'); var msg_count = 0; //訂閱事件的會時候觸發 subscribe ,回調包含兩個參數,分別爲訂閱的頻道和總訂閱數量 sub.on("subscribe", function (channel, count) { console.log('監聽到訂閱事件',channel, count) }); //在pub的時候會觸發 message事件,咱們的全部業務處理基本就是靠監聽它了,通知socket發佈消息 sub.on("message", function (channel, message) { console.log('監聽到發佈事件') console.log("sub channel " + channel + ": " + message); // socket.to(channel).emit('nice game', "let's play a game"); socket.of(channel).emit('message', message) msg_count += 1; if (msg_count === 3) { sub.unsubscribe() sub.quit() pub.quit(); } }); //添加三個訂閱 sub.subscribe("channel0"); sub.subscribe("channel1"); sub.subscribe("channel2"); //觸發頻道1的訂閱者 setInterval(function(){ pub.publish("channel1", "I am message to chanle1") },3e3) //觸發頻道2的訂閱者 setInterval(function(){ pub.publish("channel2", "I am message to chanle2") },3e3)
經測試一臺服務器一、2千用戶沒什麼壓力測試的話 用webSocket bench 很差用.(完)