C#.Net环境下的缓存技术
2021-02-19 23:20
一、缓存技术
本节将介绍以下技术:
使用Asp.Net缓存;
使用Remoting Singleton缓存;
使用内存映射文件;
使用SQL Server缓存;
使用静态变量缓存;
使用Asp.net 会话状态(Session State);
使用Asp.net客户端缓存和状态;
使用Internet Explorer缓存。
2.1 Asp.net缓存
将常用的数据保存在内存中对asp的开发人员来说并不陌生,Session对象和Application对象提供键值对来缓存数据,Session对象保存和单个用户有关的数据,Application对象可保留和应用程序有关的数据,每个用户都可以访问。
在Asp.net中,提供了专门用于缓存数据的Cache对象,它的应用范围是应用程序域。生存期是和应用程序紧密相关的,每当应用程序启动的时候就重新创建Cache对象。它域Application对象的主要区别就是提供了专门用于缓存管理的特性,比如依赖和过期策略。
你可以使用Cache对象和它的属性来实现高级的缓存功能,同时可以利用Asp.net Cache来对客户端输出的响应内容进行缓存。关于Asp.net中的缓存技术,有以下内容要介绍:
2.1.1 编程缓存Programmatic Caching
Cache对象定义在System.Web.Caching命名空间,可以使用HttpContext类的Cache属性或Page对象的Cache属性来得到Cache的引用,Cache对象除了存储键值对以外,还可以存储.net框架的对象。下面介绍相应的依赖和过期策略。
2.1.1.1 依赖和过期策略
当向缓存中加数据时,可以指定它的依赖关系来实现在某些情况下强制移除它。可用的方案包括以下几种:
·文件依赖(File Dependency)——当硬盘上的某个(某些)文件更改时,强制移除缓存数据;如:
·键值依赖(Key Dependency)——指定缓存中的某个数据项更改时移除。如:
·基于时间的过期策略——按照预先定义的时间策略来使数据失效,可以是绝对时间(如某个日期的18:00)也可以是相对现在的相对时间。如:
使用太短和太长的过期时间都不行,不是造成用不上的缓存数据,就是缓存了陈旧的数据并加重了缓存负担,所以可以使用高并发的测试来决定过期时间的最佳值。
·另外有个问题就是如何实现对数据库的依赖,这就要求实现自己的通知机制,当数据库数据改变时能够通知你的缓存数据改变。
由于数据会过期,所以当使用缓存中的数据时,必须检查数据的有效性。如以下代码:
依赖和过期策略指定了缓存中数据的移除方式,有时候你可能需要在移除发生时做一些工作,这能靠写代码来实现这一点,这就是我们要讲到的。
2.1.1.2 使用缓存回调(Cache Callback)
你可以定义回调,这样当移除自动发生时, 你可以不移除它或者使用新的数据来替换它。如:
2.1.1.3 对缓存项使用优先级
当运行应用程序的服务器内存不足时,会自动清除缓存中的数据,称为“清除scavenging”。此时,Cache对象根据缓存项的优先级来决定先移除哪些缓存数据,你可以在代码中指定缓存项的优先级。参看MSDN中“CacheItemPriority 枚举”,如:
Cache.Insert("DSN", connectionString, null, d, t, CacheItemPriority.High, onRemove);
2.1.1.4 刷新数据(清除缓存)
没有直接的方法来刷新Asp.net的输出缓存,但是有替代方法(设置所有数据失效),比如:
Response.Cache.SetExpires(DateTime.Now)
这可以清除缓存,但页面上并不立刻体现出来,直到最初的缓存期结束,比如:
指令指定的缓存只会在10秒后才清除。通常并不需要清除所有缓存项,你只要重新加载数据更新缓存就够了。
2.1.2 输出缓存(Output Cache)
你可以使用两种方式的输出缓存来缓存需要传输和显示到客户端浏览器上的数据——页面输出缓存(Page Output Cache)和页面片断缓存(Page Fragment Cache)。当整个页面相对变化较少时,可以缓存整个页面;如果只是页面的一部分经常变化,可以使用片断缓存。
2.1.2.1 页面输出缓存
Page Output Caching将对页面请求的响应放入缓存中,后续对此页面的请求将直接从缓存中得到信息而不是重建此页面。可以通过添加Page指令(高级别,声明实现)来实现,也可以使用HTTPCachePolicy类来实现(低级别,程序实现)。本指南不打算介绍技术细节,只给出如何更好使用的指南和最佳实践。有四方面的内容:
1、决定缓存的内容
页面输出缓存可缓存各种信息,缓存这些信息意味着你不需要经常处理同样的数据和结果,包括:
·经常被请求但不不改变的静态页面;
·更新频率和时间已知的页面(如显示股票价格的页面);
·根据HTTP参数,有几个可能输出的页面(如根据城市的代号显示该城市天气情况的页面);
·从Web Service返回的结果;如:
2、缓存动态页面
基于输入参数、语言和浏览器类型改变的动态网页经常用到。你可以使用OutputCache的以下属性来实现对动态页面的缓存:
VaryByParam——基于输入参数不同缓存同一页面的多个版本;
VaryByHeader——基于Page Header的内容不同缓存页面的多个版本;
VaryByCustom——通过声明属性和重载GetVaryByCustomString方法来定制缓存处理页面的多个版本;
VaryByControl——基于控件中asp对象属性的不同来缓存控件。
对多个版本页面的缓存会降低可用内存,所以要仔细衡量缓存策略。s
3、控制缓存的位置
你可以使用@OutputCache指令的OutputCacheLocation属性的枚举值来指定缓存的位置,如:
4、 配置页面输出缓存
有两种方式控制,你可以使用Page指令,也可以使用Cache API编程实现。参考以下两段代码:
2.1.2.2 页面片断缓存
有时候缓存整个页面并不灵活,同时内存的发但也比较大,这时候应考虑片断缓存。页面片断缓存适合以下类型的数据:
·创建开销很大的页面片断(控件);
·包含静态数据的页面片断;
·可被多个用户使用的页面片断;
·多个页面共享的页面片断(如公用菜单条)
以下是缓存部分页面的例子:
2.1.3 在非Web项目中使用Asp.net缓存
Asp.net Cache位于System.Web命名空间,但由于它是一个通用的方案,所以仍然可以在引用此命名空间的任何非Web项目中使用它。
System.Web.Caching.Cache 类是对象的缓存,它可以通过System.Web.HttpRuntime.Cache 的静态属性或System.Web.UI.Page 和System.Web.HttpContext.Cache来访问。因此在请求上下文之外也可以存在,在每个应用程序域中只有一个实例,所以HttpRuntime.Cache对象可以在Aspnet_wp.exe之外的每个应用程序域中存在。以下代码演示了在普通应用里访问Cache对象:
HttpRuntime httpRT = new HttpRuntime();
Cache cache = HttpRuntime.Cache;
2.2 使用Remoting Singleton缓存
.Net Remoting提供了跨应用程序域、跨进程、跨计算机的程序运行框架。服务器激活的对象有两种激活模式,其中Singleton 类型任何时候都不会同时具有多个实例。如果存在实例,所有客户端请求都由该实例提供服务。如果不存在实例,服务器将创建一个实例,而所有后继的客户端请求都将由该实例来提供服务。由于 Singleton 类型具有关联的默认生存期,即使任何时候都不会有一个以上的可用实例,客户端也不会总接收到对可远程处理的类的同一实例的引用。所以将数据缓存起来可以在多个客户端之间共享状态信息。
为了使用.Net Remoting实现缓存方案,要保证远程对象的租约不过期,并且远程对象没有被垃圾回收器销毁(对象租约是指在系统删除该对象前它在内存中的生存期)。当实现缓存时,重载MarshalByRefObject的InitializeLifetimeService方法并且返回null,这样就能保证租约永远不过期并且相关的对象生存期是无限的。以下代码是一个示例:
注意:由于这种方案的成本较高、性能上的限制并且可能造成系统不稳定,通常采用基于Sql Server的方案来替代。
2.3 使用内存映射文件(Memory-Mapped File)
内存映射文件提供独一无二的特性,允许应用程序通过指针来访问磁盘上的文件——与访问动态内存趣的方式一样。所以你可以将应用程序进程中的某个地址段的数据映射到文件中,供多个跨应用程序域或跨进程访问。
在windows中,代码和数据是以以种方式处理的,表现形式都是内存页,而在内存页背后都是磁盘上的文件。唯一的不同磁盘上的文件类型不同。代码后面是可执行的镜像,而数据后面则是系统的页面文件。当多个应用程序共享内存时,系统的性能会有明显提升。
你可以使用内存映射文件的这种特性来实现同一台机器上的跨进程和跨应用程序域的缓存解决方案。基于内存映射文件的缓存方案包含以下组件:
·windows NT服务——启动时创建内存映射文件,停止时删除它。功能是向使用缓存的进程提供句柄。当然,也可以使用命名的内存映射文件来提供操作接口;
·缓存托管组件(Cache Management Dll)——实现特定的缓存功能,比如:
a. 插入和删除数据项到缓存中;
b. 使用算法清除缓存,比如最后使用算法(Least Recently Used);
c. 保证数据不被篡改;
基于内存映射文件的缓存方案可以用在应用程序的每个层中,但由于使用win32 API调用,所以并不容易实现。.Net 框架不支持内存映射文件,所以只能以非托管代码的方式运行,当然也不能利用.Net框架的有力特性,比如垃圾回收等。同时缓存数据项的管理功能需要定制开发,还要开发性能计数器来监控缓存的效果。
2.4使用SQL Server缓存
如果需要在进程回收(重启)、机器重启或电源故障的过程中保持缓存数据的有效,基于内存的方案并不能满足要求。你可以使用基于永久数据存储的方案,如SQL server数据库或NTFS文件系统。
SQL Server在使用sql语句或存储过程得到数据时,对varchar和varBinary类型的数据有8k的大小限制,你必须使用.Net 框架提供的Ado.Net SQLDataAdapter对象来访问datatable或dataset。
使用SQL Server缓存数据的优点:
·易于实现——使用.Net 框架和Ado.Net访问数据库相当方便;
·完善的安全模型和很高的健壮性;
·数据非常方便的共享;
·数据的持久保留。
·支持很大的数据量。
·方便的管理工具
当然,也有缺点:
·需要安装SQL Server,对小型应用来说不合适;
·重新构造数据的性能和读取数据库的性能比较;
·网络负担。
2.5 使用静态变量缓存
静态变量常用来记录类的状态,你可以用它来创建定制的缓存对象。在定制的缓存类中将你的数据存储器声明为静态变量,并且提供维护接口(插入、删除和访问等)。如果没有特殊的缓存需求(比如依赖、失效策略等),使用静态变量缓存数据是很方便的。由于是在内存中,这种方案可提供对缓存数据的直接、高速的访问,当没有替代方案解决键值对的存储且对速度要求很高时,可以使用静态变量。当然,在asp.net中,应该使用Cache对象。
你可以使用这种方案保存大数据的对象,前提是它不经常更改。由于没有清除机制,大数据的内存消耗会影响性能。
你需要保证定制线程安全机制,或者使用.Net框架提供的同步对象,比如Hashtable。以下代码是使用Hashtable实现的例子:
static Hashtable mCacheData = new Hashtable();
应用范围:本方案的应用范围可以限制到类、模块或整个项目。如果变量定义为public,整个项目中的代码都能访问它,范围是整个应用程序域,实现了高效的共享。而它的生存期是和范围紧密相关的。
2.6 使用asp.net session state
你可以使用基于HttpSessionState对象的asp.net session state来缓存单个用户的会话状态信息。它解决了asp中会话状态的很多限制,包括:
·asp session要求客户端接受cookies,否则就不能使用session;而asp.net可以配置为不使用cookie;
·对web server场的情况,asp的session不能支持;当稳定性和可用性要求很高时,asp.net session state虽然效果不好,但对比较小的单个值scalar Value(比如登录信息),还是很有效。
Asp.net session有很大改进,下面描述使用范围和使用方式。
Asp.net session state有三种操作模式:
1、进程内模式InProc——Session State信息在asp.net工作进程aspnet_wp.exe的进程的内存中存储。这是默认选项,这种情况下,如果进程或应用程序域被回收,则Session 状态信息也被回收;
2、进程外模式State Server——状态信息序列化后保存在独立的状态进程中(AspNet_State.exe),所以状态信息可以保存在专门的服务器上(一个状态服务器State Server);
3、 Sql server模式——状态信息序列化后保存在SQL Server数据库中。
你可以通过调整配置文件中标签的mode属性来设置要使用的状态模式,比如使用SQL Server模式来在Web server场中共享状态信息。当然,这个优势也有缺点,就是状态信息需要序列化和反序列化,同时多了对数据库的写入和读取,所以性能上有开销,这是要仔细评估的。
2.6.1 选择使用模式
2.6.1.1 使用InProc模式
当使用进程内模式时,状态信息保存在aspnet_wp.exe的进程中。由于在web场的情况下aspnet_wp.exe的多个实例在同一台服务器上运行,所以进程内模式不适用与web场的情况。
进程内模式是唯一支持Session_End事件的session模式,当用户会话超时或中止时,可以运行Session_End中的事件处理代码来清除资源。
2.6.1.2 使用StateServer模式
StateServer模式使用指定的进程储存状态信息。因为它也是一种进程外模式,所以要保证你存储的对象是可序列化的,以支持跨进程传输。
当使用Session对象在web场的情况下使用时,必须保证web.config文件中的元素在所有服务器上是唯一的。这样所有的服务器使用同样的加密方式,才能访问缓存中的数据。参考msdn中的“MachineKey元素”。
2.6.1.3 使用SQL Server模式
SQL Server模式下,当你使用信任连接(trusted_connection=true 或 integrated security=sspi)访问Session state信息时,不能在asp.net中使用身份用户模拟。
默认情况下,SQL Server将状态信息存储在TempDb数据库中,它在每次Sql server服务启动时会自动重新创建,当然,你可以指定自己的数据库以便在数据库重启的过程中也能保持数据。
2.6.2 决定使用Session对象要存储的内容
你可以使用Session对象缓存任何类型的.net框架数据,但是要了解对某种类型来说最好的方式是什么。有以下几点需要说明:
1、 对基本类型(比如Int,Byte,String)来说,可以使用任何方式。因为在选用进程外方式时,asp.net使用一个优化的内部方法来序列化和反序列化基本类型的数据;
2、 对复杂类型(如ArrayList)来说,只选用进程内方式。因为asp.net使用BinaryFormatter来序列化和反序列化这类数据,而这会影响性能的。当然,只有在State Server和SQL Server的方式下,才会进行序列化操作;
3、 缓存的安全问题,当在缓存中存储敏感数据时,需要考虑安全性,其它页面可以访问到缓存中的数据;
4、 避免缓存大数据,那会降低性能;
5、 这种缓存方式不支持过期策略、清除和依赖。
2.6.3 实现Session State
Asp.net提供了简单接口来操作Session State,并可使用Web.Config进行简单设置,当配置文件中的设置改变时,能够在页面上立刻体现出来,而不需要重新启动asp.net进程。
以下代码演示了使用SQL Server来实现Session数据的存储和使用。
2.7使用Asp.net客户端缓存和状态
你还可以使用客户端存储页面信息的方式来降低服务器的负担,这种方法提供最低的安全保障,但却有最快的性能表现。由于需要将数据发送到客户端存储,所以数据量有限。
实现客户端缓存的机制有以下五种,接下来将依次介绍:
·隐藏栏位(Hidden Field)
·View State
·隐藏帧(Hidden Frame)
·Cookies
·Query String
这五种方式分别适合于存储不同类型的数据。
2.7.1 使用Hidden Field
你可以将经常改变的少量数据保存在HtmlInputHidden中来维护页面的状态。当每次页面回送的过程中,这些数据都会包含在表单中大送到服务器,所以你要使用HTTP POST方式来提交页面。
使用这种方式的优点如下:
不需要服务器资源,直接从页面中读取;
几乎所有的浏览器都支持;
实现简单;
由于数据在页面中,所以在web Farm的情况下也可使用。
缺点:
由于可以通过查看源码看到,所以可能会被篡改;
不支持复杂格式的数据,复杂数据必须使用解析字符串的方式来间接得到;
当存储大数据的时候会影响性能。
示例:
2.7.2 使用View State
所有的Web Form页面和控件都包含有一个ViewState属性,在对同一页面多次请求时可以保持页面内的值。它的内部实现是维护相应的hidden field,只不过是加密了的,所以比hidden field的安全性要好。
使用View State的性能表现很大程度上依赖于服务器控件的类型。一般来说,Label,TextBox,CheckBox,RadioButton,HyperLink的性能要好一些,而DropdownList,ListBox,DataGrid和DataList就要差很多,因为包含的数据量太大,所以每次页面回送都很耗时间。
有些情况下不推荐使用ViewState,比如:
1、不需要回送的页面避免使用;
2、避免使用ViewState保存大数据量;
3、在需要使用会话超时的情况下避免使用它,因为它没有超时操作。
ViewState的性能表现和Hidden Field的是类似的,但是具有更高的安全性。
优点:
数据在页面中自动维护,不需要服务器资源;
实现简单;
数据是经过加密和压缩的,比hidden field有更高的安全性;
数据存在客户端,可以在Web Farm情况下使用。
缺点:
存储大数据量时会降低性能;
和hidden field类似,在客户端数据仍然有潜在的安全威胁。
示例代码如下:
2.7.3 使用Hidden Frame
你可以使用Hidden Frame在客户端缓存数据,这就避免了使用hidden field和使用view state时每次页面回送时的缓存数据往返。比如你可以秘密的加载多个页面所需要的图片,这并不会消耗服务器资源。
优点:
a. 可以加载较多数据而不只是单个栏位的值;
b. 避免了不必要的多次回送中的数据往来;
c.可以缓存和读取在不同表单中存储的数据项(可以同时缓存多个页面的数据);
d.可以访问同一站点不同frame中的客户端脚本数据。
缺点:
a. 有些浏览器不支持frame;
b. 源代码可以在客户端看到,有潜在的安全威胁;
c. 隐藏frame的数量没有限制,如果框架页面包含较多hidden frame的话,在首次加载时速度会有限制。
示例代码如下:
2.7.4 使用Cookies
Cookie是可以在客户端存储数据另一种方案,这里不过多介绍。
优点:
不需要服务器资源;数据保存在客户端,在用户请求时发送到服务器上。
使用简单。Cookie包含简单的键值对,主要保存轻量级的文本数据。
支持过期策略;可以指定当会话结束时过期,也可指定一个时间策略。
缺点:
数据量的限制;
用户可能设置为拒绝Cookie;
安全问题;用户可能更改机器上的cookie信息,造成基于cookie的系统运行失败;
可能过期或被用户删除,造成一定程度的不可用。
参看示例代码:
2.7.5 使用Query String
Query String是在用户请求的URL后加上相应的参数来使用的,只能在使用HTTP GET方式调用URL时可用。
优点:
d.不需要服务器资源,参数附在URL里面;
e. 应用面广,几乎所有浏览器都支持;
f.实现简单,服务端使用Request对象可直接读取。
缺点:
a.参数直接对用户可见,不安全;
b.URL长度的限制,多数浏览器不支持超过255字符的URL。
示例代码:
string user = Request.QueryString["User"];
2.7.6 小结
下表是使用客户端缓存的建议:
2.8 使用Internet Explorer缓存
IE提供了缓存机制,可以实现对页面的数据进行缓存,同时可以指定过期时间。用户在IE中请求此页面,如果当过期时间没有到,则自动从缓存中提取并呈现;否则,就到服务器上获取新版本。IE对页面的缓存可以在IIS中设置。
适合在Internet Explorer中缓存的内容
页面中的图像文件;
静态的文本内容;
页面的标题栏和页脚内容——改变频率很低,可以给用户一个迅速相应;
网站的首页——更改次数页时相对较少的;
使用动态HTML在客户端保存的特定数据,比如客户自定义的颜色和布局设置信息。
优点:
减少对服务器的请求和网络负担;
支持离线浏览;
可以实现基于XML的客户端复杂应用。
缺点:
客户端的过期时间必须预先指定而不能依赖于服务器更新;IE采用的是Lazy更新机制,优先从缓存中提取数据;
对其它客户端浏览器没有作用;
存储的数据没有加密,不能保证客户端数据安全。
示例代码:
一、缓存技术
本节将介绍以下技术:
使用Asp.Net缓存;
使用Remoting Singleton缓存;
使用内存映射文件;
使用SQL Server缓存;
使用静态变量缓存;
使用Asp.net 会话状态(Session State);
使用Asp.net客户端缓存和状态;
使用Internet Explorer缓存。
2.1 Asp.net缓存
将常用的数据保存在内存中对asp的开发人员来说并不陌生,Session对象和Application对象提供键值对来缓存数据,Session对象保存和单个用户有关的数据,Application对象可保留和应用程序有关的数据,每个用户都可以访问。
在Asp.net中,提供了专门用于缓存数据的Cache对象,它的应用范围是应用程序域。生存期是和应用程序紧密相关的,每当应用程序启动的时候就重新创建Cache对象。它域Application对象的主要区别就是提供了专门用于缓存管理的特性,比如依赖和过期策略。
你可以使用Cache对象和它的属性来实现高级的缓存功能,同时可以利用Asp.net Cache来对客户端输出的响应内容进行缓存。关于Asp.net中的缓存技术,有以下内容要介绍:
2.1.1 编程缓存Programmatic Caching
Cache对象定义在System.Web.Caching命名空间,可以使用HttpContext类的Cache属性或Page对象的Cache属性来得到Cache的引用,Cache对象除了存储键值对以外,还可以存储.net框架的对象。下面介绍相应的依赖和过期策略。
2.1.1.1 依赖和过期策略
当向缓存中加数据时,可以指定它的依赖关系来实现在某些情况下强制移除它。可用的方案包括以下几种:
·文件依赖(File Dependency)——当硬盘上的某个(某些)文件更改时,强制移除缓存数据;如:
·键值依赖(Key Dependency)——指定缓存中的某个数据项更改时移除。如:
·基于时间的过期策略——按照预先定义的时间策略来使数据失效,可以是绝对时间(如某个日期的18:00)也可以是相对现在的相对时间。如:
使用太短和太长的过期时间都不行,不是造成用不上的缓存数据,就是缓存了陈旧的数据并加重了缓存负担,所以可以使用高并发的测试来决定过期时间的最佳值。
·另外有个问题就是如何实现对数据库的依赖,这就要求实现自己的通知机制,当数据库数据改变时能够通知你的缓存数据改变。
由于数据会过期,所以当使用缓存中的数据时,必须检查数据的有效性。如以下代码:
依赖和过期策略指定了缓存中数据的移除方式,有时候你可能需要在移除发生时做一些工作,这能靠写代码来实现这一点,这就是我们要讲到的。
2.1.1.2 使用缓存回调(Cache Callback)
你可以定义回调,这样当移除自动发生时, 你可以不移除它或者使用新的数据来替换它。如:
2.1.1.3 对缓存项使用优先级
当运行应用程序的服务器内存不足时,会自动清除缓存中的数据,称为“清除scavenging”。此时,Cache对象根据缓存项的优先级来决定先移除哪些缓存数据,你可以在代码中指定缓存项的优先级。参看MSDN中“CacheItemPriority 枚举”,如:
Cache.Insert("DSN", connectionString, null, d, t, CacheItemPriority.High, onRemove);
2.1.1.4 刷新数据(清除缓存)
没有直接的方法来刷新Asp.net的输出缓存,但是有替代方法(设置所有数据失效),比如:
Response.Cache.SetExpires(DateTime.Now)
这可以清除缓存,但页面上并不立刻体现出来,直到最初的缓存期结束,比如:
指令指定的缓存只会在10秒后才清除。通常并不需要清除所有缓存项,你只要重新加载数据更新缓存就够了。
2.1.2 输出缓存(Output Cache)
你可以使用两种方式的输出缓存来缓存需要传输和显示到客户端浏览器上的数据——页面输出缓存(Page Output Cache)和页面片断缓存(Page Fragment Cache)。当整个页面相对变化较少时,可以缓存整个页面;如果只是页面的一部分经常变化,可以使用片断缓存。
2.1.2.1 页面输出缓存
Page Output Caching将对页面请求的响应放入缓存中,后续对此页面的请求将直接从缓存中得到信息而不是重建此页面。可以通过添加Page指令(高级别,声明实现)来实现,也可以使用HTTPCachePolicy类来实现(低级别,程序实现)。本指南不打算介绍技术细节,只给出如何更好使用的指南和最佳实践。有四方面的内容:
1、决定缓存的内容
页面输出缓存可缓存各种信息,缓存这些信息意味着你不需要经常处理同样的数据和结果,包括:
·经常被请求但不不改变的静态页面;
·更新频率和时间已知的页面(如显示股票价格的页面);
·根据HTTP参数,有几个可能输出的页面(如根据城市的代号显示该城市天气情况的页面);
·从Web Service返回的结果;如:
2、缓存动态页面
基于输入参数、语言和浏览器类型改变的动态网页经常用到。你可以使用OutputCache的以下属性来实现对动态页面的缓存:
VaryByParam——基于输入参数不同缓存同一页面的多个版本;
VaryByHeader——基于Page Header的内容不同缓存页面的多个版本;
VaryByCustom——通过声明属性和重载GetVaryByCustomString方法来定制缓存处理页面的多个版本;
VaryByControl——基于控件中asp对象属性的不同来缓存控件。
对多个版本页面的缓存会降低可用内存,所以要仔细衡量缓存策略。s
3、控制缓存的位置
你可以使用@OutputCache指令的OutputCacheLocation属性的枚举值来指定缓存的位置,如:
4、 配置页面输出缓存
有两种方式控制,你可以使用Page指令,也可以使用Cache API编程实现。参考以下两段代码:
2.1.2.2 页面片断缓存
有时候缓存整个页面并不灵活,同时内存的发但也比较大,这时候应考虑片断缓存。页面片断缓存适合以下类型的数据:
·创建开销很大的页面片断(控件);
·包含静态数据的页面片断;
·可被多个用户使用的页面片断;
·多个页面共享的页面片断(如公用菜单条)
以下是缓存部分页面的例子:
2.1.3 在非Web项目中使用Asp.net缓存
Asp.net Cache位于System.Web命名空间,但由于它是一个通用的方案,所以仍然可以在引用此命名空间的任何非Web项目中使用它。
System.Web.Caching.Cache 类是对象的缓存,它可以通过System.Web.HttpRuntime.Cache 的静态属性或System.Web.UI.Page 和System.Web.HttpContext.Cache来访问。因此在请求上下文之外也可以存在,在每个应用程序域中只有一个实例,所以HttpRuntime.Cache对象可以在Aspnet_wp.exe之外的每个应用程序域中存在。以下代码演示了在普通应用里访问Cache对象:
HttpRuntime httpRT = new HttpRuntime();
Cache cache = HttpRuntime.Cache;
2.2 使用Remoting Singleton缓存
.Net Remoting提供了跨应用程序域、跨进程、跨计算机的程序运行框架。服务器激活的对象有两种激活模式,其中Singleton 类型任何时候都不会同时具有多个实例。如果存在实例,所有客户端请求都由该实例提供服务。如果不存在实例,服务器将创建一个实例,而所有后继的客户端请求都将由该实例来提供服务。由于 Singleton 类型具有关联的默认生存期,即使任何时候都不会有一个以上的可用实例,客户端也不会总接收到对可远程处理的类的同一实例的引用。所以将数据缓存起来可以在多个客户端之间共享状态信息。
为了使用.Net Remoting实现缓存方案,要保证远程对象的租约不过期,并且远程对象没有被垃圾回收器销毁(对象租约是指在系统删除该对象前它在内存中的生存期)。当实现缓存时,重载MarshalByRefObject的InitializeLifetimeService方法并且返回null,这样就能保证租约永远不过期并且相关的对象生存期是无限的。以下代码是一个示例:
注意:由于这种方案的成本较高、性能上的限制并且可能造成系统不稳定,通常采用基于Sql Server的方案来替代。
2.3 使用内存映射文件(Memory-Mapped File)
内存映射文件提供独一无二的特性,允许应用程序通过指针来访问磁盘上的文件——与访问动态内存趣的方式一样。所以你可以将应用程序进程中的某个地址段的数据映射到文件中,供多个跨应用程序域或跨进程访问。
在windows中,代码和数据是以以种方式处理的,表现形式都是内存页,而在内存页背后都是磁盘上的文件。唯一的不同磁盘上的文件类型不同。代码后面是可执行的镜像,而数据后面则是系统的页面文件。当多个应用程序共享内存时,系统的性能会有明显提升。
你可以使用内存映射文件的这种特性来实现同一台机器上的跨进程和跨应用程序域的缓存解决方案。基于内存映射文件的缓存方案包含以下组件:
·windows NT服务——启动时创建内存映射文件,停止时删除它。功能是向使用缓存的进程提供句柄。当然,也可以使用命名的内存映射文件来提供操作接口;
·缓存托管组件(Cache Management Dll)——实现特定的缓存功能,比如:
a. 插入和删除数据项到缓存中;
b. 使用算法清除缓存,比如最后使用算法(Least Recently Used);
c. 保证数据不被篡改;
基于内存映射文件的缓存方案可以用在应用程序的每个层中,但由于使用win32 API调用,所以并不容易实现。.Net 框架不支持内存映射文件,所以只能以非托管代码的方式运行,当然也不能利用.Net框架的有力特性,比如垃圾回收等。同时缓存数据项的管理功能需要定制开发,还要开发性能计数器来监控缓存的效果。
2.4使用SQL Server缓存
如果需要在进程回收(重启)、机器重启或电源故障的过程中保持缓存数据的有效,基于内存的方案并不能满足要求。你可以使用基于永久数据存储的方案,如SQL server数据库或NTFS文件系统。
SQL Server在使用sql语句或存储过程得到数据时,对varchar和varBinary类型的数据有8k的大小限制,你必须使用.Net 框架提供的Ado.Net SQLDataAdapter对象来访问datatable或dataset。
使用SQL Server缓存数据的优点:
·易于实现——使用.Net 框架和Ado.Net访问数据库相当方便;
·完善的安全模型和很高的健壮性;
·数据非常方便的共享;
·数据的持久保留。
·支持很大的数据量。
·方便的管理工具
当然,也有缺点:
·需要安装SQL Server,对小型应用来说不合适;
·重新构造数据的性能和读取数据库的性能比较;
·网络负担。
2.5 使用静态变量缓存
静态变量常用来记录类的状态,你可以用它来创建定制的缓存对象。在定制的缓存类中将你的数据存储器声明为静态变量,并且提供维护接口(插入、删除和访问等)。如果没有特殊的缓存需求(比如依赖、失效策略等),使用静态变量缓存数据是很方便的。由于是在内存中,这种方案可提供对缓存数据的直接、高速的访问,当没有替代方案解决键值对的存储且对速度要求很高时,可以使用静态变量。当然,在asp.net中,应该使用Cache对象。
你可以使用这种方案保存大数据的对象,前提是它不经常更改。由于没有清除机制,大数据的内存消耗会影响性能。
你需要保证定制线程安全机制,或者使用.Net框架提供的同步对象,比如Hashtable。以下代码是使用Hashtable实现的例子:
static Hashtable mCacheData = new Hashtable();
应用范围:本方案的应用范围可以限制到类、模块或整个项目。如果变量定义为public,整个项目中的代码都能访问它,范围是整个应用程序域,实现了高效的共享。而它的生存期是和范围紧密相关的。
2.6 使用asp.net session state
你可以使用基于HttpSessionState对象的asp.net session state来缓存单个用户的会话状态信息。它解决了asp中会话状态的很多限制,包括:
·asp session要求客户端接受cookies,否则就不能使用session;而asp.net可以配置为不使用cookie;
·对web server场的情况,asp的session不能支持;当稳定性和可用性要求很高时,asp.net session state虽然效果不好,但对比较小的单个值scalar Value(比如登录信息),还是很有效。
Asp.net session有很大改进,下面描述使用范围和使用方式。
Asp.net session state有三种操作模式:
1、进程内模式InProc——Session State信息在asp.net工作进程aspnet_wp.exe的进程的内存中存储。这是默认选项,这种情况下,如果进程或应用程序域被回收,则Session 状态信息也被回收;
2、进程外模式State Server——状态信息序列化后保存在独立的状态进程中(AspNet_State.exe),所以状态信息可以保存在专门的服务器上(一个状态服务器State Server);
3、 Sql server模式——状态信息序列化后保存在SQL Server数据库中。
你可以通过调整配置文件中标签的mode属性来设置要使用的状态模式,比如使用SQL Server模式来在Web server场中共享状态信息。当然,这个优势也有缺点,就是状态信息需要序列化和反序列化,同时多了对数据库的写入和读取,所以性能上有开销,这是要仔细评估的。
2.6.1 选择使用模式
2.6.1.1 使用InProc模式
当使用进程内模式时,状态信息保存在aspnet_wp.exe的进程中。由于在web场的情况下aspnet_wp.exe的多个实例在同一台服务器上运行,所以进程内模式不适用与web场的情况。
进程内模式是唯一支持Session_End事件的session模式,当用户会话超时或中止时,可以运行Session_End中的事件处理代码来清除资源。
2.6.1.2 使用StateServer模式
StateServer模式使用指定的进程储存状态信息。因为它也是一种进程外模式,所以要保证你存储的对象是可序列化的,以支持跨进程传输。
当使用Session对象在web场的情况下使用时,必须保证web.config文件中的元素在所有服务器上是唯一的。这样所有的服务器使用同样的加密方式,才能访问缓存中的数据。参考msdn中的“MachineKey元素”。
2.6.1.3 使用SQL Server模式
SQL Server模式下,当你使用信任连接(trusted_connection=true 或 integrated security=sspi)访问Session state信息时,不能在asp.net中使用身份用户模拟。
默认情况下,SQL Server将状态信息存储在TempDb数据库中,它在每次Sql server服务启动时会自动重新创建,当然,你可以指定自己的数据库以便在数据库重启的过程中也能保持数据。
2.6.2 决定使用Session对象要存储的内容
你可以使用Session对象缓存任何类型的.net框架数据,但是要了解对某种类型来说最好的方式是什么。有以下几点需要说明:
1、 对基本类型(比如Int,Byte,String)来说,可以使用任何方式。因为在选用进程外方式时,asp.net使用一个优化的内部方法来序列化和反序列化基本类型的数据;
2、 对复杂类型(如ArrayList)来说,只选用进程内方式。因为asp.net使用BinaryFormatter来序列化和反序列化这类数据,而这会影响性能的。当然,只有在State Server和SQL Server的方式下,才会进行序列化操作;
3、 缓存的安全问题,当在缓存中存储敏感数据时,需要考虑安全性,其它页面可以访问到缓存中的数据;
4、 避免缓存大数据,那会降低性能;
5、 这种缓存方式不支持过期策略、清除和依赖。
2.6.3 实现Session State
Asp.net提供了简单接口来操作Session State,并可使用Web.Config进行简单设置,当配置文件中的设置改变时,能够在页面上立刻体现出来,而不需要重新启动asp.net进程。
以下代码演示了使用SQL Server来实现Session数据的存储和使用。
2.7使用Asp.net客户端缓存和状态
你还可以使用客户端存储页面信息的方式来降低服务器的负担,这种方法提供最低的安全保障,但却有最快的性能表现。由于需要将数据发送到客户端存储,所以数据量有限。
实现客户端缓存的机制有以下五种,接下来将依次介绍:
·隐藏栏位(Hidden Field)
·View State
·隐藏帧(Hidden Frame)
·Cookies
·Query String
这五种方式分别适合于存储不同类型的数据。
2.7.1 使用Hidden Field
你可以将经常改变的少量数据保存在HtmlInputHidden中来维护页面的状态。当每次页面回送的过程中,这些数据都会包含在表单中大送到服务器,所以你要使用HTTP POST方式来提交页面。
使用这种方式的优点如下:
不需要服务器资源,直接从页面中读取;
几乎所有的浏览器都支持;
实现简单;
由于数据在页面中,所以在web Farm的情况下也可使用。
缺点:
由于可以通过查看源码看到,所以可能会被篡改;
不支持复杂格式的数据,复杂数据必须使用解析字符串的方式来间接得到;
当存储大数据的时候会影响性能。
示例:
2.7.2 使用View State
所有的Web Form页面和控件都包含有一个ViewState属性,在对同一页面多次请求时可以保持页面内的值。它的内部实现是维护相应的hidden field,只不过是加密了的,所以比hidden field的安全性要好。
使用View State的性能表现很大程度上依赖于服务器控件的类型。一般来说,Label,TextBox,CheckBox,RadioButton,HyperLink的性能要好一些,而DropdownList,ListBox,DataGrid和DataList就要差很多,因为包含的数据量太大,所以每次页面回送都很耗时间。
有些情况下不推荐使用ViewState,比如:
1、不需要回送的页面避免使用;
2、避免使用ViewState保存大数据量;
3、在需要使用会话超时的情况下避免使用它,因为它没有超时操作。
ViewState的性能表现和Hidden Field的是类似的,但是具有更高的安全性。
优点:
数据在页面中自动维护,不需要服务器资源;
实现简单;
数据是经过加密和压缩的,比hidden field有更高的安全性;
数据存在客户端,可以在Web Farm情况下使用。
缺点:
存储大数据量时会降低性能;
和hidden field类似,在客户端数据仍然有潜在的安全威胁。
示例代码如下:
2.7.3 使用Hidden Frame
你可以使用Hidden Frame在客户端缓存数据,这就避免了使用hidden field和使用view state时每次页面回送时的缓存数据往返。比如你可以秘密的加载多个页面所需要的图片,这并不会消耗服务器资源。
优点:
a. 可以加载较多数据而不只是单个栏位的值;
b. 避免了不必要的多次回送中的数据往来;
c.可以缓存和读取在不同表单中存储的数据项(可以同时缓存多个页面的数据);
d.可以访问同一站点不同frame中的客户端脚本数据。
缺点:
a. 有些浏览器不支持frame;
b. 源代码可以在客户端看到,有潜在的安全威胁;
c. 隐藏frame的数量没有限制,如果框架页面包含较多hidden frame的话,在首次加载时速度会有限制。
示例代码如下:
2.7.4 使用Cookies
Cookie是可以在客户端存储数据另一种方案,这里不过多介绍。
优点:
不需要服务器资源;数据保存在客户端,在用户请求时发送到服务器上。
使用简单。Cookie包含简单的键值对,主要保存轻量级的文本数据。
支持过期策略;可以指定当会话结束时过期,也可指定一个时间策略。
缺点:
数据量的限制;
用户可能设置为拒绝Cookie;
安全问题;用户可能更改机器上的cookie信息,造成基于cookie的系统运行失败;
可能过期或被用户删除,造成一定程度的不可用。
参看示例代码:
2.7.5 使用Query String
Query String是在用户请求的URL后加上相应的参数来使用的,只能在使用HTTP GET方式调用URL时可用。
优点:
d.不需要服务器资源,参数附在URL里面;
e. 应用面广,几乎所有浏览器都支持;
f.实现简单,服务端使用Request对象可直接读取。
缺点:
a.参数直接对用户可见,不安全;
b.URL长度的限制,多数浏览器不支持超过255字符的URL。
示例代码:
string user = Request.QueryString["User"];
2.7.6 小结
下表是使用客户端缓存的建议:
2.8 使用Internet Explorer缓存
IE提供了缓存机制,可以实现对页面的数据进行缓存,同时可以指定过期时间。用户在IE中请求此页面,如果当过期时间没有到,则自动从缓存中提取并呈现;否则,就到服务器上获取新版本。IE对页面的缓存可以在IIS中设置。
适合在Internet Explorer中缓存的内容
页面中的图像文件;
静态的文本内容;
页面的标题栏和页脚内容——改变频率很低,可以给用户一个迅速相应;
网站的首页——更改次数页时相对较少的;
使用动态HTML在客户端保存的特定数据,比如客户自定义的颜色和布局设置信息。
优点:
减少对服务器的请求和网络负担;
支持离线浏览;
可以实现基于XML的客户端复杂应用。
缺点:
客户端的过期时间必须预先指定而不能依赖于服务器更新;IE采用的是Lazy更新机制,优先从缓存中提取数据;
对其它客户端浏览器没有作用;
存储的数据没有加密,不能保证客户端数据安全。
下一篇:c# 正则