网站性能优化之缓存篇

文章来源:http://blog.sina.com.cn/s/blog_71219ee20100sgma.html

大型电子商务网站的性能优化是web程序员必修课之一,基于net开发的web应用程序,通常借助于net提供的cache技术来实现缓存。下面是我对“# 窝窝商城#”大型btoc网站基于cache缘存的一些记录。
     参考资料:OutputCache VaryByParam
  ASP.NET 的输出缓存
衡量高性能、可缩放的  web  应用程序最重要的一个指标就是缓存了。  ASP.NET  提供了高性能的  web  应用程序的缓存功能 ,ASP.NET  有三种可由  Web  应用程序使用的缓存:
·   输出缓存  ,它缓存请求所生成的动态响应。
·   片断缓存  ,它缓存请求所生成的响应的各部分。
·   数据缓存  ,它以编程方式缓存任意对象。为支持这种缓存,  ASP.NET  提供了全功能的缓存引擎,使程序员能够轻松地在请求间保留数据。
页的输出缓存是非常有用的。在海量的访问站点中,有些页面的访问频率占了非常大的比重,即使对这些页使用输出缓存很少的时间,也会减轻系统不少的负担,因为后面对这些页面的请求将不在执行创建该页的代码。
但是,这样显得不够灵活,页的请求可能的确是很多,然而在页面上我们缓存了所有的东西,无论是构造成本高还是构造成本低的部分。能否有一种可以缓存页的部分的数据呢?幸运的是  ASP.NET  提供了针对每个请求来创建或自定义该页的各部分。比如说我们可以对页面上构造成本很高的用户控件做片断缓存。
ASP.NET  缓存支持文件和缓存键依赖项,使开发人员可以使缓存项依赖于外部文件或其他缓存项。此项技术可用于在项的基础数据源发生更改时使该项无效。  ASP.NET  可以将这些项存储在  Web  服务器上或请求流中的其他软件上,例如代理服务器或浏览器。这可以使您避免重新创建满足先前请求的信息,特别是当在服务器上创建时要求大量处理器时间或其他资源的信息。
Petshop 的页缓存设置
我们可以可通过使用低级别的  OutputCache API  或高级别的  @ OutputCache  指令来实现页的输出缓存。  启用输出缓存后,当发出对页的第一个  GET  请求时创建一个输出缓存项。随后的  GET    HEAD  请求由该输出缓存项服务,直到该缓存请求过期。 输出缓存还支持缓存的  GET    POST  名称  /  值对的变体。
输出缓存遵循页的过期和有效性策略。如果某页位于输出缓存中,并且有一个过期策略标记指示该页自缓存起  60  分钟后过期,则在  60  分钟后将该页从输出缓存中移除。如果此后接收到另一个请求,则执行页代码,并且可以再次缓存该页。
下面的指令在响应时激活输出缓存:
<%@ OutputCache Duration="60" VaryByParam="none"%>
Duration    VaryByParam  是必选参数,前者标识过期时间,后者表示  GET    POST  名称  /  值对的字符串。如果不使用该属性,可是设置为  none  。在这里我们还要说明一个参数  VaryByCustom  ,使用这个参数,我们可以自定义输出缓存要求的任意文本。除了在  OutputCache  指令里面申明该属性之外,我们还得在应用程序的  global.asax  文件的代码声明块中,重写 GetVaryByCustomString  方法来为自定义字符串指定输出缓存的行为。
举一列来说:
<%@ OutputCache VaryByParam="none" VaryByCustom="CategoryPageKey" Location="server" Duration="43200" %>
这里的  VaryByCustom  定义的为  CategoryPageKey  ,那么在  global.asax  里面我们必须定义  CategoryPageKey  这个字符创输出缓存的行为,见下面代码。
public  override string GetVaryByCustomString(HttpContext context, String arg) {
              string cacheKey = "";
              switch (arg) {
                   case "CategoryPageKey":
                       if (Request.IsAuthenticated == true ) {
                            cacheKey = "QQQ" + context.Request.QueryString["category_id"] + context.Request.QueryString["requestedPage"];
                       }
                       else {
                            cacheKey = "AAA" + context.Request.QueryString["category_id"] + context.Request.QueryString["requestedPage"];
                       }
                       break ;
                   case "SearchPageKey" :
                       if (Request.IsAuthenticated == true ) {
                            cacheKey = "QQQ" + context.Request.QueryString["search_text"] + context.Request.QueryString["requestedPage"];
                       }
                       else {
                            cacheKey = "AAA" + context.Request.QueryString["search_text"] + context.Request.QueryString["requestedPage"];
                       }
                       break ;
                   case "ProductPageKey" :
                       if (Request.IsAuthenticated == true ) {
                            cacheKey = "QQQ" + context.Request.QueryString["name"] + context.Request.QueryString["product_id"] + context.Request.QueryString["requestedPage"];
                       }
                       else {
                                 cacheKey = "AAA" + context.Request.QueryString["name"] + context.Request.QueryString["product_id"] + context.Request.QueryString["requestedPage"];
                       }
                       break ;
                   case "ProductDetailsPageKey" :
                       if (Request.IsAuthenticated == true ) {
                            cacheKey = "QQQ" + context.Request.QueryString["item_id"] + context.Request.QueryString["requestedPage"];
                       }
                       else {
                            cacheKey = "AAA" + context.Request.QueryString["item_id"] + context.Request.QueryString["requestedPage"];
                       }
                       break ;
                   case "UserID" :
                       if (Request.IsAuthenticated == true ) {
                            cacheKey = "UserID_In";
                       }
                       else {
                            cacheKey = "UserID_Out";
                       }
                       break ;
              }
              return cacheKey;
         }
从上面对  CategoryPageKey  字符创所作的行为来看,当我们的请求页面中含有对特定的  category_id的某一分页显示的数据页的请求时,将调用缓存(自然是已经缓存了该页)。
下表列出了petshop的web应用程序的输出缓存设置。
ASP.NET WebForms
Cache setting
Duration
ControlHeader
<%@ OutputCache
         Duration="43200"         
         VaryByParam="none"
         VaryByCustom="UserID" %>
12 hours
Default
<%@ OutputCache
         Duration="43200"
         VaryByParam="none"
         VaryByCustom="UserID" %>
12 hours
Help
<%@ OutputCache
         Duration="43200" 
         VaryByParam="none"
         VaryByCustom="UserID" %>
12 hours
Category
<%@ OutputCache
         Duration="43200" 
         VaryByParam="none"
         VaryByCustom="CategoryPageKey " %>
12 hours
Product
<%@ OutputCache
         Duration="43200" 
         VaryByParam="none"
         VaryByCustom="ProductPageKey " %>
12 hours
ProductDetails
<%@ OutputCache
         Duration="43200" 
         VaryByParam="none"
         VaryByCustom="ProductDetailsPageKey " %>
12 hours
Search
<%@ OutputCache
         Duration="43200" 
         VaryByParam="none"
         VaryByCustom="SearchPageKey " %>
12 hours
显然  petshop    web  页面上部的  ControlHeader  是随着用户登陆的状态有关的,故其设置了  VaryByCustom  属性以来标识用户不同登陆状态的缓存版本。而  Category  页面由于可能被大量的访问,并且数据量很大,是十分有必要缓存的,但是由于数据的随机性很大,存在不同的版本,比如说是不同类别的  Category  ,甚至不同的分页显示的数据页,在这里采用了  VaryByCustom  属性以缓存不同版本的页。
Petshop 片断缓存
在前面我们提到  ASP.NET  可以提供页的局部数据的缓存,通常是一些构造代价较大的部分,诸如用户控件。在  petshop  里面,大量使用了用户控件(尤其是  .NET  示例程序  Duwamish7.0  使用了更多的用户控件,那些页面简直就是控件的拼装),用户控件的缓存设置方法和  aspx  页的缓存设置方法基本相同,在这里我们不再列出。只有  ControlHeader  控件使用了缓存设置,见上表。
 

你可能感兴趣的:(网站性能优化)