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

英语小贴士

1、 Not yet. ——还没。 2、 See you. ——再见。 3、 Shut up! ——闭嘴! 4、 So long. ——再见。 5、 Why not? ——好呀! (为什么不呢?) 6、 Allow me. ——让我来。 7、 Be quiet! ——安静点! 8、 Cheer up! ——振作起来! 9、 Good job! ——做得好! 10、 Have fun! ——玩得开心!

作者:aehyok

出处:http://www.cnblogs.com/aehyok/

感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,那不妨点个推荐吧,谢谢支持:-O。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员互动联盟

【答疑解惑】如何知道要包含哪个头文件

之前遇到一个同学问一个问题,他在c源文件中使用bool变量,然后编译的时候提示bool没有定义。不知道怎么办。其实对于初学者来说,遇到的编译错误最多的就是某某变...

3087
来自专栏有趣的Python

慕课网-Linux C语言编程基本原理与实践-学习笔记

个人整理,学习自用。课程内容by慕课网。 Linux C语言编程基本原理与实践 高效的学习带着目的性: 是什么 -> 干什么 -> 怎么用 重识C语言 C语言是...

3366
来自专栏狮乐园

高级 Angular 组件模式 (3b)

Kent C. Dodds的第四篇文章中的一个重要元素在上一篇文章中没有涉及,使用withToggle高阶组件(HoC, react中的常用模式)可以将<tog...

1521
来自专栏Grace development

初中级PHP面试基础汇总

感觉现在发面试题有些冷门,就跟昨天德国那场似的,不过看看当提前复习了。提前备战。这2个月出门面试的童鞋可注意不要中暑哦。

2101
来自专栏Linux驱动

14.linux-platform机制实现驱动层分离(详解)

本节目标: 学习platform机制,如何实现驱动层分离 1.先来看看我们之前分析输入子系统的分层概念,如下图所示: ? 如上图所示,分层就是将一个复杂的工...

2585
来自专栏移动端开发

Socket学习总结系列(二) -- CocoaAsyncSocket

这是系列的第二篇 这是这个系列文章的第二篇,要是没有看第一篇的还是建议看看第一篇,以为这个是接着第一篇梳理的 先大概的总结一下在上篇的文章中说的些内容: 1、 ...

3047
来自专栏Jackson0714

不惧面试:HTTP协议(3) - Cookie

1322
来自专栏枕边书

请求合并哪家强

工作中,我们常见的请求模型都是请求-应答式,即一次请求中,服务给请求分配一个独立的线程,一块独立的内存空间,所有的操作都是独立的,包括资源和系统运算。我们也知道...

892
来自专栏Golang语言社区

从websocket看go的应用

Go是互联网时代的通用编程语言。这样它就和命令行时代的C语言、图示界面时代的C++、以及互联网早期的Java语言等有不同的侧重。它强调保持自身的精巧和独立,从而...

3737
来自专栏知无涯

【教程】快速入门,十天学会ASP

1.2K8

扫码关注云+社区