雲平臺中使用的socket服務器是咱們本身定義一套通訊協議,並經過C#實現的一個socket服務。web
該服務目前是和web服務一塊兒運行在IIS容器中,經過啓動一個永不退出的新線程來監聽端口。數據庫
在開發的初期,因爲服務內一些消息的異常未進行捕獲,例如客戶端發來的消息格式不對、試圖去關閉一個已經被釋放的鏈接 等操做,會致使監聽線程意外退出。服務器
後來隨着系統的使用這些問題被一一修復,socket服務就穩定了不少,但是持續一個多周之後,socket服務仍是會偶爾掛掉,查看系統日誌沒有發現任何系統異常。到網上查了一些關於IIS的資料,發現IIS有一套智能的進程回收機制,目的是爲了提升服務器的性能,進程回收時內存中的session、cache以及正在運行的線程都會被清掉,因此採用IIS做爲服務器,要保證session、cache等資源長期可用的話,要把他們放到數據庫中,或者分佈式的放到其餘服務器中保存。進程回收後,IIS會啓動新的線程,原來部署在IIS中站點的端口都會被從新監聽,可是以前用戶本身啓動的那些線程IIS就不會給啓動了。session
網上有人給出一種解決方案,對IIS7進行配置:socket
回收——固定時間間隔(分鐘) 改成 0分佈式
——虛擬/專用內存限制(KB) 改成 0性能
進程模型——閒置超時(分鐘) 改成 0ui
這種方法會禁用IIS的進程回收,不過這樣可能會致使長時間運行後服務器的性能降低。並且,通過屢次嘗試這樣配置之後,通過很長時間的運行,IIS仍是會對進程進行回收的。spa
想到IIS在進程回收以後會重啓本身對運行在其上的站點的端口監聽,咱們本身也能夠運行一個服務,來判斷socket服務器的線程當前運行狀態是否正常,若是不正常的話就重啓服務。這個服務必須是運行在IIS以外的。線程
具體作法是:
web服務提供一個獲取進程狀態的接口
/SocketServer.ashx?action=getThreadStatus
提供一個重啓socket服務的接口
/SocketServer.ashx?action=startSocketServer
在IIS外部經過其餘方法啓動一個服務,每隔10秒訪問一次獲取進程狀態的接口,若是不正常則調用重啓socket服務的接口。
如今的作法是啓動了一個Nodejs服務:
//此服務用來監控雲平臺的socket服務進程,若進程崩潰或重啓,則從新啓動socket服務、ws服務、任務超時檢測 var http=require('http'); var moment = require('moment') //var host="http://xxx"; //本地調試 var host="http://xxxxxx"; //內網服務 //var host="http://xxxx";//公網服務 var statusCheck="xxx"; var startSocket= "xxx" ; var startWs= "xxx" ; var taskTimeout= "xxx"; var inteval; function start() { inteval = setInterval(checkStatus, 20000); } function end() { clearInterval(inteval); } start(); function checkStatus() { try { http.get(host + statusCheck, function (res) { res.on('data', function (data) { var socketStatus = JSON.parse(data.toString()); if (socketStatus.socketServer == '掛了' || socketStatus.socketServer == 'Stopped') { console.log(moment(new Date()).format('YYYY-MM-DD HH:mm:ss') + " socket服務不可用,正在重啓") //重啓服務 restartService(); } }) }).on('error', function (e) { console.log(moment(new Date()).format('YYYY-MM-DD HH:mm:ss') + "錯誤:" + e.message); }); } catch (e) { console.log(e.message); } } function restartService() { //end(); http.get(host + startSocket, function (res) { statusCode(res.statusCode, 'startSocket'); console.log(moment(new Date()).format('YYYY-MM-DD HH:mm:ss') + " 重啓socketserver" + res.statusCode); res.resume(); }); http.get(host + startWs, function (res) { statusCode(res.statusCode, 'startWs'); console.log(moment(new Date()).format('YYYY-MM-DD HH:mm:ss') + " 重啓wsserver" + res.statusCode); res.resume(); }); http.get(host + taskTimeout, function (res) { statusCode(res.statusCode, 'taskTimeout'); console.log(moment(new Date()).format('YYYY-MM-DD HH:mm:ss') + " 重啓任務狀態監控" + res.statusCode); res.resume(); }); var status = { startSocket: false, startWs: false, taskTimeout: false }; function statusCode(code, name) { if (code == 200) { status[name] = true; } if (status.startSocket && status.startWs && status.taskTimeout) { //start(); } } }
這種作法目前有兩個弊端:
1.每次IIS進程回收的時候,socket服務都會有幾秒鐘的時間不可用
2.socket服務運行在web服務器內,不利於之後web服務器或者socket服務器的擴展,鏈接到A服務器的設備沒法被B服務器訪問
之後的改進方向是:
把socket服務器獨立出來,從新設計Web服務器與socket服務器的通訊方法。
這樣可使socket服務不會受到IIS服務器配置的影響,並且能夠隨意擴展web服務器與socket服務器。