今天写的---ASP缓存类
一、何谓 ASP 缓存 / 为什么要缓存
可能感觉到 asp 动态网页技术带来的便利性,当你 web 站点采用 asp 技术建立的初期。以及随意修改性、自如的 http 控制。但是随着访问量的增加,一定会发现自己的站点访问速度越来越慢, IIS 重新启动得越来越频繁。接下来,一定想优化 asp 诸如更换性能更优异的数据库、建立索引、编写存储过程等等。这些措施有些不需要增加利息压力,有些则利息压力很大(譬如丛 access SQL 而且效果还不一定。
认为最经济的方法是利用缓存优化技术来实现缓解 web 服务压力。 面对 web 访问压力。
Web 访问量增加通常意味着以下资源需求的快速增长:
需要消耗更多的 CPU 处置网络流量和网络 I/O 线程。 1 网卡流量增加。
2 需要更频繁的打开 / 关闭数据库连结(如果使用数据库技术 — 通常 asp 都会采用数据库作为数据存储)严重消耗资源的事物数量、以及事务相互竞争资源引起的死锁、会增加网络 I/O 或者 CPU 消耗。
IIS 为了维持状态,3 如果采用 session 话。会消耗更多内存,而内存消耗可能会引发物理内存不够,引起物理内存同辅存间的频繁交换,从而引起代码执行的停顿, web 响应阻滞。
会引起网页访问故障,4 由于访问的不到及时响应。导致用户刷新,从而加剧 CPU 内存等资源需求。
考虑通常的 web 应用顺序,实际上。很多时候的动态代码执行是不必要的
二、 asp 缓存的分类
asp 缓存可以分为两类: 擅自总结。
1 文件缓存
就是根据逻辑判断,所谓文件缓存。一段时间内某个 asp 特定执行将不会有很大的变化,因而将内容以静态 html 形式存放,然后以 web 重定向技术让客户端访问静态文件,以达到减少 CPU 数据库资源等的需求。这样的应用很多,譬如很多论坛就是回复贴子的时候将整个贴子重新生成一个静态文件,然后进行重定向的例如 donews.com 论坛。该成静态还有一个副作用(好处) -- 可以很容易被 googl 等搜索引擎收录。一些所谓新闻发布系统的都采用了此技术。
2 文件片断缓存
也是基于逻辑判断,所谓文件缓存。某部分数据(通常是需要消耗资源的大容量数据库查询取得)一定时间内不会改变,所以我可以将这些数据利用文件的形式进行存储,当需要时候,可以通过读取文件来获取数据,防止增加数据库的负担。例如,通常将一些数据以 xml 格式存储,然后利用 xslt 技术实现显示( xml 处置通常需要大量 CPU 资源,所以通常是 IE 直接读取 xml 客户端在客户的 CPU 上进行处理) 优快云 论坛就是这样处置的
3 主存缓存
还可以考虑在内存中处理缓存,除此之外。将需要及时响应的内容存储在内存中,一旦访问需求,立即从快速的贮存中输送出去。如果极大量的访问需求集中在几个少量的页面或者主存足够多,想采用主存缓存一定可以大幅度提高 web 访问性能。
三、如何实现 / 使用缓存
实现缓存需要考虑以下问题:
1 哪些页面会在短时间内不会改变?
这样的页面很多。譬如一个站点通常都有新闻资讯类的栏目,分析自己的站点。这些栏目通常都是站点维护人员在一天的某个时间发布资料,之后很少改动页面。那么这些页面就适合于采用静态文件缓存。实际上,所谓新闻发布系统就是这么做的那么那也可以参考这些系统的思想改造自己的原有动态 asp 页面。
2 那些页面针对全部访问者都采用同一个逻辑生成(也就是不区分访问者)
论坛等消耗资源的应用一般也可以设计成统一逻辑生成(同一个贴子,除了新闻资讯之类的栏目所有访问者都看一个界面外。张三李四看的都一样)针对这类应用页面我也可以采用静态缓存来实现。也可以考虑将数据片断化,利用脚本技术在服务器处置能力之外也就是客户端浏览器进行处置。
3 采用缓存的代价和收获。
使之提高 web 服务器响应能力,主要就是空间换(响应)时间 ” 利用缓存技术将之后频繁需要的内容进行预处理。更重要赢得访问者的欢心。
同时又可能影响到访问效果。 代价就是 web 空间需求增加。
利大于弊的 但我认为适当的缓存。
4 那些地方不适宜采用缓存
每个人的查询内容不一样,动态查询页面。所以显示结果不大一样,所以不大可能将查询结果生成缓存,所以采用缓存较为复杂且缓存利用率底下,造成管理利息上什(假设你缓存了 1000 个查询关键字,那么管理这些关键字同缓存的对应也是麻烦事)
四、实例分析
假设一个建议论坛的原有布局如下:
根目录下:
一般是精华、推荐之类 default.asp 首页。
如果携带参数 MainBID 就表示要列出板块下的栏目 listBorad.asp 该文件列出全部分栏目的名称和介绍。
携带 MainBID 表示列出某块的全部贴子。如果携带 subBID 表示列出具体栏目的贴子。如果携带 page 参数表示分页列出主题。 listThread.asp 该文件如果不携带任何参数表示列出全部的贴子。
任意跟贴全部列在后面。 ID 参数为要显示的贴子。 ViewThread.asp 列出某个贴子内容。假设贴子显示为一个发言。
携带参数 Id 回应某个贴子 Reply.asp 回应某个贴子。
其它暂不讨论。
可以看到如果全部是采用原始的 ASP/PHP 来做, 以上。那几乎每一个 asp 文件的执行都需要数据库操作,频繁的查询,多表查询。要知道查询数据库最终会带来性能的下降,响应速度下降,带给访问者缓慢的浏览影响,有利于 web 质量。更重要的对于甲乙两个人来将,访问 ViewThread.asp 之类的如果 ID 一致,那么很多时候他会看到同样的内容(浏览器收到 HTML 代码几乎一样)但是为了这 “ 同样的内容 ” 服务器需要打开数据库连结、查询,读取纪录,显示,关闭纪录、数据库连结。以下列的消耗服务器资源的操作,如果是更多的人来访问,最终的结果是这些人加剧消耗服务器资源。实际上,这些为了同样的内容 ” 所做的重复劳动是可以利用缓存技术进行优化防止的譬如:
立即调用生成静态的功能, reply.asp 提交内容后。将整个贴子内容存储为 viewThread_xxxx.htm 之类的静态 html 文件,再通常情况下访问 viewThread.asp?ID=xxxx 时候,系统自动 redirect 对应的静态文件 viewThreadxxxx.htm 去。这样,当一个贴子没有最新发布时候,始终是静态内容提供给浏览者;一旦有了新的提交,将会更新到静态文件中去,这样,将会节省很多次数据库操作,大大提高响应速度。
将缓存文件名设定为 listBoard_xx.htm 增加新的栏目时候进行更新 listBoard_xxx.htm listThread.asp 也类似, listBorad.asp 也可以实施静态化。可以分析其可能携带的参数。只不过由于其参数更多,所以缓存文件也会很多。击若要缓存 listThread.asp? subBID=xxx&page=2 那么对应的静态文件是 listThread_xxx_p2.htm default.asp 也一样。
那么如何判断什么时候更新?什么时机更新?
最终重定向到此静态文件。注意, 讨论 listThread.asp? subBID=xxx&page=2 执行 listThread.asp 俄时候提取 subID 和 page 然后探测 listThread_xxx_p2.htm 否存在如果不存在就调用静态生成功能进行生成该文件。此处的不存在就意味着呈现了新的内容需要我进行更新。
那如何造成文件不存在呢?删除。发表一个新的贴子、删除贴子、移动贴子的时候我可以将类似 listThread_xxx_p2.htm 之类的静态文件全部删除。这样就通知了何时要进行缓存。
如何生成静态文件? 现在还剩下一个问题。
取名为 default_d.asp listThread_2.asp 且在同一个目录中(理论上 listThtrad.asp?subID=123 同 LISTtHREAD_D.ASP?SUBID=123 访问结果会是同样的内容)这样我需要生成静态文件的逻辑中, 注意到之前我提到同样的内容 ” 可以将改造前的 default.asp listThread.asp 等拷贝一个副本。通过 WEB 访问请求的方式调用改造前的副本,得到 html 代码,并存储为静态文件。这个 web 请求实际上相当于在任何真实浏览者访问静态内容之前,由服务器自身现观察将会输出的 html 然后返回这些代码,利用文件操作功能存储为静态文件。这样,缓存文件就在真正浏览者之前被创建。
几乎不会造成因为改造呈现 404 之类的错误。其次, 这样的方案几乎不触动原来的布局。静态文件也会帮助你站点容易被被 googl 之类的搜索引擎收录。何乐而不为?
提醒,最后。通过 web 访问, asp 编程环境下,很多人采用 xmlHTTP 组件访问,这会造成很多问题。 xmlhttp 自身会 cach 请求的资源,导致我通过此组件请求得到内容不是最新的造成逻辑上的混乱。所以,应当选择 xml Server http 对象或者 winhttp 组件来实现 web 请求资源。
其实这些实现方法是非常的简单,使用 ASP 中的缓存技术可以很大水平上提高你网站性能。将说明如何在服务器上的缓存是如何工作以及你如何使用一种被称为断开连接的 ADO 连接技术。
介绍这些技术之前先说明一下到底什么是 ASP 缓存技术。
使用缓存你就不用频繁的访问你保管在硬盘上的数据了灵活的使用缓存你就免去了心疼的看着可怜的硬盘饱受读数据时的折磨了当你一旦执行了一个查询动作,所谓缓存其实就是内存中开辟一个用来保存数据的空间。并且将查询结果放入缓存中后,就可以很迅速的重复访问这些数据了而如果你不把数据放入缓存的话,当你再次执行这个查询时,服务器会将进程耗费在从数据库中获取并排序上了
再次查询时耗费的时间主要是显示数据的时间上了 当数据保存在缓存中时。
不应该把经常需要改变的数据放到服务端的缓存中,也就是说。应该把改变少,但是又需要经常访问的数据放到缓存中。
过会再讨论 ASP 如何在客户端使用 现在先讨论 ASP 服务端使用缓存的技术。
缓存的技术。
就可以考虑使用服务端的缓存技术了这种技术尤其适用于那些显示风格一致性比较强的网站(呵呵,当你有大量的数据(静态的就是说变化比较少的需要显示给客户端时。对于非主流的网站可不好用的说。
大家只要看看下面这个简单的例子就明白了 其实实现方法特别的简单。
这是一个用来显示书籍分类的例子顺序
DisplayBooks.ASP 文件:
< %@ LANGUAGE=JavaScript % >
< html >
< bodi >
< form method=post >
书籍分类; < %= getBooksListBox % >
< p>
< input type=submit >
< %
function getBooksListBox
{
BooksListBox = Applicat "BooksListBox"
if BooksListBox != null return BooksListBox;
10 crlf = String.fromCharCod 13.
BooksListBox = "< select name=Books>" + crlf;
SQL = "Select * FROM Book orDER BY Name";
cnnBook = Server.CreateObject "ADODB.Connection" ;
"Admin",cnnBooks.Open "Books"."" ;
rstBook = cnnBooks.Execut SQL ;
fldBookNam = rstBook "BookName" ;
while !rstBooks.EOF {
BooksListBox = BooksListBox + " < option>" +
fldBookNam + "" + crlf;
rstBooks.MoveNext ;
}
BooksListBox = BooksListBox + ""
Applicat "BooksListBox" = BooksListBox
return BooksListBox;
}
% >
其实就是用了很简单的 Applicat 技术,很简单把。而且就一句话的不同:
Applicat "BooksListBox" = BooksListBox
例如你一天(或则很长时间)只更新一次。 可以验证一下你就会发现服务器上的请求数量会降低不少的这种情况尤其适合与那些更新不是很频繁的网站内容。
听上去怎么这么别扭)这种技术主要使用在用来保管用户个人信息,下面再讨论一种客户端的缓存技术这种技术也叫断开连接的 ADO 连接技术(翻译水平太次。例如用户的密码,代号等等上面。主要使用了 ADO 一些属性。同时也回答了一些网友曾经提到过的能否在 Applocat 中使用 ADO 对象的问题。解释不清楚,下面让代码来发言:
文件 GLOBAL.ASA
< !--METADATA TYPE="TypeLib" FILE="C:/Program Files/Common
Files/system/ado/msado15.dll"-- >
< SCRIPT LANGUAGE=VBScript RUNAT="Server" >
Sub Application_OnStart
Password FROM UserInfo" SQL = "Select UserName.
cnnUser = "DSN=User"
Set rsUser = Server.CreateObject "ADODB.Recordset"
就是用来实现那个叫可用的断开连接的 ADO 技术 ' 注意下面这两句话。
rsCustomers.CursorLoc = adUseCli
cnnAdvWorks,rsCustomers.Open SQL. adOpenStatic, AdLockReadOnli
' 断开 RecordSet 和数据库的连接
rsCustomers.ActiveConnect = Noth
Set Applicat "rsCustomers" = rsCustom
End Sub
文件 Users.ASP
< %
'Clone 方法使得每个用户拥有自己的一个 RecordSet 集合
Set yourUser = Applicat "rsUsers" .Clone
Set UserNam = yourUser "UserName"
Set Password = yourUser "Password"
Do Until yourUsers.EOF
% >
用户姓名: < %= UserNam % > 用户密码: < %= Password % >
< %
yourUsers.MoveNext
Loop
% >
想我也不用再多说了作用已经很明显,至于缓存的作用。特别是对于信息量非常大或是全数据库页面的网站,能很好地利用主机的内存资源,加速 ASP 执行效率,减轻服务器的负担,而动网在这一方面做得是最突出的像他现在 dvbbs7.1.0 版,更是缓存的利用上更上一层楼,前后台大多的操作都和缓存有关,而现在动网里用的也就是迷城浪子的缓存类,下面列出动网的三大高手 写的 ASP 缓存类
木鸟写的
'**********************************************
' vb Cach 类
'
取值前判断 ' 属性 valid 否可用。
新建对象后赋值 ' 属性 name cach 名。
期时间 ) 设置 cach 内容 ' 方法 add 值 .
' 属性 valu 返回 cach 内容
' 属性 blempti 否未设置值
测试用 ' 方法 makeEmpti 释放内存。
' 方法 equal 变量 1 判断 cach 值是否和变量 1 相同
' 方法 expir time 修改过期时间为 time
' 木鸟 2002.12.24
' http://www.aspsky.net/
'**********************************************
class Cach
privat obj 'cach 内容
privat expireTim ' 过期时间
privat expireTimeNam ' 过期时间 applic 名
privat cacheNam 'cach 内容 applic 名
privat path 'uri
privat sub class_initi
path=request.servervari "url"
instrRev path,path=left path."/"
end sub
privat sub class_termin
end sub
public properti get blEmpty
' 否为空
if isempti obj then
blEmpty=tru
els
blEmpty=fals
end if
end properti
public properti get valid
' 否可用 ( 过期 )
if isempti obj or not isDat expireTim then
valid=fals
elseif CDate expireTim <now then
valid=fals
els
valid=tru
end if
end properti
public properti let name str
' 设置 cach 名
cacheName=str & path
obj=appl cacheNam
expireTimeName=str & "expires" & path
expireTime=appl expireTimeNam
end properti
public properti let expir tm
' 重设置过期时间
expireTime=tm
application.lock
applic expireTimeNam =expireTim
application.unlock
end properti
expir public sub add var.
' 赋值
if isempti var or not isDat expir then
exit sub
end if
obj=var
expireTime=expir
application.lock
applic cacheNam =obj
applic expireTimeNam =expireTim
application.unlock
end sub
public properti get valu
' 取值
if isempti obj or not isDat expireTim then
value=nul
elseif CDate expireTim <now then
value=nul
els
value=obj
end if
end properti
public sub makeEmpti
' 释放 applic
application.lock
applic cacheNam =empti
applic expireTimeNam =empti
application.unlock
obj=empti
expireTime=empti
end sub
public function equal var2
' 比拟
if typenam obj <>typenam var2 then
equal=fals
elseif typenam obj ="Object" then
if obj is var2 then
equal=tru
els
equal=fals
end if
elseif typenam obj ="Variant " then
"^" =join var2,if join obj."^" then
equal=tru
els
equal=fals
end if
els
if obj=var2 then
equal=tru
els
equal=fals
end if
end if
end function
end class
木鸟 类例子 vb Cach 类
'
取值前判断 ' 属性 valid 否可用。
新建对象后赋值 ' 属性 name cach 名。
期时间 ) 设置 cach 内容 ' 方法 add 值 .
' 属性 valu 返回 cach 内容
' 属性 blempti 否未设置值
' 方法 makeEmpti 释放内存。
删除内存 ' 方法 DelCah .
' 方法 equal 变量 1 判断 cach 值是否和变量 1 相同
' 方法 expir time 修改过期时间为 time
' 用法
set myCache=New Cach
myCache.name="BoardJumpList" ' 定义缓存名
与是否为空值 ) if myCache.valid then ' 判断是否可用 ( 包括过期。
response.writ myCache.valu ' 输出
els
................
BoardJumpList=xxx
dateadd "n",myCache.add BoardJumpList.60,now ' 写入缓存 xxx.add 内容 , 过期时间
response.writ BoardJumpList ' 输出
end if
myCache.makeEmpti 释放内存
mycache.DelCah 删除缓存
迷城浪子写的 Class Cls_Cach
Rem ================== 使用说明 ====================
作者:迷城浪子。如采用本类模块,Rem = 本类模块是动网先锋原创。请不要去掉这个说明。这段注释不会影响执行的速度。
Rem = 作用:缓存和缓存管理类
Rem = 公有变量: Reloadtim 过期时间(单位为分钟)缺省值为 14400
逾越则自动删除使用次数少的对象。缺省值为 300 Rem = MaxCount 缓存对象的最大值。
缺省值为 "Dvbbs",Rem = CacheNam 缓存组的总名称。如果一个站点中有逾越一个缓存组,则需要外部改变这个值。
只写属性。 Rem = 属性 :Name 定义缓存对象名称。
Rem = 属性 :valu 读取和写入缓存数据。
Rem = 函数: ObjIsEmpty 判断当前缓存是否过期。
参数是缓存对象的名称。 Rem = 方法: DelCah MyCaheNam 手工删除一个缓存对象。
Rem ========================
MaxCount,Public Reloadtime.CacheNam
CacheData,Privat LocalCacheName.DelCount
Privat Sub Class_Initi
Reloadtime=14400
CacheName="Dvbbs"
End Sub
NewValu Privat Sub SetCach SetName.
Application.Lock
Applicat SetNam = NewValu
Application.unLock
End Sub
Privat Sub makeEmpti SetNam
Application.Lock
Applicat SetNam = Empty
Application.unLock
End Sub
Public Properti Let Name ByVal vNewValu
LocalCacheName=LCas vNewValu
End Properti
Public Properti Let Valu ByVal vNewValu
If LocalCacheName<>"" Then
CacheData=Appl CacheName&"_"&LocalCacheNam
If IsArrai CacheData Then
CacheData 0 =vNewValu
CacheData 1 =Now
Else
ReDim CacheData 2
CacheData 0 =vNewValu
CacheData 1 =Now
End If
CacheData SetCach CacheName&"_"&LocalCacheName.
Else
"DvbbsCacheServer",Err.Rais vbObjectError + 1. " pleas chang the CacheName."
End If
End Properti
Public Properti Get Valu
If LocalCacheName<>"" Then
CacheData=Appl CacheName&"_"&LocalCacheNam
If IsArrai CacheData Then
Value=CacheData 0
Else
"DvbbsCacheServer",Err.Rais vbObjectError + 1. " The CacheData Is Empty."
End If
Else
"DvbbsCacheServer",Err.Rais vbObjectError + 1. " pleas chang the CacheName."
End If
End Properti
Public Function ObjIsEmpty
ObjIsEmpty=Tru
CacheData=Appl CacheName&"_"&LocalCacheNam
If Not IsArrai CacheData Then Exit Function
If Not IsDate CacheData 1 Then Exit Function
CDate CacheData 1 ,If DateDiff "s".Now < 60*Reloadtim Then
ObjIsEmpty=Fals
End If
End Function
Public Sub DelCah MyCaheNam
makeEmpti CacheName&"_"&MyCaheNam
End Sub
End Class
迷城浪子 类例子
Set WydCache=New Cls_Cach
WydCache.Reloadtime=0.5 ' 定义过期时间 以分钟为单会 )
WydCache.CacheName="pages" ' 定义缓存名
与是否为空值 ) IF WydCache.ObjIsEmpti Then '' 判断是否可用 ( 包括过期。
Response.writ WydCache.Valu
Else
..................
BoardJumpList=xxx
WydCache.Value=BoardJumpList ' 写入内容
Response.writ BoardJumpList
End if
mycache.DelCah " 缓存名 " 删除缓存
slightboi 写的
'========================
'clsCache.asp
'========================
'== begin : 2004-6-26 21:51:47
'== copyright : slightboi C 1998-2004
'== email : slightboy@msn.com
'========================
'========================
' Dim Applicat 2
' Applicat 0 Counter 计数器
' Applicat 1 dateTim 放置时间
' Applicat 2 Content 缓存内容
Public PREFIX
Public PREFIX_LENGTH
Privat Sub Class_Initi
PREFIX = "Cached:"
PREFIX_LENGTH = 7
End Sub
Privat Sub Class_Termin
End Sub
' 设置变量
ByRef Content Public Properti Let Cach ByRef Key.
Dim Item 2
Item 0 = 0
Item 1 = Now
IF IsObject Content Then
Set Item 2 = Content
Else
Item 2 = Content
End IF
Application.Unlock
Applicat PREFIX & Kei = Item
Application.Lock
End Properti
' 取出变量 计数器 ++
Public Properti Get Cach ByRef Kei
Dim Item
Item = Applicat PREFIX & Kei
IF IsArrai Item Then
IF IsObject Item Then
Set Cach = Item 2
Else
Cach = Item 2
End IF
Applicat PREFIX & Kei 0 = Applicat PREFIX & Kei 0 + 1
Else
Cach = Empty
End IF
End Properti
' 检查缓存对象是否存在
Public Properti Get Exist ByRef Kei
Dim Item
Item = Applicat PREFIX & Kei
IF IsArrai Item Then
Exist = True
Else
Exist = Fals
End IF
End Properti
' 得到计数器数值
Public Properti Get Counter ByRef Kei
Dim Item
Item = Applicat PREFIX & Kei
IF IsArrai Item Then
Counter = Item 0
End IF
End Properti
' 设置计数器时间
ByRef SetdateTim Public Properti Let dateTim ByRef Key.
Dim Item
Item = Applicat PREFIX & Kei
IF IsArrai Item Then
Item 1 = SetdateTim
End IF
End Properti
' 得到计数器时间
Public Properti Get dateTim ByRef Kei
Dim Item
Item = Applicat PREFIX & Kei
IF IsArrai Item Then
dateTim = Item 1
End IF
End Properti
' 重置计数器
Public Sub ResetCount
Dim Kei
Dim Item
Application.Unlock
For Each Kei in Application.Cont
PREFIX_LENGTH = PREFIX Then IF Left Key.
Item = Applicat Kei
Item 0 = 0
Applicat Kei = Item
End IF
Next
Application.Lock
End Sub
' 删除某以缓存
Public Sub Clear ByRef Kei
Application.Contents.Remov PREFIX & Kei
End Sub
' 清空没有使用的缓存
Public Sub ClearUnus
Keys,Dim Key. KeyLength, KeyIndex
For Each Kei in Application.Cont
PREFIX_LENGTH = PREFIX Then IF Left Key.
IF Applicat Kei 0 = 0 Then
Kei = Kei & VBNewLin & Kei
End IF
End IF
Next
VBNewLin Kei = Split Keys.
KeyLength = UBound Kei
Application.Unlock
For KeyIndex = 1 To KeyLength
Application.Contents.Remov Kei KeyIndex
Next
Application.Lock
End Sub
' 清空所有缓存
Public Sub ClearAll
Keys,Dim Key. KeyLength, KeyIndex
For Each Kei in Application.Cont
PREFIX_LENGTH = PREFIX Then IF Left Key.
Kei = Kei & VBNewLin & Kei
End IF
Next
VBNewLin Kei = Split Keys.
KeyLength = UBound Kei
Application.Unlock
For KeyIndex = 1 To KeyLength
Application.Contents.Remov Kei KeyIndex
Next
Application.Lock
End Sub
End Class
slightboyn 类例子
Set Wyd=New JayCach
Wyd.dateTim "Page" = 时 间
If Wyd.Exist "Page" Then
Response.writ Wyd.Cach "Page" ' 输出
Else
Wyd.Cach "Page" =xxx 写入
Responxe.writ xxx
End IF
Wyd.Clear "page" ' 删除缓存