开发高性能的WebService应用
议程:
l WebService性能概述
l WebService性能最佳实践
连接与线程优化
WebMethod的优化
高效地调用WebMethod
设置超时
缓存
状态管理
WebService性能概述
性能是一项功能
l 设计时就考虑性能
l 不要在事后再加入性能!
l 在项目开发的整个过程中反复测试
l 两种量化Web性能的方法:
1) 机器吞吐率(requests/sec)
2) 响应时间(time to first/last bytes)
由于Web Service也是通过IIS处理的,所以
ASP.NET的优化处理在这里也能适用。
下面的对比是看看在面向对象和面向服务的条件下的比较
面向对象 | 面向服务 |
l 应用于同一平台和运行环境 l 共享类型而不是schemas l 采用便宜, 透明通信 l 对象的标识与生命周期由系统维护 l 客户机和服务器的同步的部署 l 容易概念化,因而提供一个自然的模型 l 一般不需要状态管理 l 应用于一个可预测的序列、期限和结果 l 目标是远程透明地使用方法和类型 | l 应用于异构平台和运行环境 l 共享schemas而不是类型 l 采用高成本, 明确通信 l 服务是自治的: 安全和失效是隔离 l 允许的连续, 分离部署客户机和服务器 l 基于软件组件和分布的对象,依赖服务的协议 l 拥有并维护状态 l 基于消息, 异步的, 和长通信 l 目标是提供服务隔离和调用的标准。 |
WebService性能设计的考虑
l 设计"大块头"的接口减少往返
[这是考虑在网络环境的开销问题。在面向对象的设计中,一般要求最大程度达到软件服用,但是在网络环境下,接口调用的往返是必须考虑的问题]
l 基于消息的编程而不是远程过程调用(RPC)
[RPC强调方法的复用,每个方法很小,基本上看作面向对象的]
l 使用XML字串作为参数。
l 尽量使用原始数据类型参数。
l 避免在调用之间维护服务器状态。
l 考虑为复杂的WebMethod提供输入校验。
[减少传输量]
l 考虑对WebMethod的结果进行缓存。
l 选择适用的大数据包传送方式。
l 避免调用本地的WebService。
消息VS RPC
l RPC
Serv.SendItemsToBePurchased(Array[] items);
Serv.ShippingAddress(stringAddress);
Serv.CheckOut();
l 消息
//Client
string msg= "<Items>...</Items>";
MyMethod(msg);
//Server
[WebMethod]
void MyMethod(stringmsg){ . . . }
WebService性能最佳实践
连接与线程优化
连接
l 配置maxconnection 属性。
<connectionManagement>
<add address="WebServiceA" maxconnection="8">
<add address="WebServiceB" maxconnection="4">
</connectionManagement>
l 对WebService按优先级分配连接资源
l 使用单一身份进行调用。
serv= new WebService1();
serv.PreAuthenticate=true;
ICredentialsconCredentials=new
NetworkCredential("UId","Pwd","NPSTest" );
serv.Credentials= conCredentials;
serv.AllowAutoRedirect=false;
serv.ConnectionGroupName= "SameForAllUsers";
l 为集成认证使用:
UnsafeAuthenticatedConnectionSharing=true(不安全认证连接共享)让不同用户共享同一连接,默认情况下一个用户使用一个连接,不能共享
l 为基本验证使用PreAuthenticate
域认证,这样节约大量的时间
<connectionManagement>
<add address="*" maxconnection="12"/>
</connectionManagement>
线程
l 优化线程池减少竞争。
l 考虑minIoThreads 和minWorkerThreads为断断续续的集中的负载
[这里设置较高,在集中访问(访问高峰)能够快速调用:线程池]
WebMethod的优化
l 使用原始类型参数。
l 考虑使用缓冲。
l 将WebMethod的返回缓存。
l 只在需要会话状态时才使用它。
大数据包的处理
l 使用字节数组作为参数或返回值
l 返回一个URL[在用户需要的时候在返回]
l 使用串行化流
<configuration>
<system.web>
<httpRuntime maxRequestLength="8096"
useFullyQualifiedRedirectUrl="true"
executionTimeout="45"/>
</system.web>
</configuration>
maxRequestLength:请求长度
executionTimeout:执行过期时间
串行化
l 使用XmlIgnore减少串行化。
l 减少往返。
l 考虑使用XML 压缩。
public class MyClass
{
// The str1 value will be serialized.
public string str1;
/* This field will be ignored when
serialized--unless it's overridden. */
//str2不参与服务器端和客户端的串行化,可以考虑Ignore
[XmlIgnoreAttribute]
public string str2;
}
异步Webmethod
l 用异步Webmethods对I/O 操作。
l 当Webmethods依赖于工作线程时,不要使用异步。
//webservice [WebMethod] IAsyncResultBeginMyProc(...) [WebMethod] EndMyProc(...) | //the WSDL will show themethodas MyProc(...) |
单工通信
如果不需要返回,考虑使用OneWay属性。
[SoapDocumentMethod(OneWay=true)]
[WebMethod(Description="Return immediately")]
public void SomeMethod()
{...}
COM 交互
l 建议: 尽量避免交互
l 最好将COM代码移植到.NET
可能会很昂贵, 尤其对于数组操作
“受管” 与“不受管” 转换
l 注意单元线程组件
缺省情况ASP.NET 使用MTA线程
损害STA 组件性能
注意所有VB6组件!
高效地调用WebMethod
异步调用
l 当有并发任务时例用异步调用WebService。
l 使用异步调用多个不相关的WebService。
l 异步叫调用WebService可以增加UI 响应。
【源代码】
服务器端
[WebMethod]
Public string HelloWorld()
{
Thread.Sleep(5000);
Return “hello world!”
}
客户端
ASP.NET2.0
Private void Async_Click(object sender,EventArgs e)
{
//代理
Localhost.service ser=new WSClient.localhost.Service();
Ser.HelloWorldCompleted+=new WSClient.localhost .HelloWorldCompletedEventHandle(ser_HelloWorldComplete);
Ser.HelloWorldAsync();
}
Private void ser_HelloWorldComplete(object sender, HelloWorldCompletedEventArgs e)
{
MesageBox.Show(e.Result.ToString());
}
设置超时
l 适当地设置代理的超时。
l 设置您的ASP.NET 超时大于您的WebService的超时。
l 如果页面超时,则放弃页面与WebService的连接。
MyWebServobj= new MyWebServ();
obj.Timeout= 15000; // in milliseconds
缓存
l 对时效性不强的数据进行缓存。
l 考虑提供与缓存所相关的信息给客户。
l 考虑使用边界缓存,如ISA上的缓存
//不使用会话,不支持事务,缓存时间为10秒
[WebMethod(false,TransactionOption.NotSupported,10)]
状态管理
l 只在需要会话状态时才使用它。
l 减少应用状态与服务器的亲合力。
InProc:进程内,最好的性能,但是与服务器亲和力最强。
StateServer
SQLServer
【代码分析】
服务器端
在global.asax加入Session[“count”]=0;
[WebMethod(true)]
Public int getCount()
{
Int temp=(int)Session[“count”];
temp++;
Session[“count”]=temp;
return temp
}
客户端,考虑WinForm
Using System.Net;
CookieContainer cc=new CookieContainer();
Public void getCount_Click(object sender,EventArgs e)
{
Localhost.service t=new WSClient.localhost.service();
t. CookieContainer=cc;
MessageBox.Show(t. getCount ().ToString());
}
在注释红色字体的情况下,我们会发现,会话不起作用。这是因为服务器和客户端端传递保存有SeesionID的Cookie,对于IE等浏览器能够处理Cookie,能够有效保存会话,而WinForm中,不能处理Cookie,每次都扔掉不处理,所以每一个请求都认为是新的Session,所以不能保存会话。这里做一下处理就可以完成这样的保存。