.Net下的分布式缓存--从Discuz!NT的缓存设计谈起

  最近拜读了代振军同学写的关于Discuz!NT的缓存设计的一篇文章《Discuz!NT 缓存设计简析 [原创]》,颇有些想法,姑且写在这里让大家拍砖吧。

  缓存真是个好东西,在大型的系统中可以有效地提升系统的速度,此乃废话就不多说了,在.NET 平台下面我把缓存从功用大致分为两类,数据对象缓存和页面输出缓存. 对于数据缓存来讲是由System.Web.Caching.Cache这个类来实现,可以从上下文对象Context.Cache 来获取这个对象的引用.而页面/控件输出缓存则是由.NET环境在运行时依据头部的缓存申明来控制缓存策略. 本文主要论证与数据缓存相关的一些应用与问题.

  文中代同学提到了"无法跨Web园共享数据的问题",虽然提到解决方案就是使用XML文件来存放缓存的键值,这里有一个疑惑,就是.NET的Web园既然是进程独立的又何来共享之说呢,真要是这样的话即便是通过XML文档写入缓存键值缓存的对象也不能同时在两个进程中共享,而这里获得的好处仅是避免了在其它的进程中读到了已在当前进程中失效的“脏”缓存数据,这样的话开几个Web园就会产生几个缓存的对象对系统资源的利用系就比较低了. 如果是用Web场布署的话浪费就更多了,也许是还少有论坛达到这样的规模故不在设计能力的范围中吧.CommunityServer也是使用了这个系统对象,并对它作了一些包装形成了CommunityServer.Components.CSCache这个类,还是不错的,可以在项目中选择使用.

  基于这个类的应注实现还有EnterpriseLibrary的CacheBlock里面的NullBackingStore方式,但是为了满足多进程/服务器共程缓存数据的需求EntLib还提供了将SQL SERVER作为后端存储设备的方案,这样在性能要求不是太严,客户端连接不是太多的情况下也可以使用这种方式.只需要将EntLib 配置为共享数据库分区的工作方式即可,所有的CacheManager实例都有对缓存块的读写权,当然你也可配置为只允许一个实例写,其它的来读.

  那么还有没有更好的办法呢,其实是有的. 不过我很奇怪在.NET平台下居然没有“原生态”的分布式缓存解决方案,也许是俺孤陋寡闻吧,有哪位达人知道的请分享。还好我们有Memcached这东西,它在php平台上已经取得了巨大的成功,是优秀的分布式缓存解决方案,可以参看这篇文章 , 大型的站点上应该必不可少吧.有举的同学可以去看看, 另外还想好一个思路, 就是在EntLib的基础上作扩展实现IBackingStore 接口从BaseBackingStore派生一个实现出来,再经由Remoting或者ICE这样的分布式中间件技术应该也可以实现的类似的功能吧.

  用XML作为缓存键的存储方式倒是一个不错的想法,这样在批量移除缓存项的时候就不需要作扫描而直接得到相应的缓存键值,跟分布式缓存作一个整合应当是一个不错的方案。

  好了,让我们再回头看看Discuz!NT在页面缓存上有些什么高招.

  总的说来我是不怎么喜欢.NET2.0提供的页面输出缓存功能,主要是不能手动地控制页面缓存的过期,而使有缓存依赖项似乎也有点不爽。事实上使用数据绑定控件相对来说是比较消耗资源的,同样的数据我用StringBuilder直接拼出来输出速度要快不少,测试代码比较简单我这里就不给了,大家可以自己去测去,Discuz!NT在设计中也大量地采用了这样的方法(怪不得速度这么快呢;))。一般来讲模版被保存后后台会在ASPx目录生成对应的页面文件, 比如你有一个页面,上面需要显示一个来访者的姓名,它的伪代码看起来可能是这个样子

  模版文件内容show.html:

<html>
<body>
Hello, Your name
is <% yourname %>
</body>
</html>
生成的文件 show.ASPx
templateBuilder.AppendLine(
"<html>");
templateBuilder.AppendLine(
"<body>");
templateBuilder.AppendLine(
"Hello, Your name is " + this.yourname);
templateBuilder.AppendLine(
"</body>");
templateBuilder.AppendLine(
"</html>");

NET技术.Net下的分布式缓存--从Discuz!NT的缓存设计谈起,转载需保留来源!

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。