Programming WCF Services 学习笔记四、Instance Management
1. Behaviors
i. Service的实例模型是客户端无关的,即Client端不会知道Service的实例模型,Service的实例模型也不会影响Client端
ii. 通过ServiceBehavior Attribute可以设定Service的实例模型
iii. OperationBehavior Attribute设定OperationContract的行为
三种实例模型
2. PerCall:
i. 每次一个新的调用到来时,WCF会创建一个新的Service实例进行服务,调用结束时销毁实例
ii. PerCall的好处
1. 传统的CS模式是每个Client长期占用一个Service实例,直至Client停止,这样专用的方式很浪费Service实例
2. 一个好的办法是直到一个Client的Call到来时才创建一个Service实例,Call结束时就销毁实例,这样使得Service实例的数目不再是Client的所有数目,而是同时调用(并发访问)的数目
3. 使用
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]指定使用PerCall实例模型
4. 因为PerCall是在每次Call时创建一个新的实例,Call完就销毁实例,所以需要一个保存状态的机制(Call之前Load状态,Call之后保存状态)
5. 因为PerCall每次会创建/销毁新的实例,还需要一个Instance的ID标识要获得/保存哪个Instance的状态
6. PerCall在两种情况下工作最佳
1. 每一次Call所做的事情没有关联性
2. 没有幕后的工作要做(异步)
7. PerCall适合负载均衡的场合,能在多台机器之间负载
8. PerCall在性能(创建实例)和可测量性(资源占用)之间做了一个平衡,要根据具体情况而定
9. 使用PerCall时,不要为ServiceContract添加Cleanuup()之类的方法,即Client不能执行Cleanup的工作
10. PerCall的最大优点是可扩容性,他可以容纳更多的Client调用,而且PerCall可以很好地参与事务
3. PerSession
a) WCF可以在一个Client(Proxy)和一个Service Instance之间维持一个Session
b) PerSession和经典的C/S模式很像。优点是可以保存状态,隔离性。缺点是专属Session,可扩容性差
c) PerSession是默认的实例模型
d) PerSession状态下,Session在Proxy close时被Close
e) Proxy被Close时需要通知Service,所以Service要标识Proxy。WCF可以使用Transport-level session
f) NetTcpBinding,NetNamedPipeBinding支持Transport-level session
g) WSHttpBinding可以通过在消息头中包含Session ID来达到同样的目的
h) 还可以在ServiceContract上指定SessionMode=SessionMode.Allowed,指定ServiceContract使用PerSession模型。但最终是使用哪种模型,还是取决于ServiceBehavior和协议
i) 通过指定SessionMode=SessionMode.Required指定ServiceContract必须使用PerSession,但如果使用不支持Transport-level session的协议,WCF会在运行时报错,但ServiceBehavior设为PerCall时会使用PerCall
j) 通过制定SessionMode=SessionMode.NotAllowed指定ServiceContract不能使用Transport-level session的协议,它强制适应PerCall,如果使用TCP或IPC协议,WCF会在运行时报错。而WSHttpBinding可以使用
k) 较为好的办法是使用NotAllowed时,ServiceBehavior设为PerCall
Table 4-1. Instance mode as a product of the binding, contract configuration, and service behavior |
||||
Binding |
Session mode |
Context mode |
Async Dispose() |
Instance mode |
Basic |
Allowed/NotAllowed |
PerCall/PerSession |
Yes |
PerCall |
TCP, IPC |
Allowed/Required |
PerCall |
No |
PerCall |
TCP, IPC |
Allowed/Required |
PerSession |
Yes |
PerSession |
WS (no security, no reliability) |
NotAllowed/Allowed |
PerCall/PerSession |
Yes |
PerCall |
WS (with security or reliability) |
Allowed/Required |
PerSession |
Yes |
PerSession |
WS (with security or reliability) |
NotAllowed |
PerCall/PerSession |
Yes |
PerCall |
l) 当使用PerSession时,Session的可靠性是依赖于Transport的可靠性的,所以尽量开启可靠消息传输
m) SessionID用来表示当前的Session。Service端通过OperationContext.Current.SessionId取得,Client端通过Proxy.InnerChannel.SessionId取得
n) 取得Session的策略
i. 当使用TCP协议并启用可靠消息传输时,Session在第一次Call之后获得,之前获得的是null。
ii. 当使用TCP协议但未启用可靠消息传输时,Client可以在Call之前取得SessionID,但SessionID不会匹配任何Service
iii. 当使用WS Binding,并启用可靠消息传输时,在第一次Call之前,SessionID为Null
iv. 当使用WS Binding,但不启用可靠消息传输时,必须先Open Proxy,否则会报异常,Open之后,SessionID可用
v. NamedPipe Binding时,第一次Call之前就能取得SessionID,但SessionID不匹配Service,无意义
vi. 当Client端Proxy10(默认)分钟无任何动作时,Session失效,可以修改超时时间。在reliableSession中的inactivityTimeout中设定
vii. 当Client和Service都设定超时时间时,取其短
4. Singleton
i. 所有的Client独立地连接到同一个Service Instance,尽管他们连接到不同的Endpoint。Singleton Service Instance在Host创建时创建,在Host 关闭时销毁。
ii. Singleton不要求Session。当ServiceContract需要Session时,Service Instance会维护一个Session(SessionID同Client相同),当Client Proxy关闭时,Session被关闭,但Service Instance依然存在。而且Session不会过期。
iii. 如果想自己创建Singleton Instance并自定义初始化操作,WCF提供了一种方式:ServiceHost的一个构造函数接受Object类型的Singleton Instance,可以传递一个自己创建的对象传给ServiceHost。并且可以在Service对象的SingletonInstance属性取得此Instance。在代码链中,可以通过OperationContext.Current.Host. SingletonInstance取得。
iv. Singleton十分不利于扩容性。原因是状态同步。Singleton让多个Client共享一个Service Instance,需要管理多个Client并发,状态同步,这样会降低性能。
v. Singlet适用于像日志这样的只需一个对象的场景,不使用于可能服务于多个Client,并且Client可能增加的场景。
5. Demarcating Operations
i. 在需要Session的ServiceContract中,有时需要某个方法最先被调用,或某个方法最后被调用,WCF使用OperationContract Attribute的IsInitiating和IsTerminating标识Service边界。
ii. 如果这两个Property被设置为非默认值,在Service Load时,WCF会检验方法所在地ServiceContract是否支持Session,如果不支持,会报异常。PerSession和Singleton都支持Demarcating Operation。
6. Instance Deactivation
i. 在需要Session的ServiceContract中,WCF允许在某个方法上指定调用之前或之后销毁当前Service Instance。
ii. 通过在方法上使用ReleaseInstanceMode枚举,指定行为。
iii. 不能在每个方法上都是用它,因为这样就和PerCall相同了。
iv. 可以使用Demarcating Operation指定销毁Instance的顺序。
v. 当ReleaseInstanceMode被设为BeforCall时,方法调用前,Client被阻塞,WCF首先销毁当前Session中存在的Service Instance(调用Dispose),再调用方法。
vi. 当ReleaseInstanceMode被设为BeforAndAfterCall时,在调用方法前后,都会销毁当前的Instance然后创建一个新的。它可以用在BeforCall之后,或AfterCall之前,用来模拟PerCall的情况。
vii. 除了使用Attribute在设计时指定之外,还可以调用InstanceContext.ReleaseServiceInstance()在运行时释放Service Instance。而且可以和Attribute合作,BeforCall Attribute+方法结尾时调用InstanceContext.ReleaseServiceInstance()相当于BeforAndAfterCall Attribute。
viii. Instance Deactivation是一个优化的技术,就像所有的优化技术一样,尽量避免把它使用到普通场景下。Instance Deactivation使用在遇到性能和可扩容性共同存在是时比较有效,并且可以得到一些改善。但如果可扩容行和吞吐量是你所关心的指标的话,尽量使用PerCall方式,而避免使用Instance Deactivation。
7. Throttling
i. Throttling允许WCF抑制Client连接和负载。通过设置Throttling,可以控制Service服务的Client的数量和Service访问的资源。
ii. Throttling通过把超出规定数目的Client请求入队来抑制Client的连接,如果一个Client Call在出队之前就超时的话,Client会得到超时异常。
iii. Throttling使用于各种Service实例模型,即对所有的Service都有效。
iv. Throttling通过Channel Dispatcher起作用
v. Throttling的几种情况
1. Session的并发数:在启用Session时,可以设置每个Session可以同时服务的Client数目,默认是10个。但这种设置对不起用Session的情况无效。
2. 调用(Call)的并发数:所有Instance服务的Client Call的并发数,默认是16个。
3. Instance的并发数:同时存在的Instance Context的数目,默认无限制。Context的数目和Instance的数目是不一样的,取决于Instance Deactivation的设置。
4. 在PerSession Service中,Instance的最大数目取决于Instance的并发数和Session的并发数。当Instance Deactivation被使用时,Instance的数目会少于Context的数目(因为Instance可能会在Call之后被销毁)。但是当Context的数目达到Instance的并发数目时,Client会被阻塞。
5. 在PerCall Service中,Instance的数目就是Call的并发数。
6. Throttling对Singleton无效。
vi. 配置Throttling
1. 在Behaviors节ServiceBehaviors中ThrottledBehavior中设置ServiceThrottling的MaxConcurrentCalls,MaxConcurrentSessions,MaxConcurrentInstances。
2. 编程方式:设置
host.Description.Behaviors.Find<ServiceThrottlingBehavior>( );
vii. Binding的Throttling
1. 可以在TCP和NamePipe Binding中设置MaxConnections,如果Binding和Service同时设置,WCF取其最小值。
(未完待续)