动网论坛缓存技术研究

发布时间:2014-10-25 2:24:32
来源:分享查询网

     动网论坛算是国内比较著名的一款论坛.从DVBBS7.0版本开始,动网重构了代码核心,采用缓存机制,程序和模板完全分离,在代码质量,权限等级,用户体验方面算是一个里程碑的作品了.虽然从7.0到现在的8.2,每一个阶段动网论坛都爆出了较大的漏洞(主要是上传和注入漏洞,7.0的欺骗上传漏洞使动网一度瘫痪),抛开这些,动网确实是一个不错的软件作品,我们可以从中学习到很多编程处理技巧.纵观现在市场上的一些web软件产品,都或多或少带有动网代码的影子.      由于工作上的需要,我于2005年开始研究动网7.0的代码,长时间的接触使我一度对代码熟悉起来,可以肯定的说,现在我对动网7.0的代码熟悉程度在95%以上.动网7.0最大的特点就是采用独有的缓存机制,这种缓存机制到现在还在被很多web产品在使用.下面我谈谈动网的缓存机制的理解.      缓存就是将用户频繁访问的数据放到内存中,二次访问时从内存中读取,而不需要频繁的访问硬盘,加快了数据处理速度,同时也减轻了服务器的访问压力. 那么什么样的情况下使用缓存呢?使用缓存首要的原则就是数据对所有用户来说具有共享性,说得具体点,就是每个用户浏览的页面结果都是一样的,不会是用户甲浏览的是一个页面结果,其他用户浏览又是一个结果.相同的效果才能使数据对所有用户具有较好的共享.当然,不同用户浏览出现不同效果也可以用缓存,但是这种缓存会使服务器具有内存崩溃掉,不推荐使用.举个简单的例子.网站首页的新闻头条,这些新闻总是从数据库中提取最新的几条,对所用用户,其显示结果都是一样的,所有用户浏览都是相同的结果,因此可以使用缓存.如果查询新闻信息,不同的用户查询可以查询到不同的信息结果,这里就不推荐使用缓存.      动网采用如下几种缓存:      1.数组缓存,采用getrows函数,将数据表字段置入一个二维数组中,通过数组下标遍历调用.如下面实例代码:   Set Rs=Dvbbs.Execute("Select         TopicID,boardid,title,postusername,postuserid,dateandtime,child,hits,votetotal,lastpost,lastposttime,istop,isvote,is best,locktopic,Expression,TopicMode,Mode from dv_topic Where istop>0 and TopicID in ("&Forum_AllTopNum&") Order By istop desc, Lastposttime Desc")'执行SQL语句    If Rs.Eof And Rs.Bof Then'执行不成功时,Forum_AllTopNum = 0       Forum_AllTopNum = 0    Else     SQL=Rs.GetRows(-1)'就是这里,这里最关键,将以上数据表字段置入二维数组中     For i=0 To Ubound(SQL,2)'数组下标遍历       Showtitle=SQL(2,i)'赋值                 Next     End If     2.调用缓存类,这个缓存类代码非常精简,非常不错.     具体解释如下 '下面是dvbbs缓存模块,从dvbbs7.0开始,动网开始使用缓存机制,到SQL8.2版本,动网缓存机制使用更上一层楼,结合Application,采 用xml缓存.个人认为,动网的缓存机制值得学习 Public Property Let Name(ByVal vNewValue)'定义Name属性,此处Name属性主要是缓存Name,不同的缓存有不同的Name,此 Name是自定义的.个人认为,Name主要起一个标记作用,因为缓存数量过多的话,主要是靠Name来识别.Name就像房间号一样,对号入座.   LocalCacheName = LCase(vNewValue)'将传递参数转换成小写 End Property Public Property Let Value(ByVal vNewValue)'定义Value属性,此处Value属性是指写入缓存的Value,后面着重介绍   If LocalCacheName<>"" Then'LocalCacheName不为空    Application.Lock'锁定,其他人无法写入    Application(CacheName & "_" & LocalCacheName &"_-time")=Now()'将now函数写入Application中    Application(CacheName & "_" & LocalCacheName) = vNewValue'将参数vNewValue写入Application中    Application.unLock'解锁,共享缓存   End If End Property Public Property Get Value()'定义一个类的属性,该属性返回Value的值   If LocalCacheName<>"" Then  '判断条件,也就是缓存名不为空,每一个缓存有一个Name值,才能执行下面语句     Value=Application(CacheName & "_" & LocalCacheName)'将缓存的内容赋给Value   End If End Property Public Function ObjIsEmpty()'此函数是判断缓存对象是否过期,有一个返回值ObjIsEmpty,初始值为False   'Response.Write DateDiff("s",CDate(Application(CacheName & "_" & LocalCacheName &"_-time")),Now())&" 秒"   ObjIsEmpty=False'返回值初始化   If  IsDate(Application(CacheName & "_" & LocalCacheName &"_-time")) Then'用IsDate函数判断缓存中的 now()是否转换成日期    If DateDiff("s",CDate(Application(CacheName & "_" & LocalCacheName &"_-time")),Now()) > (60*Reloadtime) Then ObjIsEmpty=True'缓存是否过期判断,主要是和Now进行比较,得到一个返回值   Else    ObjIsEmpty=True   End If   If ObjIsEmpty Then RemoveCache()'过期了,是否缓存 End Function Public Sub RemoveCache()'是否缓存对象   Application.Lock'锁定   Application.Contents.Remove(CacheName & "_" & LocalCacheName)'释放缓存数据   Application.Contents.Remove(CacheName & "_" & LocalCacheName &"_-time")'释放缓存的时间   Application.unLock'解锁 End Sub 3.xml缓存机制 这种xml机制在7.1以后版本中用到,通过建立xml节点,并将这些节点共享.具体要参考xpath语法. 首先是建立一个xml根节点,并通过缓存类将这个根节点缓存起来,根节点建好后再建立根结点的子节点,建立好字节点后,通过执行SQL语句对子节点赋值(赋值还是数据表的字段内容),那么就可以在其他页面重复使用数据表中字段值了.举个例子: Set UserSession = RecordsetToxml(rs,"userinfo","xml")'建立根结点,这里用函数封装了   UserSession.documentElement.selectSingleNode("userinfo/@cometime").text=Now()'赋值   UserSession.documentElement.selectSingleNode("userinfo/@activetime").text=DateAdd("s",-3600,Now())'时间赋值   UserSession.documentElement.selectSingleNode("userinfo/@boardid").text=boardid说明一下,为什么要将用户所有字段内容缓存起来呢?因为缓存起来后将用户资料置入内存中,下次需要取出用户资料时直接从内存中读取,不需要读取数据库,减轻了数据库的压力. 因为涉及倒用户资料的页面太多了,如果每个页面的用户资料都从数据库中读取,频繁的反问会造成IIS假死.下面说说RecordsetToxml函数的作用,该函数建立后,整个论坛都在调用,重用性很强.Public Function RecordsetToxml(Recordset,row,xmlroot)'row是行节点,xmlroot是根节点  Dim i,node,rs,j,DataArray'定义变量  If xmlroot="" Then xmlroot="xml"'xml为空时,xmlroot设置默认值,这里为xml  If row="" Then row="row"'同上  Set RecordsetToxml=Dvbbs.CreateXmlDoc("msxml2.FreeThreadedDOMDocument"& MsxmlVersion)'创建自由线程XMlDOM对象,这种格式是固定的,不用怕,呵呵  RecordsetToxml.appendChild(RecordsetToxml.createElement(xmlroot))'创建根节点了  If Not Recordset.EOF Then'布尔值判断,此处是为真,能执行通过的话,执行如下语句   DataArray=Recordset.GetRows(-1)'哈哈,这里又用到缓存数组   For i=0 To UBound(DataArray,2)'缓存数组下标遍历    Set Node=RecordsetToxml.createNode(1,row,"")'建立行节点,什么是行节点,这要看看xml格式,呵呵,一看就知道了    j=0    For Each rs in Recordset.Fields       node.attributes.setNamedItem(RecordsetToxml.createNode(2,LCase(rs.name),"")).text= DataArray(j,i)& ""'这里是建立根节点的子节点       j=j+1'循环    Next    RecordsetToxml.documentElement.appendChild(Node)'子节点赋值   Next  End If  DataArray=NullEnd Function当然,缓存要合理利用,因为它是牺牲服务器的内存为代价,过多的使用缓存会造成内存大量消耗. 缓存每隔一段时间要释放出来,一般有自动释放和手动释放.自动释放是到了一定时间,程序自动释放被占用的内存.手动释放需要在后台进行管理.

返回顶部
查看电脑版