zoukankan      html  css  js  c++  java
  • 系统上线后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服务的处理是否还有其他方式,也让博客园的大牛们来指点一二吧。

  • 相关阅读:
    算法·进阶石
    How can I determine whether a 2D Point is within a Polygon?
    直线射线线段的相交判断
    关于时间的感想
    企业级自定义表单引擎解决方案(七)--视图模型管理
    GB28181安防Web无插件流媒体平台LiveGBS如何配置集群部署增加并发播放和录像
    接口测试之object []如何类型传参
    Excel2010工作簿被锁定,无法复制或者新增加sheet表格。
    drawio下载
    alsa-amixer-api
  • 原文地址:https://www.cnblogs.com/aehyok/p/3757664.html
Copyright © 2011-2022 走看看