ASP.NET性能优化之局部缓存分析

在网站的开发过程中,经常碰到的一类需求场景是:

1:页面含热点新闻,热点新闻部分需要10分钟更新一次,而整个页面的其它部分1天内都不会变动;

2:首页的某个BANNER需要显式:欢迎***;

上面场景中的1,如果整个页面的缓存失效都定为10分钟,则势必增加性能开销,所以最好的策略是页面的不同部分采用不同的缓存失效时长。对于场景2也一样,我们不应该为了迁就某个BANNER不能应用缓存,就让整个页面都不支持缓存。

可以说,如果我们在开发网站过程中的缓存策略是不支持页面局部缓存的,整个架构就是不合理的。

一:局部缓存常用解决方案

针对上面的需求,有几类解决方案:

1、Client Side Includes(CSI):通过frame、iframe、 javascript、javacript+ajax等方式将另外一个页面的内容动态包含进来。像现在流行的jquery等javascript库对此有较好的支持。

优点:能够利用浏览器客户端并行处理及装载的机制;通过浏览器缓存机制可以降低网络传输时间,提高性能;计算放在客户端,能够降低服务器端压力

缺点:搜索引擎优化问题;javascript兼容性问题;客户端缓存可能导致服务器端内容更新后不能及时生效;XSS等安全隐患

2、Server Side Includes(SSI):

优点:SSI技术是通用技术,不受具体语言限制,只需要Web服务器或应用服务器支持即可,Ngnix、Apache、Tomcat、Jboss等对此都有较好的支持

缺点:SSI在语法上不能够直接包含其他服务器的url(当然也可以通过redirect等来变通实现),因此在需要充分利用缓存及负载均衡的环境下相对不是很灵活。

当然如果不使用单独的缓存服务器,而是使用Ngnix,利用Ngnix对SSI及Memcached支持,通过NginxHttpSsiModule、 NginxHttpMemcachedModule也可以实现页面缓存,但与专业的缓存服务器(例如Varnish)相比较,Ngnix作为缓存服务器只适合于中小规模的场合。

3、使用ASP.NET的片段缓存

可以利用用户控件将页面分段,在ascx文件中写入缓存的语句,而不在aspx文件中写缓存语句,这样ASP.NET就可以只缓存ascx片断的输出了。

缺点:片段缓存不支持Location特性;缓存页面片段惟一合法的地方是web服务器。这是因为片段缓存在ASP.NET中是新的功能,所以浏览器和代理服务器不支持。由于它不是W3C标准,像SQUID和VARNISH这样的代理服务器也不支持它。

4、Edge Side Includes (ESI):

Edge Side Includes(ESI) 和Server Side Includes(SSI) 和功能类似。SSI需要特殊的文件后缀(shtml,inc)。ESI可以直接通过URI包含远程服务器文件,ESI更适合用于缓存服务器上,缓存整个页面或页面片段,因此ESI特别适合用于缓存。本文要介绍的就是ESI的方式来支持局部缓存。

优点:ESI是一个W3C标准,被当下流行的缓存服务器SQUID,Varnish支持。

二:ESI的ASP.NET实现

本文所要阐述的是ESI局部缓存的实现。主页面(test1.aspx)前台:


代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="test1.aspx.cs" Inherits="WebApplication2.aspx.test1" %>
<%@ Import Namespace="System.Globalization" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<div>这里是局部缓存</div>
<esi:include src="test2.aspx"/>
<div>局部缓存结束</div>
<%=DateTime.Now.ToString("U", DateTimeFormatInfo.InvariantInfo)%>
</body>
</html>

主页面的后台请参看上篇,对主页面采取了缓存策略,即在页面中使用esi:include标识。
被包含的页面(test2.aspx)的前台:


代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="test2.aspx.cs" Inherits="WebApplication2.aspx.test2" %>
<%@ Import Namespace="System.Globalization" %>
<div>
局部缓存中的页面:
<%=DateTime.Now.ToString("U", DateTimeFormatInfo.InvariantInfo)%>
</div>

被包含的页面的后台什么也不需要处理,也就是不为它加入任何缓存策略,该页面是实时的。
VARNISH配置文件如下:


代码如下:

backend default {
.host = "192.168.0.77";
.port = "80";
}
sub vcl_fetch {
remove beresp.http.Set-Cookie;
if(req.url ~ "test1.aspx") {
esi;
}
if(req.url ~ "test2.aspx"){
return (pass);
}
}
sub vcl_recv {
remove req.http.Cookie;
#remove req.http.Accept-Encoding;
#remove req.http.Vary;
}
sub vcl_hit {
if(req.http.Cache-Control~"no-cache"||req.http.Cache-Control~"max-age=0"||req.http.Pragma~"no-cache"){
set obj.ttl=0s;
return (restart);
}
return (deliver);
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
}

上文的vcl_fetch函数中加了两个判断,指的是:如果碰到test1.aspx就处理esi标识,如果碰到test2.aspx,就直接忽略让后台IIS处理。
值得注意的是,启动命令中加入了-p选项(这是一个varnish的小问题,请查阅参考,此处不表):
varnishd -a :8011 -T :8088 -f c:/varnish/etc/default.vcl -p esi_syntax=0x1 -s file,c:/varnish/var/cache,100M
三:效果
启动varnish后,我们发现,对于test2.aspx,由于我们使用了esi对其进行了包含,而test2.aspx又未进行缓存,所以在test1.aspx的缓存有效期内,随着每一次刷新,test1.aspx的内容没有变动,但是所包含的test2.aspx区域,会实时刷新。
参考(第一小节大部分来自参考文字):
https://www.varnish-cache.org/trac/ticket/352

http://cd34.com/blog/infrastructure/no-esi-processing-first-char-not/

http://hi.baidu.com/chuanliang2007/blog/item/075f67963e20f315d31b7035.html

http://www.w3.org/TR/esi-lang

(0)

相关推荐

  • asp.net 程序性能优化的七个方面 (c#(或vb.net)程序改进)

    1.使用值类型的ToString方法 在连接字符串时,经常使用"+"号直接将数字添加到字符串中.这种方法虽然简单,也可以得到正确结果,但是由于涉及到不同的数据类型,数字需要通过装箱操作转化为引用类型才可以添加到字符串中.但是装箱操作对性能影响较大,因为在进行这类处理时,将在托管堆中分配一个新的对象,原有的值复制到新创建的对象中. 使用值类型的ToString方法可以避免装箱操作,从而提高应用程序性能. int num=1; string str="go"+num.T

  • asp.net性能优化之使用Redis缓存(入门)

    1:使用Redis缓存的优化思路 redis的使用场景很多,仅说下本人所用的一个场景: 1.1对于大量的数据读取,为了缓解数据库的压力将一些不经常变化的而又读取频繁的数据存入redis缓存 大致思路如下:执行一个查询 1.2首先判断缓存中是否存在,如存在直接从Redis缓存中获取. 1.3如果Redis缓存中不存在,实时读取数据库数据,同时写入缓存(并设定缓存失效的时间). 1.4缺点,如果直接修改了数据库的数据而又没有更新缓存,在缓存失效的时间内将导致读取的Redis缓存是错误的数据. 2:R

  • ASP.NET性能优化之让浏览器缓存动态网页的方法

    OutputCache是针对所有访问服务器资源的用户,本篇要介绍的浏览器缓存则是针对单个用户,让浏览器在我们的控制下彻底不持续访问服务器上的动态内容,也就是我们要让浏览器变成我们的缓存机制中的一部分,在某些特定的场景下最大化地提升ASP.NET站点的性能.如果说OutputCache是从广度上提升并发效率,则浏览器缓存是从深度上提升效率. 一:HTTP头简介 1.1浏览器第一次请求 假设我们请求一个URL地址,譬如我服务器上的一个静态页面http://192.168.0.77/luminji2/

  • ASP.NET比较常用的26个性能优化技巧

    本篇文章主要介绍了"ASP.NET中常用的26个优化性能方法",主要涉及到ASP.NET中常用的26个优化性能方法方面的内容,对于ASP.NET中常用的26个优化性能方法感兴趣的同学可以参考一下. 现在很多客户也慢慢开始注重网站的性能了,同时有很多运营网站的公司也不像以前那样特别在意网站是否非常漂亮,而把更多的精力放在了网站性能优化上面,提供更快更稳定的浏览速度,在这个基础上面进行网站功能上的扩充和完善,那么在asp.net中如何优化性能呢? 1. 数据库访问性能优化 数据库的连接和关

  • ASP.NET 性能优化之反向代理缓存使用介绍

    到目前为止,我们讨论了把缓存存放在ASP.NET的输出缓存中(内存和硬盘),以及浏览器缓存中,而大型站点的另一种常用做法是将缓存部署在反向代理服务器上,这类缓存我们通常称之为反向代理缓存,比如Squid和Varnish.这两款软件通常都部署在非WINDOWS平台上,对于Windows平台上的Asp.net来说,其实一样能使用,我们完全可以把反向代理软件部署在LINUX上,然后代理会路由到后台的WINDOWS WEB(IIS)服务器.总之,非WINDOWS的世界很精彩. 当然,无论是squid还是

  • ASP.NET性能优化小结(ASP.NET&C#)

    ASP.NET: 一.返回多个数据集 检查你的访问数据库的代码,看是否存在着要返回多次的请求.每次往返降低了你的应用程序的每秒能够响应请求的次数.通过在单个数据库请求中返回多个结果集,可以减少与数据库通信的时间,使你的系统具有扩展性,也可以减少数据库服务器响应请求的工作量. 如果用动态的SQL语句来返回多个数据集,那用存储过程来替代动态的SQL语句会更好些.是否把业务逻辑写到存储过程中,这个有点争议.但是我认为,把业务逻辑写到存储过程里面可以限制返回结果集的大小,减小网络数据的流量,在逻辑层也不

  • ASP.NET性能优化之构建自定义文件缓存

    现在,借助于.NET4.0中的OutputCacheProvider,我们可以有多种选择创建自己的缓存.如,我们可以把HTML输出缓存存储到memcached分布式集群服务器,或者MongoDB中(一种常用的面向文档数据库,不妨阅读本篇http://msdn.microsoft.com/zh-cn/magazine/gg650661.aspx).当然,我们也可以把缓存作为文件存储到硬盘上,考虑到可扩展性,这是一种最廉价的做法,本文就是介绍如果构建自定义文件缓存. 1:OutputCachePro

  • ASP.NET性能优化之减少请求

    这种机制存在的性能损耗,就是服务器的ASP.NET仍旧要接收请求,处理请求.此篇所讲的机制是让浏览器自己去决定是否去读缓存,这样就彻底消灭了针对服务器的请求. 1:减少静态页面请求 要让静态页面支持这个需求,我们需要用到http头中的Cache-Control: max-age.值得注意的是Cache-Control是在HTTP/1.1协议下的标识,它是HTTP/1.0协议中的Expires的升级.为了让静态页支持Cache-Control,一种方案是在IIS中进行设置,如下,我在需要静态缓存的

  • asp.net小谈网站性能优化

    当然,网站性能优化是多方面的,这里先谈一下这些天来的所获: 1.书写代码的习惯: 再复杂的逻辑,也是从最简单的开始.在书写代码的过程中,很多不好的规范都会影响网站的性能: 以下是整理出来的些许代码习惯: 1)字符串的比较 用 string.Empty 代替 " " 2)在遍历过程中,先定义好计数变量, 再遍历, 这样会减少每次遍历就分配一次内存空间: 复制代码 代码如下: int i; for( i=0; i<100;i++) { // codeing } 3)同样的,用 Str

  • ASP.NET技巧:同时对多个文件进行大量写操作对性能优化

    我自己的一个项目,需要同时对65536个文件进行多次写操作. 如果先全部打开所有的文件,然后重复写,最后关闭所有的文件.那么第一次写操作全部完成需要16分钟左右,而第二次就需要40分钟了.没有继续测试了. for (int i = 0; i < 65536; i++)            {                fileStream[i] = new FileStream(buffDir+"\\"+ i.ToString() + ".dat", F

随机推荐