系統上線后WCF服務最近經常死掉的原因分析總結


前言  

  最近系統上線完修改完各種bug之后,功能上還算是比較穩定,由於最近用戶數的增加,不知為何經常出現無法登錄、頁面出現錯誤等異常,后來發現是由於WCF服務時不時的就死掉了。后來就開始分析問題。得到的初步解決方案如下:

  1、在Web端調用WCF服務使用后,未釋放未關閉導致新的鏈接無法訪問

  2、增加默認的連接數,系統默認的鏈接數比較小

  3、提供同一個WCF服務的不同實例

1、在Web端調用WCF服務使用后,未釋放未關閉導致新的鏈接無法訪問  

首先保證客戶端每次建立的連接在使用完成后進行關閉。那么請不要使用傳統的using語句中來調用WCF,這里@dudu大神也曾經有遇到過這個問題 http://www.cnblogs.com/dudu/archive/2011/01/18/1938144.html。對其分析也比較全面,在此不再贅述。

不過自己感覺更好的處理方式可能是下面這樣,也就是將@dudu中的方法進行了簡單的封裝,但自己感覺還有優化的空間,暫時還沒試出來。

    public static class WcfExtensions
    {
        public static void Using<T>(this T client, Action<T> work)
            where T : ICommunicationObject
        {
            try
            {
                work(client);
                client.Close();
            }
            catch (CommunicationException e)
            {
                client.Abort();
            }
            catch (TimeoutException e)
            {
                client.Abort();
            }
            catch (Exception e)
            {
                client.Abort();
            }
        }
    }

進行調用看起來是如下的方式,看上去還是比較簡練了,但是感覺還是有些繁瑣,不知道能不能直接一行return代碼搞定?

        public static DocAppend GetDocAppend(string dwid, string actionId)
        {
            DocAppend docAppend = new DocAppend();
            new DocumentServiceV2.DocumentServiceV2Client().Using(channel => docAppend = channel.GetDocAppend(dwid, actionId));
            return docAppend;
        }

另外一種關閉鏈接的方式,這種方式其實和上面那種大同小異,也是可以封裝的,系統中暫且就使用的上面的方式。

            Document document = null;
            DocumentServiceClient client = new DocumentService.DocumentServiceClient();
            try
            {
                document= client.GetDocument(id);
                if (client.State != System.ServiceModel.CommunicationState.Faulted)
                {
                    client.Close();
                }
            }
            catch (Exception ex)
            {
                client.Abort();
            }
            return document;

 

2、增加默認的連接數,系統默認的鏈接數比較小  

如果采用的netTcp綁定,而在windows7中,並發連接數默認是10。

這是原來的配置文件

<binding name="netTcpBindConfig" closeTimeout="00:10:00" 
openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" 
transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" 
hostNameComparisonMode="StrongWildcard" listenBacklog="10" 
maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxConnections="10" 
maxReceivedMessageSize="2147483647"> 

將項目移植到服務器上之后

<binding name="netTcpBindConfig" closeTimeout="00:30:00" 
openTimeout="00:30:00" receiveTimeout="00:30:00" sendTimeout="00:30:00" 
transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" 
hostNameComparisonMode="StrongWildcard" listenBacklog="100" 
maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxConnections="100" 
maxReceivedMessageSize="2147483647"> 

但有些時候還是不能解決問題,就想到是不是需要配置一下行為,於是將行為的連接數量也改變了

      <serviceBehaviors>
        <behavior name="ThrottledBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
          <serviceThrottling maxConcurrentCalls="5000" maxConcurrentSessions="5000" maxConcurrentInstances="5000" />
        </behavior>
      </serviceBehaviors>

maxConcurrentCalls:在同一時刻允許處理的最大服務器操作數。如果超過次數,則需要把其他方法調用插入隊列中,以等待處理。

maxConcurrentSessions:同時傳輸或應用程序會話的最大個數。

maxConcurrentInstances:實例的最大個數。

增加連接數量

在Http協議中,規定了同個Http請求的並發連接數最大為2. 這個數值,可謂是太小了。而目前的瀏覽器,已基本不再遵循這個限制,但是Dot Net平台上的 System.Net 還是默認遵循了這個標准的。從而造成了,在使用HttpWebRequset 或者 WebClient 利用多線程的方式,訪問某個網站時,經常出現 連接被異常關閉 的錯誤,大大降低了效率。

這個限制的值,是可以自己設置或配置的。此值設置后,只對以后發起的HTTP請求有效。

  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="5000"/>
    </connectionManagement>
  </system.net>

 

3、提供同一個WCF服務的不同實例

3、首先查看一個WCF服務類

里面有N多構造函數的重載版本,我們來具體看一下第二個構造函數

        public DocumentWriteServiceClient(string endpointConfigurationName) : 
                base(endpointConfigurationName) {
        }

即傳入配置名生與代碼類的實例,我們在web.config中的wcf配置節,做如下處理:

      <endpoint address="http://localhost:8700/Design_Time_Addresses/SinoSZJS.WebWCF/DocumentWriteService/"
 binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICommonBinding"
 contract="DocumentWriteService.IDocumentWriteService" name="1">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
      <endpoint address="http://localhost:8700/Design_Time_Addresses/SinoSZJS.WebWCF/DocumentWriteService/"
 binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICommonBinding"
 contract="DocumentWriteService.IDocumentWriteService" name="2">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
      <endpoint address="http://localhost:8700/Design_Time_Addresses/SinoSZJS.WebWCF/DocumentWriteService/"
 binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICommonBinding"
 contract="DocumentWriteService.IDocumentWriteService" name="3">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>

修改客戶端的調用代碼

DocumentWriteServiceClient client = new DocumentWriteServiceClient();

改為

DocumentWriteServiceClient client = new DocumentWriteServiceClient(new Random().Next(1, 4).ToString());

即客戶端隨機從多個wcf服務端的host中挑一個,生成代碼類實例,說白了就是把一個wcf的host分身成了3個,並且客戶端隨機調用3者之一。

如果要考慮到大量並發的情況下,偽隨機數可能確實有一些問題,不過,這個應該也不難解決,自己另外寫一個類似偽隨機數的算法,只要保證生成指定范圍內不重復的數字(或字符)就可以了。

總結 

暫時這三種方式有效地防止了WCF服務的再次掛掉,至少最近幾天服務一直在穩定的運行,沒有太大的異常,很是讓人欣慰。不知道針對WCF服務的處理是否還有其他方式,也讓博客園的大牛們來指點一二吧。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM