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

王朝学院·作者佚名  2009-03-27
窄屏简体版  字體: |||超大  

我通常的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[] { "" })

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航