第十五讲 实例模式
代码
https://yunpan.cn/cPns5DkGnRGNs 密码:3913
不是特殊的Demo,我们不再贴实例Demo的图片了,直接去网盘找相应的项目看
对并发服务调用请求的处理是WCF最基本要求,为了提供服务的响应能力,WCF会在不同的线程中处理并发请求。在单例模式下,服务实例是唯一的,也就是说相同的服务实例会同时被多个线程并发地访问。在默认的情况下,多个线程以同步的方式访问单例服务对象,也就是说,在某个时刻,最多只会有一个线程在使用服务实例。如果一个服务操作需要1秒,那么在一分钟内最多只能处理60个服务调用请求。倘若客户端采用默认的超时时限(1分钟),对于60个并发地服务调用请求,至少会有一个服务调用会失败。这极大地降低了WCF服务的可扩展性、响应能力和可用性。
Demo:提供一个相同的功能,采用单调模式和单例模式,对客户端影响的差别。Add方法中通过使用线程休眠5秒模拟一个耗时的服务操作。在云盘 ( 1.单例2 )
服务契约的实现:
1 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 2 //[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 3 //[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] 4 public class Services : ICalculator 5 { 6 public double Add(double x, double y) 7 { 8 Thread.Sleep(5000); 9 return x + y; 10 } 11 }
客户端:
1 static void Main(string[] args) 2 { 3 //通过ThreadPool模式5个并发的客户端,在ADD操作调用成功后输出 4 //当前的时间,从而校验服务的影响力. 5 for (int i = 0; i < 5; i++) 6 { 7 ThreadPool.QueueUserWorkItem(delegate 8 { 9 using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorservice")) 10 { 11 ICalculator calculator = channelFactory.CreateChannel(); 12 Console.WriteLine("{3}:x+y={2} when x={0} and y={1}", 1, 2, calculator.Add(1, 2), DateTime.Now); 13 } 14 }); 15 } 16 Console.Read(); 17 }
首先我们先使用 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 单调模式
看我们的执行结果:
[ 15-01 ]
结果是一下子全部出现运算结果,表示真正使用了多线程。
接着使用第二种模式 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 单例模式
运行结果:
[ 15-02 ]
每个运算结果都是 过5秒钟 后 运算完成一个,仔细看 时间间隔,都是5秒钟。
最后使用 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] 单例 且 多线程
运行结果:
[ 15-03 ]
与第一种一样的结果。
总结:
在使用PerCall模式下,对于5个并发的服务调用均得到了及时的相应,这是我们希望看到的结果。
在使用Single,情况就完全不一样了。从最终的结果可以看出,客户端得到执行结果的间隔为5s。WCF通过并发模式表示多线程访问单例服务对象的方式,而并发模式作为一种服务可以通过ServiceBehaviorAttribute特性进行设定。WCF通过ConcurrencyMode枚举来表示不同形式的并发模式,三个枚举值Single,Reentrant和Multiple分别表示单线程,重入和多线程三种并发模式。ConcurrencyMode.Single是默认采用的并发模式,这正是上面的例子中服务操作同步执行的根本原因。为了让服务操作异步的执行,以提供服务的响应能力,我们只需要通过ServiceBehaviorAttribute将并发模式设为ConcurrencyMode.Multiple就可以了。
会话(Session)与会话(Per-Session)实例上下文模式:
从状态保持来看,会话的目的在于保持调用某个WCF服务的同一个客户端多次服务调用的状态;从消息交换来看,会话则是关联来自相同客户端所有请求消息的一种消息识别机制。
WCF会话简介
在基于ASP.NET的WEB应用中,基于客户端的会话状态被保存在服务端,可根据不同的需要选择保存在WEB服务器内存中,可以是状态服务器或SQLSERVER中。Asp.net为每一个会话分配一个具有唯一性的SessionID.对于每次HTTP请求,SessionID通过Cookie或URL的形式发送到WEB服务器,ASP.NET借助于SessionID获得客户端相应的会话状态。
WCF与ASP.NET的会话,在实现方式上各有不同,但是最终的目的都是一样的:保持同一个客户端多次请求的状态。 不过ASP.NET应用的客户端指的用户访问WEB应用的浏览器,而WCF应用的客户端则代表用于服务调用的服务代理对象。
WCF会话模式的实现依赖于两个方面:会话信道栈与基于会话的服务实例模式。前者通过一个会话信道关联从相同客户端发送的所有消息,后者通过建立基于会话的服务实例上下文保持会话状态。
所以WCF基于会话的编程围绕着这两个方面,基于会话的WCF编程,需要考虑以下3个状态:
1:会话模式:通过在服务契约中定义不同的会话模式 允许,强制或禁止会话.
2:支持会话的绑定:支持会话的绑定才能创建支持会话的信道栈.
3:会话实例上下文模式:这是一种位于单调和单例之间的第三种实例上下文模式,该模式采用基于会话或服务代理服务实例上下文的创建和生命周期的管理。
会话模式定义在服务契约中,通过ServiceContractAttribute特性的SessionMode属性定义。定义在SessionMode的3个枚举值分别对应3种不同的会话模式:Allowed,Reqired和NotAllowed。
1.Allowed:允许会话,对会话的具体支持依赖于绑定对会话的支持。
2.Required:强制服务契约提供对会话的支持,如果绑定不支持会话,抛出异常。
3.NotAllowed:禁止会话。
默认使用的会话模式为SessionMode.Allowed,所以以下两种服务契约的定义方式是等效的:
1 [ServiceContract(Namespace = "http://www.HulkXu.com/", SessionMode = SessionMode.Allowed)] 2 public interface ICalculator 3 { 4 }
1 [ServiceContract(Namespace = "http://www.HulkXu.com/")] 2 public interface ICalculator 3 { 4 }
在进行基于会话服务调用中,会话开始于基于对应服务代理的第一次服务调用,或者通过Open方法人为开启服务代理。而当我们调用Close方法关闭服务代理的时候,也意味着 会话结束。
在服务端和客户端建立一致性的会话信道是现实会话的基本前提,WCF会话的实现要求创建信道的绑定具有支持会话的能力。不同的传输协议的绑定类型,按照不同方式实现对会话的支持。
对于会话不同的是实现方式,大体可以将其分为两种类型:
1:传输层会话:完全通过基于连接的传输层实现会话,比如基于TCP协议的NetTcpBinding。
2:模拟传输层会话:对于无连接,无状态的HTTP协议,传输层本身并不能提供会话的支持,只能通过在消息报头加上额外的信息(SessionID)实现对客户端的识别。BasicHttpBinding不能提供对会话的支持。
如果在服务契约中显示地强制了不支持会话的协议,不论是对于服务寄宿,还是服务调用,如果使用的绑定不支持会话,都会抛出异常。
相反的,通过在服务契约定义中显示地禁止会话,对于基于传输层会话实现的绑定类型,比如NetTcpBinding,无论是进行服务寄宿还是服务调用,都会抛出异常。(这个意思就是 NetTcpBinding本身是支持会话的,但在服务契约实现 时 禁用了 会话,那么在服务器寄宿或者调用过程中都会报错的 )
应用场景
因此,会话实例上下文模式仅仅适合一些客户端数量很少的应用,并且在确定不使用服务代理的时候,应该显示地将它们关闭.
服务实例的释放
可通过在服务的操作方法上应用OperationBehaviorAttribute特性设置相应的实例释放模式,使实例在该操作方法执行之前或之后释放。实例释放模式通过System.ServiceMode。ReleaseInstanceMode枚举表示。ReleaseInstanceMode中的3个枚举值BeforeCall,AfterCall,BeforeAndAfterCall表示现有的服务实例将在相应的操作执行之前,之后及前后被释放。默认值为ReleaseInstanceMode.None,这 意味着不会执行基于该操作的实例释放操作。在下面的代码中,在Add方法中,通过OperationBehaviorAttribute特性将实例释放模式设置为ReleaseInstanceMode.BeforeAndAfterCall,表明对于Add操作,WCF运行时每次都会为其创建新的服务实例,并且该服务实例在完成该操作后会马上被释放。
例子:
1 [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] 2 public class CalculatorService:ICalculator 3 { 4 [OperationBehavior(ReleaseInstanceMode=ReleaseInstanceMode.BeforeAndAfterCall)] 5 public double Add(double x,double y) 6 { 7 return x+y; 8 } 9 }
并发
在上一个Demo中我们采用单例模式,默认为并发,每5秒执行一次的这个Demo。最后解决是 多线程的并发模式。
那么我们现在详细的去看下这个并发。
在运行时,如果多个线程试图访问相同的资源,就会出现并发问题。当请求到达一个服务时,该服务模型会从线程池中取出一个线程来传送消息。当然,如果多个客户端调用相同的服务,多个并发请求会同时到达该服务。特定服务对象处理每个请求时,是基于服务的实例化模式的。PerCall(单调)会为每一个请求分配一个新的服务对象。对于PerSession服务,同一个服务对象从同一个客户端接收请求。对于Single实例模式,所有的客户端请求都被发送到同一个单例服务对象。在此基础上,当客户端是多线程时的时候,PerSession服务就有并发访问的可能,而对于Single服务,该危险是永远存在的。
默认情况下,无论其实例化是何种模式,只有一个请求线程可以获准访问所有服务对象。
服务的并发设置是ServiceBehaviorAttribute的ConcurrencyMode属性。默认值设置是Single。
这个属性可以设置为下列ConcurrencyMode枚举的任意值:
1.Single:一个单一的请求线程能够在某一个特定的时间访问这些服务对象。
2.Reentrant:一个单一的请求线程能够访问这些服务对象,单线程可以退出这项服务,并重新输入而不会死锁。
3.Multiple:多个请求线程能够访问这些服务对象和共享资源,但是必须手动保护以免并发访问。
单并发模式Single
当服务被设置为Single并发模式,请求被服务对象处理时,该对象会获得一个锁。而其他对同一个对象的调用会按照服务接收的顺序被放入到队列中,以免发生客户端发送会话超时,或者服务器会话超时的情况。当拥有锁的请求完成时就会释放锁,队列中的下个
请求就会获取锁并开始处理。这种设置减少了当存在会话或单例时服务可能的吞吐量(单位时间内WCF能够处理的请求的数量),但它也将并发问题的风险降到最小。
采用Single并发模式来限制并发访问对于吞吐量来说往往是一个折中方案,对于PerCall服务,却并非如此,因为会为每个请求分配分配一项新的服务,对于PerSession服务,
Single并发不允许从同一客户端的多重并发调用,以免影响多个客户端的吞吐量。对于Single实例模式,在所有的客户端之间,只能处理一个请求。
虽然Single并发模式是保护共享资源最安全和最简单的方法,而且这些资源可能来自于会话中的所有单例服务多线程客户端,但是有时重入和增加吞吐量的措施也是必要的,这就需要更高级的多线程技术。
Single并发与PerCall:
场景模拟:
在同一时间内 A客户端发送两次请求 B客户端也发送2次请求。那么将服务端将为这四次请求创建四个对象进行处理。
所以 对于PerCall服务,每个线程都将分配新的服务实例。不会产生并发性问题。
Single模式在这里也不会对吞吐量产生影响
可以处理并发问题。
[ 15-04 ]
Single并发与Perssion:
场景模拟:
在同一时间内 A客户端发送两次请求 B客户端也发送2次请求。那么将服务端将为这两个客户端创建两个对象且分别并发式处理请求。(也就是说A客户端的第一个请求处理完了才可以处理第一个客户端的第二个请求。第二个客户端发送的两次请求同理)
所以 对于PerSession服务,保护服务实例不会受到多线程客户端的影响。
Single模式会对单一客户端的吞吐量产生影响
可以处理并发访问。
[ 15-05 ]
Single并发与单例(Single)模式:
场景模拟:
在同一时间内 A客户端发送两次请求 B客户端也发送2次请求。那么将服务端将为这两个客户四个请求创建唯一的一个对象并发式处理请求。(也就是说一次只能处理一个请求,不管是来此A客户端的请求还是B客户端的请求)
所以 对于单例服务,保护服务实例不会受到任何并发访问的影响。
Single模式会对单例的吞吐量产生影响。
多线程和多客户端无法同时访问限制并发访问的处理。
[ 15-06 ]
Reentrant并发模式:
是可重入的单线程模式。
解释 单线程 与 可重入
单线程:只能有一个线程进入服务实例进行操作。
可重入:当客户端A去调用服务WCF-Service1,然后WCF-Service1回调客户端A,最后客户端A将信息送回WCF-Service1,最后一次( 客户端A将信息送回WCF-Service1 )称为可重入的。
[ 15-07 ]
对比Single是不可重入的,因为WCF对它进行加锁了。
Reentrant保证了只有一个线程对服务进行处理。在处理的过程中,仍然会对这个服务进行加锁的处理。后续的请求必须排队。当这个请求处理以后,这个锁被解开,让其它的请求进行处理。回调的请求会排列到这个队列的尾部等待它前面的请求处理完以后,再进行处理。所以说,Reentrant应用的场景主要用于当服务发起回调到客户端的场景。也就是说当回调操作不是one-way操作时。
举个小例子:
一匹狼吃肉。当它吃到一半的时候,想起一件事,比方说通知它的伙伴也来吃肉。然后它回来以后可以继续吃肉,但是必须要排队。必须要保证只有一匹狼吃肉。
Multiple并发模式:
Multiple并发模式可以增加吞吐量:带有多线程客户端的PerSession服务处理大量客户端的Singleton服务。
当服务实例处理请求时,系统不会自动加锁。多线程同时访问服务实例一定要注意:
1.共享资源必须得到保护
2.需要自定义实现多线程保护
为了提高PerSession和Single实例模式的吞吐量,可以允许多个线程使用一个共享的服务实例。在这种情况下,服务实例没有请求锁,而所有共享的状态和资源,必须用手工同步技术加以保护。
那说到了必须保护共享资源,也顺便提一下 .NET同步技术
有很多方法来实现定制同步,包括Monitor,Mutex,Semaphore,ReadWriterLock、Interlocked操作等。也有一些.NET的属性,可以用来同步对一个类型的访问。在这里我们简要概述一下一些多线程的技术。
使用Monitor,能获得对象实例的一个全局锁,此时使用Enter()和Exit()方法。
如下所示:
1 try 2 { 3 //访问共享资源
4 Monitor.Enter(this);
5 }
6 finally
7 {
8 Monitor.Exit(this);
9 }
事实上,对lock()声明进行编译,可以得到同样的结果:
1 lock(this) 2 { 3 4 //访问共享成员 5 6 }
这里我们 运行一下 本节课的 第二个Demo ( 2.并发 Concurrency ) ,看我们模拟客户端的多个并发请求。 云盘中有此Demo
看服务契约:
1 [ServiceContract(Namespace = "http://www.HulkXu.com/samples/2006/06")] 2 public interface IMessagingService 3 { 4 [OperationContract(IsOneWay = true)] 5 void SendMessage1(string message); 6 7 [OperationContract(IsOneWay = true)] 8 void SendMessage2(string message); 9 10 [OperationContract(IsOneWay = true)] 11 void SendMessage3(string message); 12 }
服务契约的实现:
1 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] 2 public class MessagingService : IMessagingService 3 { 4 5 int m_messageCounter; 6 7 Dictionary<int, string> m_messages = new Dictionary<int, string>(); 8 9 #region IMessagingService Members 10 11 public void SendMessage1(string message) 12 { 13 m_messages.Add(m_messageCounter, message); 14 Trace.WriteLine(string.Format("Message {0}: {1}", m_messageCounter, message)); 15 m_messageCounter++; 16 } 17 18 public void SendMessage2(string message) 19 { 20 lock (this) 21 { 22 m_messages.Add(m_messageCounter, message); 23 Trace.WriteLine(string.Format("Message {0}: {1}", m_messageCounter, message)); 24 m_messageCounter++; 25 } 26 } 27 28 public void SendMessage3(string message) 29 { 30 m_messages.Add(m_messageCounter, message); 31 Trace.WriteLine(string.Format("Message {0}: {1}", m_messageCounter, message)); 32 m_messageCounter++; 33 } 34 35 36 #endregion 37 }
上面,我们先测试 单例实例上下文模式 且为 多线程模式 ( [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] )
服务器寄宿代码就不写了,都一样。
然后再看 客户端代码 (WinFrom):
1 public partial class Form1 : Form 2 { 3 public Form1() 4 { 5 InitializeComponent(); 6 } 7 8 /// <summary> 9 /// 服务代理 10 /// </summary> 11 MessagingServiceClient.MessagingServiceClient proxy = new Client.MessagingServiceClient.MessagingServiceClient(); 12 13 private void button1_Click(object sender, EventArgs e) 14 { 15 for (int i = 0; i < 200; i++) 16 { 17 proxy.BeginSendMessage1("SendMessage1()", null, null); 18 Application.DoEvents(); 19 } 20 } 21 22 private void button2_Click(object sender, EventArgs e) 23 { 24 for (int i = 0; i < 200; i++) 25 { 26 proxy.BeginSendMessage2("SendMessage2()", null, null); 27 Application.DoEvents(); 28 } 29 } 30 31 private void button3_Click(object sender, EventArgs e) 32 { 33 for (int i = 0; i < 200; i++) 34 { 35 proxy.BeginSendMessage3("SendMessage3()", null, null); 36 Application.DoEvents(); 37 } 38 } 39 40 private void Form1_FormClosed(object sender, FormClosedEventArgs e) 41 { 42 proxy.Close(); 43 } 44 45 46 47 }
好了,我们进行测试,首先启动寄宿,然后启动客户端,结果如下:
点击第一个按钮:
[ 15-08 ]
异常信息:
“System.ArgumentException”类型的异常在 mscorlib.dll 中发生,但未在用户代码中进行处理
其他信息: 已添加了具有相同键的项。
客户端发送了多个请求,服务端虽然是 单例实例上下文模式 ( InstanceContextMode = InstanceContextMode.Single ) 但是设置了 多线程模式 ( ConcurrencyMode = ConcurrencyMode.Multiple ),也就是说不存在排队的情况了,所有的请求几乎同时执行,在第一条记录还没有执行到 m_messageCounter++ 这行的代码时,第二条记录也开始向 Dictionary 字典集合中 追加 Key 等于 0 的记录,那么一定会报 “ 已添加了具有相同键的项 ”这个错误。
我们再测试第二个按钮:
再第二个按钮所访问的服务里,我们加上了 锁 的机制:
[ 15-09 ]
很顺利的将所有客户端发过来的信息 打印在 输出 控制台
所以 上面提到的,再次强调下 :
1.共享资源必须得到保护
2.需要自定义实现多线程保护
还有其它的模式,自己修改下 服务实例上下文模式 和 并发的模式 自己测试下。
下面我总结一下 上面 实例模式 内容的 一个 思维图
[ 15-10 ]
实例化分流:
为了增加服务的吞吐量,必须允许进行多重并发调用.PerCall服务默认有多重并发调用的能力,因为每个调用都被分配自己的服务实例。PerSession服务也允许从唯一客户端增加吞吐量,但是一次仅允许一个来自同一客户端会话的请求。Single实例模式默认情况下一次只允许处理一个请求,无论客户端怎样,这都会影响吞吐量。为了增加多线程会话和单例服务的吞吐量,你可以设置并发模式为Multiple,并提供相应的同步机制。
不管是何种并发请求,服务器资源一般没有处理无限数量的并发请求的能力。每项请求可能需要一定数量的进程、内存分配、硬盘和网络访问,以及其它开销。会话也要求资源分配,就像对单例一样,通常要能经受得住独立的请求。WCF提供了一个分流行为来管
理服务负载和资源消耗。
该行为具有下列属性:
1.MaxConcurrentCalls:这个属性限制服务实例可以处理的所有并发请求的数量,默认值为16。
2.MaxConcurrentInstances:这个属性限制了某一特定的时刻可以分配的服务实例的数量。对于PerCall服务,此设置与并发调用的数目一致。对于PerSession服务,此设置与活动的会话实例的数目一致。此设置不影响Single实例模式,因为此时只创建了一个实例。这个属性的默认值为2147483647
3.MaxConcurrentSessions:这个属性限制服务允许的活动会话的数量,包括应用会话、传送会话、可靠会话,以及安全会话,默认值是10。
上述设置是被应用于某一特定ServiceHost实例的,并与所有服务终端相关联。为了显式设置这些值,你需要关联一个服务行为,并添加<serviceThrottling>节点,默认分流值的服务行为如:
<serviceThrottling maxConcurrentCalls="16" maxConcurrentInstances="2147483647" maxConcurrentSessions="10"/>
1 <system.serviceModel> 2 <services> 3 <service name="Counters.CounterService" behaviorConfiguration="serviceBehavior"> 4 <endpoint address="CounterService" binding="basicHttpBinding" contract="Counters.ICounterService"/> 5 </service> 6 </services> 7 <behaviors> 8 <serviceBehaviors> 9 <behavior name="serviceBehavior"> 10 <serviceThrottling maxConcurrentCalls="16" maxConcurrentInstances="2147483647" maxConcurrentSessions="10"/> 11 </behavior> 12 </serviceBehaviors> 13 </behaviors> 14 </system.serviceModel>
为了在程序中配置该行为,你可以在运行期间为服务描述添加一个ServiceThrottle行为。请记住,如果已提供了设置,那么该行为就将存在。下面的例子中覆盖了默认的方法:
1 ServiceHost host=new ServiceHost(typeof(Counters.CounterService)); 2 3 ServiceThrottle throttle=hostA.Description.Behaviors.Find<ServiceThrottle>(); 4 5 If(throttle!=null) 6 7 { 8 9 throttle.MaxConcurrentCalls=30; 10 11 throttle.MaxConcurrentInstances=30; 12 13 throttle.MaxConcurrentSessions=100; 14 15 }
对分流行为的设置是否适当取决于多项因素,包括服务实例化模式,应用程序所公开出来的服务的数目,以及分流要求的输出等。
单调服务分流(PerCall服务分流):
由于PerCall服务在每次调用之后就会释放相关的资源,并且允许由唯一的服务实例处理多个并发请求,因此可以增加可扩展性和吞吐量。MaxConcurrentCalls分流属性影响并发服务实例的数目,这将影响服务可以并行处理的请求的数目。通过粗略计算可以看到吞吐量的大小。让我们假设你在宿主进程中寄存一个单服务类型(ServiceHost)实例。如果你设置MaxConcurrentCalls值为30,并且每个请求需要0.5秒来处理,你的主机每秒大约可以处理60个特定服务类型的请求。如果请求需要几分之一秒,你每秒也许可以处理多达300个请求。
对于PerCall服务,MaxConcurrentInstances应设定为大于或等于MaxConcurrentCalls的值。将两个值设定为较小的值可以用来限制并发请求。MaxConcurrentSessions在PerCall服务中对应应用程序会话没有影响。
假设一个纯粹的没有任何形式会话的PerCall服务,它没有可靠会话或安全会话的BasicHttpBinding和WSHttpBinding绑定,那么你可以从以下分流配置开始:
1 <serviceThrottling maxConcurrentCells="30" maxConcurrentInstances="30"/>
两个分流设定应保持同步,正如刚才所说,较低的两个分流将影响吞吐量。在此没有提到对会话的设置,因为它在这种终端上被忽视了。
会话服务分流(分流的会话):
会话的形式可以是传输会话,可靠会话,安全会话或应用会话。不管并发模式或会话的类型如何,为MaxConcurrentCalls的限制都应视为类似的方式,其目标是允许每秒有合适数目的请求通过,而不是依赖于会话的数量。
在应用会话的模式下,MaxConcurrentInstances应达到或超过MaxConcurrentSessions的限制。因为这个值实际上限制了可以保持活动以支持应用会话的并行服务实例的数量。
在任何情况下,对于一个大型的企业系统来说,首先你可能需要进行下面的设置,并根据使用模式和服务器能力进行调整:
1 <serviceThrottling maxConcurrentCalls="30" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>
一定要跟踪连接超时的性能计数器,这样你可以监视增大这些值的需求。
单例服务分流(分流单例):
对于单例服务,MaxConcurrentCalls应当遵循为PerCall和PerSession服务所提供的指导。MaxConcurrentInstances是无关紧要的,因为总共只需要创建一个实例单例。MaxConcurrentSessions应按照会话的方式处理.需要注意的是,对于大型系统,你可能
首先要考虑这些设置:
1 <serviceThrottling maxConcurrentCalls="30" maxConcurrentInstances="1" maxConcurrentSessions="1000">
小结
1:尽可能使用PerCall服务.
2:对大规模的部署避免PerSession并发模式.
3:当需要PerSession服务时,尽量使用Single并发模式进行同步.
4:对于大规模服务器的部署,应避免Single并发模式.
5:总是检查代理状态,以确保服务器信道没有出现故障。
6:设置分流行为,使单一主机的进程每秒接受的请求约为300个,并确保调用者能得到新的会话。