网站优化之页面级缓存方案

用缓存来优化网站性能的方法,估计是无人不知的。 ASP.NET提供了HttpRuntime.Cache对象来缓存数据,也提供了OutputCache指令来缓存整个页面输出。 虽然OutputCache指令使用起来更方便,也有非常好的效果, 不过,它需要我们在那些页面中添加这样一个指令。

对于设置过OutputCache的页面来说,浏览器在收到这类页面的响应后,会将页面响应内容缓存起来。 只要在指定的缓存时间之内,且用户没有强制刷新的操作,那么就根本不会再次请求服务端, 而对于来自其它的浏览器发起的请求,如果缓存页已生成,那么就可以直接从缓存中响应请求,加快响应速度。 因此,OutputCache指令对于性能优化来说,是很有意义的(除非所有页面页面都在频繁更新)。

在网站的优化阶段,我们可以用Fiddler之类的工具找出一些内容几乎不会改变的页面,给它们设置OutputCache, 但是,按照传统的开发流程,我们需要针对每个页面文件执行以下操作:

方式一、使用ASP.NET平台提供的OutputCache(运行时内存)机制

实现方式:

  1. 为列表页配置输出缓存声明;
  2. 根据页面不同的查询参数缓存不同的页面
    1. E.g.同样是列表页,分类1页面:http://www.wedn.net/cat/1/和 分类二页面:http://www.wedn.net/cat/2/分别缓存成不同的缓存对象

优点:

  1. 配置简单、
  2. 不侵入原本系统、
  3. 访问速度非常快(因为是将执行结果缓存到内存)

缺点:

  1. 占用资源比较多,无法缓存所有的页面。
  2. 另外有个问题:没有解决使用时间长了以后访问缓存速度变慢;

方式二、同样使用ASP.NET平台提供的OutputCache(自定义Provider)机制

实现方式:

  1. 开发自定义Provider程序提供给ASP.NET调用去存取输出缓存;
  2. 其余同方式一

优点:

  1. 可以自主控制缓存读写、
  2. 不侵入原有系统、
  3. 访问快

缺点:

  1. 配置相对复杂、
  2. 需要开发Provider
  3. 需要额外的资源(分布式缓存)

附:

自定义OutputCacheProvider实现将输出缓存放到分布式缓存中

实现原理:

实现方式:

  1. 实现抽象基类OutputCacheProvider的增删方法;
  2. 附上大概的代码(简单的通过文件读写、JSON序列化和二进制序列化实现),思路仅供参考:
OutputCacheProvider
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Diagnostics;
  4 using System.IO;
  5 using System.Linq;
  6 using System.Runtime.Serialization.Formatters.Binary;
  7 using System.Security.Cryptography;
  8 using System.Text;
  9 using System.Web.Caching;
 10 using Micua.Utility;
 11 namespace Micua.UI.Cache
 12 {
 13     public class MicuaOutputCacheProvider : OutputCacheProvider, IDisposable
 14     {
 15         readonly IList<CacheItem> _cacheItems;
 16         public MicuaOutputCacheProvider()
 17         {
 18             if (File.Exists("z:\\cache.json"))
 19             {
 20                 var json = File.ReadAllText("z:\\cache.json");
 21                 _cacheItems = JsonHelper.Deserialize<List<CacheItem>>(json) ?? new List<CacheItem>();
 22             }
 23             else
 24             {
 25                 _cacheItems = new List<CacheItem>();
 26             }
 27         }
 28         public override object Get(string key)
 29         {
 30             Debug.WriteLine(string.Format("Cache.Get({0})", key));
 31             key = MD5(key);
 32             var cacheItem = _cacheItems.FirstOrDefault(c => c.Id == key);
 33             if (cacheItem != null)
 34             {
 35                 if (cacheItem.Expiration.ToUniversalTime() <= DateTime.UtcNow)
 36                 {
 37                     _cacheItems.Remove(cacheItem);
 38                 }
 39                 else
 40                 {
 41                     return Deserialize(cacheItem.Item);
 42                 }
 43             }
 44             return null;
 45         }
 46         public override object Add(string key, object entry, DateTime utcExpiry)
 47         {
 48             Debug.WriteLine("Cache.Add({0}, {1}, {2})", key, entry, utcExpiry);
 49             key = MD5(key);
 50             if (utcExpiry == DateTime.MaxValue)
 51                 utcExpiry = DateTime.UtcNow.AddMinutes(5);
 52             var item = _cacheItems.FirstOrDefault(c => c.Id == key);
 53             if (item != null)
 54             {
 55                 if (item.Expiration.ToUniversalTime() <= DateTime.UtcNow)
 56                 {
 57                     _cacheItems.Remove(item);
 58                 }
 59                 else
 60                 {
 61                     SaveChange();
 62                     return Deserialize(item.Item);
 63                 }
 64             }
 65             _cacheItems.Add(new CacheItem
 66             {
 67                 Id = key,
 68                 Item = Serialize(entry),
 69                 Expiration = utcExpiry
 70             });
 71             SaveChange();
 72             return entry;
 73         }
 74         public override void Set(string key, object entry, DateTime utcExpiry)
 75         {
 76             Debug.WriteLine("Cache.Set({0}, {1}, {2})", key, entry, utcExpiry);
 77             key = MD5(key);
 78             var item = _cacheItems.FirstOrDefault(c => c.Id == key);
 79             if (item != null)
 80             {
 81                 _cacheItems.Remove(item);
 82                 item.Item = Serialize(entry);
 83                 item.Expiration = utcExpiry;
 84                 _cacheItems.Add(item);
 85             }
 86             else
 87             {
 88                 _cacheItems.Add(new CacheItem
 89                 {
 90                     Id = key,
 91                     Item = Serialize(entry),
 92                     Expiration = utcExpiry
 93                 });
 94             }
 95             SaveChange();
 96         }
 97         public override void Remove(string key)
 98         {
 99             Debug.WriteLine("Cache.Remove({0})", key);
100             key = MD5(key);
101             _cacheItems.Remove(_cacheItems.FirstOrDefault(c => c.Id == key));
102             SaveChange();
103         }
104         private static string MD5(string value)
105         {
106             var cryptoServiceProvider = new MD5CryptoServiceProvider();
107             var bytes = Encoding.UTF8.GetBytes(value);
108             var builder = new StringBuilder();
109             bytes = cryptoServiceProvider.ComputeHash(bytes);
110             foreach (var b in bytes)
111                 builder.Append(b.ToString("x2").ToLower());
112             return builder.ToString();
113         }
114         private static byte[] Serialize(object entry)
115         {
116             var formatter = new BinaryFormatter();
117             var stream = new MemoryStream();
118             formatter.Serialize(stream, entry);
119             return stream.ToArray();
120         }
121         private static object Deserialize(byte[] serializedEntry)
122         {
123             var formatter = new BinaryFormatter();
124             var stream = new MemoryStream(serializedEntry);
125             return formatter.Deserialize(stream);
126         }
127         private void SaveChange()
128         {
129             var json = JsonHelper.Serialize(_cacheItems);
130             File.WriteAllText("z:\\cache.json", json);
131         }
132         public void Dispose()
133         {
134             var json = JsonHelper.Serialize(_cacheItems);
135             File.WriteAllText("z:\\cache.json", json);
136         }
137     }
138 }

 

 
posted @ 2014-01-02 21:52  汪磊  阅读(1521)  评论(0编辑  收藏  举报