欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-06 17:30:56
在网站的开发过程中,经常碰到的一类需求场景是: 1:页面含热点新闻,热点新闻部分需要10分钟更新一次,而整个页面的其它部分1天内都不会变动; 2:首页的某个banner需要...
在网站的开发过程中,经常碰到的一类需求场景是:

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区域,会实时刷新。
参考(第一小节大部分来自参考文字):

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