编写高性能的Web应用程序的10个注意点

15 篇文章 0 订阅
8 篇文章 0 订阅

文章讨论:

1.       普遍的asp.net性能点

2.       ASP.NET中有用的性能点和窍门

3.       ASP.NET中使用数据库时的一些建议

4.       ASP.NET中的缓存和后台处理

内容:

数据层性能

Tip1:返回多个结果集

Tip2:数据访问分页

Tip3:连接池

Tip4:ASP.NET缓存API

Tip5:预请求缓存

Tip6:后台处理

Tip7:页面输出缓存和代理服务

Tip8:运行IIS6(如果只市为了内核缓存)

Tip9:使用Gzip压缩

Tip10:服务器空间的视图状态(ViewState)

总结

其他:

常见的性能点

 

使用ASP.NET来编写WEB应用程序并不是想象的那么容易.如此简单的话,许多开发人员就不会花时间来结构化他们的应用程序来提高性能了。我会在本文中讲到编写高性能应用程序的10个注意点。我不会局限于对ASP.NET应用程序的注解,因为他们仅仅是WEB应用程序的一个子集而已。本文不会是优化WEB应用程序的权威指南,而是一本完整的能简单的专注于其中(WEB应用程序优化)的书。换句话说,把它想象成为WEB应用程序优化的入门。

在正式开始之前,我习惯做一些用于攀登的岩石。在冒险的攀登之前,我会查看旅游册上的路线,读一些曾经去过那个地方的人们的建议。但是,旅游册如何的好都没关系,在你尝试一项特别有挑战性的攀登之前,你需要的上攀登的实际经历。类似地,当你面对优化性能的问题或运行高吞吐量的网站时,你只能学习如何编写高性能的WEB应用程序才行。

我个人的经验来源于我在微软ASP.NET团队中身为一个基础下部组织的项目经理时积累的,那时主要负责运营、管理www.asp.net和为架构社区服务(Architect Community Server)提供帮助,这个社区是几个知名的ASP.NET应用程序的下一个版本(由ASP.NET Forums,.Text,nGallery的组成的平台)。我相信这些曾经帮助过我的Tips也会对你们有帮助的。

你应该考虑将你的应用程序进行合理的分层。你有可能听说过3层(或n层)物理架构的术语,通常有一些规定的体系结构模板来物理的划分跨处理或跨硬件的功能。由于系统规模的需要,更多的硬件可以很容易添加。然而,有个与处理和机器能力有关的降低性能的点,因此,要加以避免。所以,只要有可能,就在同一应用程序中一起运行asp.net页面及其相关部件。

由于分离开的代码和层与层之间的分界,使得使用Web Services 或者远程调用都会降低性能20%或更高。

数据层是很特别的一块,因为通常使用专门的硬件来支持你们的数据库。然而,处理数据库的成本仍然很高,因此,在你优化你的代码的时候,应讲数据层的性能放在首位来考虑。

在置身于你的应用程序的优化问题之前,确保你分析应用程序来找出问题的所在。关键性能点(如反应执行垃圾回收所耗时间的百分比)在找出应用程序耗费多半时间的地方也是很有用的,因此耗费时间的地方通常很敏感(unintuitive.

本文有两种提高性能的方法:大型优化,就像使用ASP.NETCache,和反复使用自己的微优化。这些微优化有时是最有意思的,你修改了一小部分代码,而带来了成千上万倍的回报。使用大型优化,你可能看到整体性能有个大的跳跃。使用微型的,你可能只能对一个给定的请求降低几毫秒的时间,但是将每天所有请求混合起来的时候,将会有巨大的性能提升。

数据层的性能

在优化应用程序的时候,有一个你能用来划分工作的优先次序的测试:代码访问数据库吗?如果是这样,那么通常是如何做呢?注意,相同的测试也可以应用于使用Web Services或远程调用的代码,但本文并不涉及。

如果你有一个数据库请求,要求必须在某一特定代码路径,你看看其他方面如您要首先优化的字符串操作,制止和履行你的测试。除非你有严重的性能问题,你的时间就会更好的加以利用来努力优化所花费的和连接数据库的所需要的时间,数据返回的数量,和往返数据库操作的频率。

随着一般信息的确定,让我们看看能优化你的应用程序的10个要点,I'll begin with the changes that can make the biggest difference.

       Tip 1 – 返回多结果集

再看看你的数据库代码,看看是否有一个以上的请求数据库的路径。每一次数据往返都会降低你应用程序所能提供的请求的效率(每秒所能接受的请求数)。通过返回给单个数据库请求放回多个结果,你可以削减同数据库通讯时花费的总体时间,你还会使你的系统更具扩展性,还会缓解数据库服务器管理请求的工作压力。

你可以使用动态SQL来返回多个结果集,我更倾向于使用存储过程。业务逻辑是否需要放在存储过程里时可以论证的,但是我认为,如果存储过程中的逻辑能约束返回的数据(降低数据集的大小,花费在网络上的时间,而且不必在逻辑层过滤数据),那么它是好的。

使用SqlCommand实例和它的ExecuteReader方法来构造强类型的业务类,你可以通过调用NextResult来将结果集的指针往后移。图1显示了一个将多个ArrayList转化为类型化的类的一个例子。仅从数据库返回你需要的数据会更多的减低你的服务器的内存空间。

Figure 1 Extracting Multiple Resultsets from a DataReader

// read the first resultset

reader = command.ExecuteReader();

// read the data from that resultset

while (reader.Read()) {

    suppliers.Add(PopulateSupplierFromIDataReader( reader ));

}

// read the next resultset

reader.NextResult();

// read the data from that second resultset

while (reader.Read()) {

    products.Add(PopulateProductFromIDataReader( reader ));

}

 

Tip 2 数据访问分页

ASP.NETDataGrid控件具有极强的功能,包括数据分页支持。当DataGrid的分页功能被启用时,会一次显示固定的数目的结果。另外,分页用户界面也可以显示在DataGrid控件的下部,用来导航结果。分页用户界面允许你向前向后翻页来显示数据,一次显示固定数目的结果。

这里有个缺点,使用DataGrid来分页会将所有数据绑定到网格。例如,你的数据层需要返回所有的数据,然后由DataGrid根据当然页来过滤显示的结果。假如当你正通过DataGrid分页时有100,000条记录返回,那么每个请求都会有99,975条记录被丢弃(假设每页显示25条)。随着记录数目的增加,程序的性能会大大受损,因为每个请求所请求的数据越来越多。

一个很好的方法受使用存储过程来写更好的分页代码。图2显示了一个Northwind数据库中对Orders表分页的存储过程。在这个例子中,你唯一要做的就是传递两个参数页的索引和页面大小,然后相应的结果集就会被计算出,并被返回。

在社区服务系统中,我们受编写了一个分页服务控件来负责所有的数据分页。例如,一条where子句用于约束返回的数据,返回记录的总数一定要知道,目的是为了计算总页数来显示在分页界面上。例如,有1,000,000条记录,WHERE子句用来筛选出1,000条,分页逻辑需要知道总记录数来相应的呈现到分页页面上。

Figure 2 Paging Through the Orders Table

CREATE PROCEDURE northwind_OrdersPaged

(

    @PageIndex int,

    @PageSize int

)

AS

BEGIN

DECLARE @PageLowerBound int

DECLARE @PageUpperBound int

DECLARE @RowsToReturn int

 

-- First set the rowcount

SET @RowsToReturn = @PageSize * (@PageIndex + 1)

SET ROWCOUNT @RowsToReturn

 

-- Set the page bounds

SET @PageLowerBound = @PageSize * @PageIndex

SET @PageUpperBound = @PageLowerBound + @PageSize + 1

 

-- Create a temp table to store the select results

CREATE TABLE #PageIndex

(

    IndexId int IDENTITY (1, 1) NOT NULL,

    OrderID int

)

 

-- Insert into the temp table

INSERT INTO #PageIndex (OrderID)

SELECT

    OrderID

FROM

    Orders

ORDER BY

    OrderID DESC

 

-- Return total count

SELECT COUNT(OrderID) FROM Orders

 

-- Return paged results

SELECT

    O.*

FROM

    Orders O,

    #PageIndex PageIndex

WHERE

    O.OrderID = PageIndex.OrderID AND

    PageIndex.IndexID > @PageLowerBound AND

    PageIndex.IndexID < @PageUpperBound

ORDER BY

    PageIndex.IndexID

 

END

Tip 3 连接池

设置Web应用程序和SQL Server之间的TCP连接可能是个很费事的操作。Microsoft的开发者现在已经利用连接池几次了,允许他们重用对数据库的连接。相比给每个请求建立一个新的TCP连接来说,现在只要在连接池中没有可用的连接时建立一个新连接就可以了。当连接一被关闭,就被返回给连接池,这个池仍然与数据库有部分连接,因为不赞成完全撤销TCP连接。

当然,你需要关注连接溢出。当你使用完连接时,总要关闭它。我再说一遍:任何人说Microsoft .net framework的垃圾回收机制什么话都没关系,只要在你使用完连接后调用Close或者Dispose来显示的关闭连接就行。不要太相信CLR能为你在需要的时间清除和关闭连接。CLR会在最终销毁类和专注于连接的关闭,但是你不能保证对象的垃圾回收操作会不会真正执行。

为使最佳的使用连接池,这里有两个规则共参考。一,打开连接,工作,然后关闭连接。对每个请求打开和关闭连接多次使可行的,如果你不得不这样(使用Tip 1更理想),而不是保持连接并在不同的方法中使用它。二,使用相同的连接字符串(如果使用混合验证方式的话,还要使用相同的线程标记)。如果你不用相同的连接字符串的话,例如使用基于已登陆的用户的定制化连接字符串,这样你就不能得到连接池提供的同样的理想值。而你使用混合验证方式来模拟大匹用户的话,你的连接池会大大降低性能。在尝试跟踪任何于连接池有关联的事件上,.NET CLR数据性能计数器会非常有用。

你的应用程序无论何时连接资源(如数据库)还是在其他进程中运行,你都应该致力于连接资源的耗时,发送或获取数据的耗时及数据往返(round-trips)次数等的优化上。优化应用程序进程的任何一部分(process hop)都是开始达到优化目的的第一步。

应用层包括连接数据并将数据转化为类的逻辑和一些业务逻辑。例如,社区服务中,这就是你填充论坛或线程收集,应用业务规则(例如许可验证)的地方。最重要的它是实施缓存逻辑的地方。

Tip 4 ASP.NET 缓存API

在你编写一行应用程序代码之前首先要做的是你应该构建应用层框架来达到最优化并使用asp.net的缓存功能。

假如你的组件正运行在ASP.NET应用程序中,你只需要引入System.Web.dll到你的应用程序的工程中。当你需要访问缓存时,使用HttpRuntime.Cache属性(同样的对象还有Page.CacheHttpContext.Cache)。

缓存数据有一些规则。首先,如果数据会被使用多于一次,那么该数据适合使用缓存。第二,如果数据很常规,而不是特别针对特定请求或用户的,则非常适合于缓存;如果数据依赖于请求或用户,但有很长的生命周期,它同样适合缓存,但可能不是经常被使用。第三,也是经常被忽视的规则,有时你可以缓存太多。通常,在X86的机器上,你想运行一个不高于 800M 的私有字节的进程,来降低内存溢出错误的机会。因此,缓存应该要有限制的,换句话说,你有可能重用计算的结果(result of a computation),但如果计算要10个参数的话,你可能尝试着去缓存10种排列,这很可能让你陷入困境。对ASP.NET来说,其中最常见的调用支持是过分缓存导致的内存溢出错误,尤其是大数据类型。

有几个重要的缓存特征你需要明白。首先,缓存实现最近最少使用算法,迫使ASP.NET清除缓存----自动清除缓存中不用的项目----如果内存不足的话。第二,缓存还支持能迫使失效的过期依赖。它们包括时间,关键字和文件。时间是经常使用的,但ASP.NET 2.0中,一个更新功能更强大的失效类型是数据库缓存失效。当数据库中的数据发生改变时候,它能知道删除缓存中的实体。关于数据库缓存类型的更多信息可以查看MSDN Magazine 20047Dino EspositoCutting Edge栏目.。看一下缓存的体系架构,如图3

Figure 3 ASP.NET Cache

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值