最近在调优SliverLightweb程序,两个下手点:wcf调用方式优化;iis并发访问优化
2013-06-06 14:21
423 查看
把同事总结的一份wcf调用方式记录下来,感谢同事的总结与分享
XXX系统的silverlight项目中,一般会出现当两个页面同时想wcf发送请求时(比如查询),数据会按照请求顺序一个一个返回,不管第二个请求查询数据有多快,也会等到第一个请求数据返回后才返回,影响了项目的性能。
经调查,这与wcf的并发和实例有关系,得到如下结论:
调查结果:如下
1. 为什么会出现请求按顺序返回结果的现象?
因为我们的项目用的wcf并发模式是个单线程的模式,即某时刻只能有一个线程调用服务实例,其余的线程处于等待队列中。但是当某线程回调客户端操作时,该线程就不再锁定该服务实例,等待队列中的下个线程将锁定服务实例进行调用。当回调客户端的线程执行完客户端调用后再回到服务端时,它将进入线程等待队列中重新排队等待。
通俗的讲:当客户端三次请求(A,B,C)到达服务端后,A请求将锁定服务实例,并调用服务,B请求和C请求将在等待队列中排队。在A请求处理过程中进行回调时,A请求会暂时释放对服务实例的锁定,此时队列中的B请求会锁定服务,进行调用。当B请求处理回调时,B请求也会暂时释入服务实例锁定,此时C请求会锁定服务进行调用......。当A回调结束后会重入服务实例,并在等待队列的尾部排队等待后续处理。
2. 如何解决这个现象?
经调查,发现WCF有两种控制并发的行为: InstanceContextMode 和 oncurrencyMode。
具体为:
InstanceContextMode服务行为用来控制实例而且可以设置成以下三种值:
Single. 服务类的一个实例处理所有接收到的请求。这实现了一个单例。
PerCall. 为每个接收到的请求创建一个服务类的实例。
PerSession. 每个客户端会话创建一个服务类实例。当使用不支持会话的信道时,所有的服务调用与PerCall一样,即便是InstanceContextMode被设置成PerSession.。
ConcurrencyMode服务行为用来控制一个服务实例内部的线程并发。默认设置,ConcurrencyMode.Single,指导WCF在某一时刻旨在服务类的实例中执行一个线程。这个行为可以被设置成三个值之一:
Single. 在一个时刻只有一个线程可以访问服务类。这是最安全的设置因为服务操作不必担心线程安全。
Reentrant. 在一个时刻仅有一个线程可以访问服务类,但是这个线程可以离开类并在稍后返回继续。
Multiple. 多个线程可以同步访问服务类。这个设置要求类创建在线程安全基础上。
默认的情况下是,两者的行为的默认选择分别是:PerSession和Single,这样就形成了“请求-响应”的调用模式,造成数据阻塞,所以我们修改这两个行为相互配合:
从图中可以看出:当InstanceContextMode设成PerCall时,可以解决问题,但每次请求都实例化服务,影响性能。
当InstanceContextMode设成PerSession时,按项目中basicHttpBinding的使用,应该会降级成PerCall,但没有PerCall的效果。
当ConcurrencyMode设成Multiple时,服务器用多线程处理请求,可以解决问题,但要做好代码的线程保护。
推荐: ConcurrencyMode用Multiple,InstanceContextMode用Single
3. 使用方式
在服务的类前写如上的行为契约。
4. 总结
使用推荐的行为方式可以解决请求阻塞的问题,但经测试当客户端向服务发两个或多个并发请求时,响应时间或多或少都会受到影响,增加了查询时间,不可避免的发生了。
XXX系统的silverlight项目中,一般会出现当两个页面同时想wcf发送请求时(比如查询),数据会按照请求顺序一个一个返回,不管第二个请求查询数据有多快,也会等到第一个请求数据返回后才返回,影响了项目的性能。
经调查,这与wcf的并发和实例有关系,得到如下结论:
调查结果:如下
1. 为什么会出现请求按顺序返回结果的现象?
因为我们的项目用的wcf并发模式是个单线程的模式,即某时刻只能有一个线程调用服务实例,其余的线程处于等待队列中。但是当某线程回调客户端操作时,该线程就不再锁定该服务实例,等待队列中的下个线程将锁定服务实例进行调用。当回调客户端的线程执行完客户端调用后再回到服务端时,它将进入线程等待队列中重新排队等待。
通俗的讲:当客户端三次请求(A,B,C)到达服务端后,A请求将锁定服务实例,并调用服务,B请求和C请求将在等待队列中排队。在A请求处理过程中进行回调时,A请求会暂时释放对服务实例的锁定,此时队列中的B请求会锁定服务,进行调用。当B请求处理回调时,B请求也会暂时释入服务实例锁定,此时C请求会锁定服务进行调用......。当A回调结束后会重入服务实例,并在等待队列的尾部排队等待后续处理。
2. 如何解决这个现象?
经调查,发现WCF有两种控制并发的行为: InstanceContextMode 和 oncurrencyMode。
具体为:
InstanceContextMode服务行为用来控制实例而且可以设置成以下三种值:
Single. 服务类的一个实例处理所有接收到的请求。这实现了一个单例。
PerCall. 为每个接收到的请求创建一个服务类的实例。
PerSession. 每个客户端会话创建一个服务类实例。当使用不支持会话的信道时,所有的服务调用与PerCall一样,即便是InstanceContextMode被设置成PerSession.。
ConcurrencyMode服务行为用来控制一个服务实例内部的线程并发。默认设置,ConcurrencyMode.Single,指导WCF在某一时刻旨在服务类的实例中执行一个线程。这个行为可以被设置成三个值之一:
Single. 在一个时刻只有一个线程可以访问服务类。这是最安全的设置因为服务操作不必担心线程安全。
Reentrant. 在一个时刻仅有一个线程可以访问服务类,但是这个线程可以离开类并在稍后返回继续。
Multiple. 多个线程可以同步访问服务类。这个设置要求类创建在线程安全基础上。
默认的情况下是,两者的行为的默认选择分别是:PerSession和Single,这样就形成了“请求-响应”的调用模式,造成数据阻塞,所以我们修改这两个行为相互配合:
InstanceContextMode ConcurrencyMode | Single | PerCall | PerSession |
Single默认 | 服务是单例:一个实例被创建来处理请求,当一个请求呗处理时,所有的顺序请求被加入队列并按照fifo(先进先出)处理。 属于最基本的wcf请求模式,不能解决问题 | 每次调用都创建一个实例。并发请求没有影响,因为每个实例都有它自己线程来执行。 优点可以解决问题,但每次请求都创建一个实例,相当于new一个服务对象,如果服务的构造函数有数据加载或复杂操作,会影响性能 | 每个客户端会话创建一个实例,而且仅有一个线程被创建来处理那个会话的请求,如果客户端再一次会话上使用多个异步调用,它们会被放入列并按照(fifo)顺序处理。 通俗理解就是多次请求,请求还是会阻塞,是项目使用的默认模式,不能解决问题。但这是针对会话来说,项目中使用的basicHttpBinding不支持会话,会降级为PerCall,和PerCall行为一样 |
Reentrant | 服务是单例:一个实例被创建而且仅有一个现成被创建来处理请求,当一个请求被处理后,所有的请求按顺序被放入队列中并按照fifo顺序处理。 感觉这个跟ConcurrencyMode的single是一样的,不能解决问题 | 每次调用都创建一个实例。并发请求没有影响,因为每个实例都有它自己线程来执行。 优点可以解决问题,但每次请求都创建一个实例,相当于new一个服务对象,如果服务的构造函数有数据加载或复杂操作,会影响性能 同上。 | 每个客户端会话创建一个实例,而且仅有一个线程被创建来处理那个会话的请求,如果客户端再一次会话上使用多次异步调用,它们会被放入列并按照(fifo)顺序处理。单个线程可以离开这个方法,做其他工作,稍后返回,就像服务端异步编码。 通俗理解就是多次请求,请求还是会阻塞,不能解决问题,即使服务端有异步编码,但还是一个线程处理。并且这是针对会话来说,项目中使用的basicHttpBinding不支持会话,会降级为PerCall,和PerCall行为一样 |
Multiple | 一个实例被创建但是多个线程可以再这个实例中并行执行。类的成员必须用同步代码保护,应为同样的成员可以被多个线程修改。 这个可以解决问题,并且是这几种配合中感觉比较好的但会遇到多线程的通病,需要做类成员保护,在项目中这点修改的点可能会多。 | 每次调用都创建一个实例。并发请求没有影响,因为每个实例都有它自己线程来执行。 优点可以解决问题,但每次请求都创建一个实例,相当于new一个服务对象,如果服务的构造函数有数据加载或复杂操作,会影响性能 同上。 | 每个客户端会话创建一个实例,有多个线程可以再实例中并发执行。如果客户端在一个会话总进行多次异步调用,它们是并行的,不会影响。类的成员必须用同步代码保护,因为同样的成员可以被多个线程修改。 这个是可以解决问题的,同Single差不多,但需要做类成员保护。并且这是针对会话来说,项目中使用的basicHttpBinding不支持会话,会降级为PerCall,和PerCall行为一样 |
当InstanceContextMode设成PerSession时,按项目中basicHttpBinding的使用,应该会降级成PerCall,但没有PerCall的效果。
当ConcurrencyMode设成Multiple时,服务器用多线程处理请求,可以解决问题,但要做好代码的线程保护。
推荐: ConcurrencyMode用Multiple,InstanceContextMode用Single
3. 使用方式
在服务的类前写如上的行为契约。
4. 总结
使用推荐的行为方式可以解决请求阻塞的问题,但经测试当客户端向服务发两个或多个并发请求时,响应时间或多或少都会受到影响,增加了查询时间,不可避免的发生了。
相关文章推荐
- 发布Silverlight+WCF程序到IIS后,客户端访问数据库失败的解决方案
- 在IIS7.5中ASP.NET调用cmd程序拒绝访问决绝方法小记
- iOS-90-调用后台接口(WCF,soap访问方式,接口后缀.svc形式),使用WSDL2objc工具才能搞定
- (转)发布Silverlight+WCF程序到IIS后,客户端访问数据库失败的解决方案
- 调用部署在本机IIS服务器的WCF服务并返回数据DataTable,一直报错:远程主机强迫关闭了一个现有的连接,但是服务访问正常
- 发布Silverlight+WCF程序到IIS后,客户端访问数据库失败的解决方案
- 在IIS7.5中ASP.NET调用cmd程序拒绝访问决绝方法小记
- IIS Host 的WCF大数据量大并发调用的时候IIS返回403错误
- wcf数据访问采用集成验证方式导致客户端调用失败的解决方案(IIS7寄宿wcf)
- 您可能无法使用服务器管理器,如果两个线程同时访问 IIS 管理 IIS 的修补程序
- 自己在之前做两个项目中遇到多线程并发访问如何解决的一个简单demo程序
- BizTalk Orchestration Publish Host In-Process Wcf Service without IIS 多种供客户端调用方式
- 在IIS7.5中ASP.NET调用cmd程序拒绝访问决绝方法小记
- BizTalk Orchestration Publish Host In-Process Wcf Service without IIS 多种供客户端调用方式
- WCF服务以控制台程序为宿主时的跨域访问问题(附源码)
- Java程序性能优化 读书笔记(十六)集合访问优化
- iis无法启动 “另一个程序正在使用此文件,进程无法访问”
- 内存分配的原理__进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。
- 2018/01/08JAVA 基础 / 接口与继承:调用父类/子类的类方法、对象方法,访问父类的类属性、对象属性的方式汇总
- java程序通过密钥方式使用JSch API访问SSH(转帖)