在大型web架构的承载能力瓶颈往往在数据库这里,最难的就是对数据库的优化,在数据库层面可以采用加索引,分库,分表,主从复制等等都是为了减少数据库压力,那么在程序层面主要两种方式来解决这个问题,就是生成静态和后端http cache 缓存,当然也有数据表缓存,不过这个不是本章讨论重点,下面就生成静态和后端http cache做一个比较。
实现原理
生成静态:
是在新内容发布的同时就立刻生成相应内容的静态页面,比如:2003年3月22日,管理员通过后台内容管理界面录入一篇文章后,就立刻生成/tech/2003/03/22/001.html这个静态页面,并同步更新相关索引页上的链接。
生成静态的技术主要两种:
1、模板替换技术,通过把静态html中的标签通过正则替换为后台输出数据,然后另存为html文件。
2、访问时动态生成,比如访问/tech/2003/03/22/001.html这个文件,对应动态地址是:?table=tech&id=1,那么在没有静态文件情况下可以先访问?table=tech&id=1,然后再访问同时来生成/tech/2003/03/22/001.html,第二次访问时候由于已经生成了静态,直接访问静态页面即可,这个可以在表中增加一个字段(如:IsHtml)来保存是否生成静态,前端根据这个字段来决定输出url地址类型。
这两种方式大家可以自己选。
动态缓存:
是在新内容发布以后,并不生成相应的静态页面,直到对相应内容发出请求时,如果浏览器中找不到相应缓存,就向后台内容管理服务器发出请求,这时服务器端有两种情况
1、如果后端的HTTP Cache有当前页面的缓存,而且没有过期,那么会直接从httpcache中输出并在浏览器显示。
2、如果后端的HTTP Cache没有当前页面的缓存,那么页面就会和普通动态页面一样,请求数据库,加载后端脚本,然后输出浏览器,输出同时会把当前页面加入到HTTP Cache中,下面我项目中用到的一个http缓存过滤器,用的是Net Mvc的过滤器实现,代码如下:
public override void OnActionExecuted(ActionExecutedContext filterContext) { double duration = 30; //此参数可以自己写到配置文件中,这里仅演示 if (filterContext.Exception != null) { return; //如果出现http错误则不进行缓存 } HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache; cache.VaryByHeaders["host"] = true;//域名不同时采用缓存不同 //cache.VaryByHeaders["User-Agent"] = true;//浏览器设备不一样时候缓存也不一样,如微信浏览器和pc浏览器 //cache.SetVaryByCustom("CustomName"); //自定义缓存,在global.aspx中重写GetVaryByCustomString TimeSpan cacheDuration = TimeSpan.FromSeconds(duration);//单位秒 cache.SetCacheability(HttpCacheability.Public); cache.SetExpires(DateTime.Now.Add(cacheDuration)); cache.SetMaxAge(cacheDuration); cache.AppendCacheExtension("must-revalidate, proxy-revalidate"); }
十年前我会推荐采用静态技术,那时候硬件不发达,内存也不算便宜,但是现在我推荐大家用http cache缓存,下面说说静态缓存缺点
静态缓存的缺点:
生成静态必须人工干预:比如首页调用文章,栏目也调用了文章,专题页也调用了文章,那么在第一次更新静态的时候,首页、栏目、专题页也要同步更新,这种我暂时没有什么好的办法判断到底哪些页面调用这篇文章,所以我的解决办法就是:后台手工生成,而http cache只需要清理缓存或增加自动过期时间即可解决。