WEB开发网
开发学院WEB开发ASP.NET 用异步缓存确保高流量网页及时更新与低错误率 阅读

用异步缓存确保高流量网页及时更新与低错误率

 2009-03-26 17:42:15 来源:WEB开发网   
核心提示: 我通常的WEB开发中,有时我们会碰以这种情况,一个页面有很多模块组成,而这些模块之间是不关链的,就像一个网站的首页,里面有很多块块,有些是读新闻的,有些是读产品信息,还有一些部分是读论坛,博客之类的地方.而这个页面的要求是很高的,无论在什么情况下都要保证页面是可以正确打开的(当然服务器故障是没有办法的).而且网站的

  我通常的WEB开发中,有时我们会碰以这种情况,一个页面有很多模块组成,而这些模块之间是不关链的,就像一个网站的首页,里面有很多块块,有些是读新闻的,有些是读产品信息,还有一些部分是读论坛,博客之类的地方.而这个页面的要求是很高的,无论在什么情况下都要保证页面是可以正确打开的(当然服务器故障是没有办法的).而且网站的流量很大.

通常这样的页面是需要生成静态页来保证页面正确的,但是这种做法会有很大的问题,如果网站中一个小块异常了,会导致整个页面不更新.

现在我们给出这样一个解决方案:页面分两级缓存,一级为内存缓存,二级为文件缓存.这里的文件缓存是起辅助做用的,有一种特殊的情况,一个asp.net应用程序池是会重新初始化的,初始化完过后,内存数据会被清空,这个时候如果我们直接去执行数据访问程序,那么我们不能保证当时情况下程序的正确性和性能(对于程序调用过多的页面来说,执行速度慢,大量的并发请求会导致服务器崩溃).

  也就是说,对于页面程序来说,如果程序一执行会先去读内存,如果发现内存为空,那么改去读相应的缓存文件,如果文件还没生成,那么再执行程序(这种情况只在程序在服务器上第一运行是发生).

  为了确保页面更新及时,这里需要异步缓存,也就是说为每一个模块起一个线程来维护,如果线程方法执行成功,那么更新内存中的内容.这里建议把文件更新另起一个线程式,因为文件更新可以时间间隔长一起,结约系统资源.例如,每个模块内存更新速度是20秒,那么文件的可以设为5分钟.

  下面给出一段代码,这个主要是用于缓存处理的.....

 
+ expand sourceview plaincopy to clipboardPRint?
using System; 
using System.Data; 
using System.Configuration; 
using System.Linq; 
using System.xml.Linq; 
using System.IO; 
using System.Collections.Generic; 
using System.Threading; 
using System.Diagnostics; 
 
/// <summary> 
/// 本类主要负责处理根把相关参数设置缓存结果 
/// </summary> 
public class CacheSvr 
{ 
   public delegate string ProcessDataDelegate(params object[] args); 
   public static string cacheDir = "D:\tmpFile"; 
   public static Dictionary<string, string> cacheTable = new Dictionary<string, string>(); 
   public static ReaderWriterLockSlim lockx = new ReaderWriterLockSlim(); 
   public static Dictionary<string, Thread> threadTable = new Dictionary<string, Thread>(); 
 
   public CacheSvr() 
   { 
     // 
     // TODO: Add constructor logic here 
     // 
   } 
 
   #region 文件缓存逻辑 
   /// <summary> 
   /// 保存程序执行结果致文件 
   /// </summary> 
   /// <param name="thisDelegate">所要执行的方法</param> 
   /// <param name="fileName">文件名</param> 
   /// <param name="args">参数列表</param> 
   /// <returns></returns> 
   public static void saveDataFile(CacheItem item) 
   { 
     string result = item.doProcess(); 
     if (result.Length > 0) 
     { 
       write(result, item.CacheName); 
     } 
   } 
 
   /// <summary> 
   /// 写文件代码 
   /// </summary> 
   /// <param name="text">写入内容</param> 
   /// <param name="fileName">文件名</param> 
   public static void write(String text, string fileName) 
   { 
     try 
     { 
       String path = cacheDir; 
       path = path + fileName + ".cache"; 
       Stream fsc = File.Create(path); 
       fsc.Close(); 
       Stream fs = File.Open(path, FileMode.Open, Fileaccess.Write); 
       TextWriter tw = new StreamWriter(fs, System.Text.Encoding.GetEncoding(936)); 
       tw.Write(text); 
       tw.Close(); 
       fs.Close(); 
     } 
     catch 
     { 
 
     } 
   } 
 
   public static string readFile(string fileName) 
   { 
     string content = ""; 
     try 
     { 
       //Stopwatch watch = new Stopwatch(); 
       //watch.Start(); 
       String path = cacheDir; 
       path = path + fileName + ".cache"; 
       Stream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read); 
       StreamReader tr = new StreamReader(fs, System.Text.Encoding.GetEncoding(936)); 
       content = tr.ReadToEnd(); 
       //content += "\r\n <!--read from file " + path + "--> \r\n"; 
       tr.Close(); 
       fs.Close(); 
       //watch.Stop(); 
       //content = content + "<!--执行时间为:" + watch.ElapsedMilliseconds + "-->\r\n"; 
     } 
     catch 
     { 
       content = ""; 
     } 
     return content; 
   } 
   #endregion 
 
   #region 内存缓存模块 
   /// <summary> 
   /// 内存缓存 
   /// </summary> 
   /// <param name="thisDelegate">所需执行的方法</param> 
   /// <param name="cacheName">内存中的名字</param> 
   /// <param name="args">参数列表</param> 
   /// <returns></returns> 
   public static void saveDataCache(CacheItem item) 
   { 
     string result = item.doProcess(); 
     if (result.Length > 0) 
     { 
       cache(result, item.CacheName); 
     } 
   } 
 
   /// <summary> 
   /// 向内存中写入内容 
   /// </summary> 
   /// <param name="text"></param> 
   /// <param name="cacheName"></param> 
   public static void cache(string text, string cacheName) 
   { 
     lockx.EnterWriteLock(); 
     try 
     { 
       //text += "\r\n<!--缓存更新,时间为:" + DateTime.Now.ToString() + "-->\r\n"; 
       cacheTable[cacheName] = text; 
     } 
     catch { } 
     finally { lockx.ExitWriteLock(); } 
   } 
 
   public static void writelog(String text, string fileName) 
   { 
     try 
     { 
       String path = cacheDir; 
       path = path + fileName + ".cache"; 
       if (!File.Exists(path)) 
       { 
         Stream fsc = File.Create(path); 
         fsc.Close(); 
       } 
       Stream fs = File.Open(path, FileMode.Append, FileAccess.Write); 
       TextWriter tw = new StreamWriter(fs, System.Text.Encoding.GetEncoding(936)); 
       tw.Write(text); 
       tw.Close(); 
       fs.Close(); 
     } 
     catch 
     { 
 
     } 
   } 
 
   public static string readCache(string cacheName) 
   { 
     string content = ""; 
     lockx.EnterReadLock(); 
     try 
     { 
       bool result = cacheTable.TryGetValue(cacheName, out content); 
       //if (result) 
       //{ 
       //   content += "\r\n <!--read from memory--> \r\n"; 
       //} 
       return content; 
     } 
     catch 
     { 
       return ""; 
     } 
     finally 
     { 
       lockx.ExitReadLock(); 
     } 
   } 
   #endregion 
 
   #region 线程处理模块 
 
   public static void UpdateCache(object obj) 
   { 
     CacheItem thisCache = (CacheItem)obj; 
     writelog("线程:" + thisCache.CacheName + "--启动于:" + DateTime.Now.ToString() + "\r\n", "exceptions"); 
     while (true) 
     { 
       try 
       { 
         saveDataCache(thisCache); 
       } 
       catch 
       { 
 
       } 
       Thread.Sleep(thisCache.memoryTime * 1000);//内存20秒更新 
     } 
   } 
 
   public static void UpdateFile(object obj) 
   { 
     CacheItem thisCache = (CacheItem)obj; 
     while (true) 
     { 
       try 
       { 
         saveDataFile(thisCache); 
       } 
       catch 
       { 
 
       } 
       Thread.Sleep(thisCache.fileTime * 1000);//文件2分钟缓存 
     } 
   } 
 
   public static Thread getThread(string threadName) 
   { 
     Thread tmpThread = null; 
     lockx.EnterReadLock(); 
     try 
     { 
       if (threadTable.Keys.Contains(threadName)) 
       { 
         tmpThread = threadTable[threadName]; 
       } 
     } 
     catch 
     { 
     } 
     finally 
     { 
       lockx.ExitReadLock(); 
     } 
     return tmpThread; 
   } 
 
   /// <summary> 
   /// 添加缓存 
   /// </summary> 
   /// <param name="item">缓存对象</param> 
   public static void saveCache(CacheItem item) 
   { 
     string mCacheName = item.CacheName + "_memory"; 
     string fCacheName = item.CacheName + "_file"; 
     Thread memoryCache = getThread(mCacheName); 
     Thread fileCache = getThread(fCacheName); 
     if (memoryCache == null) 
     { 
       memoryCache = new Thread(new ParameterizedThreadStart(UpdateCache)); 
       memoryCache.IsBackground = true; 
       memoryCache.Start(item); 
     } 
     if (fileCache == null) 
     { 
       fileCache = new Thread(new ParameterizedThreadStart(UpdateFile)); 
       fileCache.IsBackground = true; 
       fileCache.Start(item); 
     } 
     lockx.EnterWriteLock(); 
     try 
     { 
       threadTable[mCacheName] = memoryCache; 
       threadTable[fCacheName] = fileCache; 
     } 
     catch { } 
     finally { lockx.ExitWriteLock(); } 
   } 
 
   public static string readCacheContent(CacheItem item) 
   { 
     //Stopwatch watch = new Stopwatch(); 
     //watch.Start(); 
     string content = readCache(item.CacheName); 
     if (content==null || content.Length < 0) 
     { 
       content = readFile(item.CacheName); 
       saveCache(item); 
     } 
     //读取缓存失败 
     if (content != null && content.Length <= 0) 
     { 
       //throw (new Exception("读取内容失败:" + item.CacheName)); 
       content = item.doProcess(); 
       //saveCache(item); 
     } 
     return content; 
     //watch.Stop(); 
     //content += ("\r\n<!--方法执行时间:" + watch.ElapsedMilliseconds + "-->\r\n"); 
   } 
   #endregion 
 
   #region 公共处理 
   public static string saveCache(string cacheName, ProcessDataDelegate mainMathod, object[] args) 
   { 
     using (CacheItem tmpCache = new CacheItem()) 
     { 
       tmpCache.CacheName = cacheName; 
       tmpCache.CacheDelegate = mainMathod; 
       tmpCache.CacheArgs = args; 
       string content = ""; 
       content = readCacheContent(tmpCache); 
       return content; 
     } 
   } 
   #endregion 

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Xml.Linq;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;

/// <summary>
/// 本类主要负责处理根把相关参数设置缓存结果
/// </summary>
public class CacheSvr
{
   public delegate string ProcessDataDelegate(params object[] args);
   public static string cacheDir = "D:\tmpFile";
   public static Dictionary<string, string> cacheTable = new Dictionary<string, string>();
   public static ReaderWriterLockSlim lockx = new ReaderWriterLockSlim();
   public static Dictionary<string, Thread> threadTable = new Dictionary<string, Thread>();

   public CacheSvr()
   {
     //
     // TODO: Add constructor logic here
     //
   }

   #region 文件缓存逻辑
   /// <summary>
   /// 保存程序执行结果致文件
   /// </summary>
   /// <param name="thisDelegate">所要执行的方法</param>
   /// <param name="fileName">文件名</param>
   /// <param name="args">参数列表</param>
   /// <returns></returns>
   public static void saveDataFile(CacheItem item)
   {
     string result = item.doProcess();
     if (result.Length > 0)
     {
       write(result, item.CacheName);
     }
   }

   /// <summary>
   /// 写文件代码
   /// </summary>
   /// <param name="text">写入内容</param>
   /// <param name="fileName">文件名</param>
   public static void write(String text, string fileName)
   {
     try
     {
       String path = cacheDir;
       path = path + fileName + ".cache";
       Stream fsc = File.Create(path);
       fsc.Close();
       Stream fs = File.Open(path, FileMode.Open, FileAccess.Write);
       TextWriter tw = new StreamWriter(fs, System.Text.Encoding.GetEncoding(936));
       tw.Write(text);
       tw.Close();
       fs.Close();
     }
     catch
     {

   }
   }

   public static string readFile(string fileName)
   {
     string content = "";
     try
     {
       //Stopwatch watch = new Stopwatch();
       //watch.Start();
       String path = cacheDir;
       path = path + fileName + ".cache";
       Stream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
       StreamReader tr = new StreamReader(fs, System.Text.Encoding.GetEncoding(936));
       content = tr.ReadToEnd();
       //content += "\r\n <!--read from file " + path + "--> \r\n";
       tr.Close();
       fs.Close();
       //watch.Stop();
       //content = content + "<!--执行时间为:" + watch.ElapsedMilliseconds + "-->\r\n";
     }
     catch
     {
       content = "";
     }
     return content;
   }
   #endregion

   #region 内存缓存模块
   /// <summary>
   /// 内存缓存
   /// </summary>
   /// <param name="thisDelegate">所需执行的方法</param>
   /// <param name="cacheName">内存中的名字</param>
   /// <param name="args">参数列表</param>
   /// <returns></returns>
   public static void saveDataCache(CacheItem item)
   {
     string result = item.doProcess();
     if (result.Length > 0)
     {
       cache(result, item.CacheName);
     }
   }

   /// <summary>
   /// 向内存中写入内容
   /// </summary>
   /// <param name="text"></param>
   /// <param name="cacheName"></param>
   public static void cache(string text, string cacheName)
   {
     lockx.EnterWriteLock();
     try
     {
       //text += "\r\n<!--缓存更新,时间为:" + DateTime.Now.ToString() + "-->\r\n";
       cacheTable[cacheName] = text;
     }
     catch { }
     finally { lockx.ExitWriteLock(); }
   }

   public static void writelog(String text, string fileName)
   {
     try
     {
       String path = cacheDir;
       path = path + fileName + ".cache";
       if (!File.Exists(path))
       {
         Stream fsc = File.Create(path);
         fsc.Close();
       }
       Stream fs = File.Open(path, FileMode.Append, FileAccess.Write);
       TextWriter tw = new StreamWriter(fs, System.Text.Encoding.GetEncoding(936));
       tw.Write(text);
       tw.Close();
       fs.Close();
     }
     catch
     {

   }
   }

   public static string readCache(string cacheName)
   {
     string content = "";
     lockx.EnterReadLock();
     try
     {
       bool result = cacheTable.TryGetValue(cacheName, out content);
       //if (result)
       //{
       //   content += "\r\n <!--read from memory--> \r\n";
       //}
       return content;
     }
     catch
     {
       return "";
     }
     finally
     {
       lockx.ExitReadLock();
     }
   }
   #endregion

   #region 线程处理模块

   public static void UpdateCache(object obj)
   {
     CacheItem thisCache = (CacheItem)obj;
     writelog("线程:" + thisCache.CacheName + "--启动于:" + DateTime.Now.ToString() + "\r\n", "exceptions");
     while (true)
     {
       try
       {
         saveDataCache(thisCache);
       }
       catch
       {

     }
       Thread.Sleep(thisCache.memoryTime * 1000);//内存20秒更新
     }
   }

   public static void UpdateFile(object obj)
   {
     CacheItem thisCache = (CacheItem)obj;
     while (true)
     {
       try
       {
         saveDataFile(thisCache);
       }
       catch
       {

     }
       Thread.Sleep(thisCache.fileTime * 1000);//文件2分钟缓存
     }
   }

   public static Thread getThread(string threadName)
   {
     Thread tmpThread = null;
     lockx.EnterReadLock();
     try
     {
       if (threadTable.Keys.Contains(threadName))
       {
         tmpThread = threadTable[threadName];
       }
     }
     catch
     {
     }
     finally
     {
       lockx.ExitReadLock();
     }
     return tmpThread;
   }

   /// <summary>
   /// 添加缓存
   /// </summary>
   /// <param name="item">缓存对象</param>
   public static void saveCache(CacheItem item)
   {
     string mCacheName = item.CacheName + "_memory";
     string fCacheName = item.CacheName + "_file";
     Thread memoryCache = getThread(mCacheName);
     Thread fileCache = getThread(fCacheName);
     if (memoryCache == null)
     {
       memoryCache = new Thread(new ParameterizedThreadStart(UpdateCache));
       memoryCache.IsBackground = true;
       memoryCache.Start(item);
     }
     if (fileCache == null)
     {
       fileCache = new Thread(new ParameterizedThreadStart(UpdateFile));
       fileCache.IsBackground = true;
       fileCache.Start(item);
     }
     lockx.EnterWriteLock();
     try
     {
       threadTable[mCacheName] = memoryCache;
       threadTable[fCacheName] = fileCache;
     }
     catch { }
     finally { lockx.ExitWriteLock(); }
   }

   public static string readCacheContent(CacheItem item)
   {
     //Stopwatch watch = new Stopwatch();
     //watch.Start();
     string content = readCache(item.CacheName);
     if (content==null || content.Length < 0)
     {
       content = readFile(item.CacheName);
       saveCache(item);
     }
     //读取缓存失败
     if (content != null && content.Length <= 0)
     {
       //throw (new Exception("读取内容失败:" + item.CacheName));
       content = item.doProcess();
       //saveCache(item);
     }
     return content;
     //watch.Stop();
     //content += ("\r\n<!--方法执行时间:" + watch.ElapsedMilliseconds + "-->\r\n");
   }
   #endregion

   #region 公共处理
   public static string saveCache(string cacheName, ProcessDataDelegate mainMathod, object[] args)
   {
     using (CacheItem tmpCache = new CacheItem())
     {
       tmpCache.CacheName = cacheName;
       tmpCache.CacheDelegate = mainMathod;
       tmpCache.CacheArgs = args;
       string content = "";
       content = readCacheContent(tmpCache);
       return content;
     }
   }
   #endregion
}

 
现在给一个使用的例子:
 

view plaincopy to clipboardprint?
   #region 广告下文字链 
   public static string getTopAdList(params object[] args)  
   { 
     BeanOper oper = new BeanOper(); 
     StringBuilder result = new StringBuilder(); 
     result.Append("<div class=\"ad1\">"); 
     result.Append("<ul>"); 
     result.Append(oper.getAdNewsHtml(3519, 1, 9, "ad1_")); 
     result.Append("</ul>"); 
     result.Append("<div class=\"clear\"></div>"); 
     result.Append("</div>"); 
     return result.ToString(); 
   } 
   #endregion 
 
CacheSvr.saveCache("TopAdList", new CacheSvr.ProcessDataDelegate(IndexHtml.getTopAdList), new object[] { "" }) 

Tags:异步 缓存 确保

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接