經過監控線程狀態來保證socket服務器的穩定運行

雲平臺中使用的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服務器。

相關文章
相關標籤/搜索