摘要:介绍缓存的基本概念和经常使用的缓存技术,给出了各类技术的实现机制的简单介绍和适用范围说明,以及设计缓存方案应该考虑的问题(共17页)html
· 性能——将相应数据存储起来以免数据的重复建立、处理和传输,可有效提升性能。好比将不改变的数据缓存起来,例如国家列表等,这样能明显提升web程序的反应速度;web
· 稳定性——同一个应用中,对同一数据、逻辑功能和用户界面的屡次请求时常常发生的。当用户基数很大时,若是每次请求都进行处理,消耗的资源是很大的浪费,也同时形成系统的不稳定。例如,web应用中,对一些静态页面的呈现内容进行缓存能有效的节省资源,提升稳定性。而缓存数据也能下降对数据库的访问次数,下降数据库的负担和提升数据库的服务能力;算法
· 可用性——有时,提供数据信息的服务可能会意外中止,若是使用了缓存技术,能够在必定时间内仍正常提供对最终用户的支持,提升了系统的可用性。sql
在深刻介绍缓存技术以前,须要对状态有一个认识,由于缓存能够说是状态管理的框架。理解状态的含义和它的一些特性——好比生存期和生存范围——对决定是否缓存和选择合适的缓存技术有很大帮助。状态是指一些数据,在应用系统某个时间点上,数据的状态和条件。这些数据多是永久性的存储在数据库中,多是只在内存里停留一会,也多是按照某个逻辑存活(好比多长时间后释放),它的应用范围多是全部用户可访问,多是单个用户有权限;数据库
生存期是指数据保持有效性的时间区间,也就是从建立到移除的时间间隔。一般的生存期有如下几种:编程
·永久状态Permanent State——应用程序使用的永久数据;windows
·进程状态Process State——只在进程周期内有效;浏览器
·会话状态Session State——和特定的用户会话有关;缓存
·消息状态Message State——处理某个消息的时间内有效;安全
状态的范围指对该状态有访问权限的物理或逻辑范围。
·物理范围指能够被访问到的状态数据存放的物理位置,一般包括:
一、 组织Organization——在一个组织内的全部应用程序能够访问状态数据;
二、 场Farm——在应用场范围内的任何机器上均可以访问;
三、 机器Machine——单个机器范围内能够访问;
四、 进程Process——进程内的访问许可;
五、 应用域AppDomain——应用程序域内的访问许可。
·逻辑范围指可访问状态数据的逻辑范围,常见的有:
一、 应用程序Application;
二、 业务流程Business Process;
三、 角色Role;
四、 用户User;
缓存的状态数据只是主数据(Master State Data)的快照,因为数据源可能被修改,因此状态数据就有会陈旧的特性。合理利用此特性和将数据陈旧的负面影响最小化是缓存状态数据的一个重要任务。你能够以一下方式定义数据的陈旧依据:
·主数据更改的可能性——随着时间的推动,主数据更改的多是否大大增长?安照这一点来决定缓存状态数据的陈旧;
·更改的相关性——主数据更新时,缓存的状态数据不相应更新是否是形成影响系统的使用?好比,更改系统的外观风格并不会对业务形成很大影响。
缓存状态数据的陈旧对业务流程的影响称为容忍度,应用系统的能够为不能容忍(No Tolerance)和必定程度的容忍(some Tolerance),前者必须和主数据同步更新,后者容许必定时间或必定范围的陈旧,判断标准就是对业务流程的影响度。
状态的另外一个属性是在不一样阶段的表现形式。在数据库中存储的是原始格式的数据,业务流程中的是处理过的数据,给最终用户呈现的则是另外的形式。以下表所示:
表现形式 |
描述 |
举例 |
原始数据 |
数据的原始形式 |
如数据库中的数据 |
处理过的数据 |
业务流程中对原始数据加工后的数据 |
业务过程当中的数据形式 |
呈现形式 |
可呈现给最终用户的形式 |
HTML或可理解的文字说明 |
当决定缓存数据时,应该考虑缓存哪一个阶段(哪一种形式)的状态数据。如下方针有助于你作决定:
· 当业务逻辑能够容忍缓存数据的陈旧时就缓存原始数据;原始数据能够缓存在数据库访问组件和服务代理中;
·缓存处理过的数据以减小处理时间和资源;处理过的数据能够缓存在业务逻辑组件和服务接口中。
·当须要呈现的数据量很大而且控件的呈现时间很长时,缓存呈现数据(好比包含大数据量的Treeview控件)。这种数据应该被缓存在UI控件中。
在应用程序中缓存数据有如下好处:
·减小交互的通信量——缓存数据能有效减小在进程和机器间的传输量;
·下降系统中的处理量——减小处理次数;
·下降须要作的磁盘访问次数——好比缓存在内存中的数据。
缓存数据只是一份主数据的拷贝,它可能在内存中或以不一样的表现形式保存在硬盘上,也就是说,离说句的使用者越近越好。因此,除了考虑要缓存哪些数据之外,数据缓存在哪里也是一个主要的考量点。这个问题分为如下两个范围:
一、 存储类型Storage Type——数据可用的物理存储位置;
二、 层间的架构元素(Layered architecture elements)——数据可用的逻辑存储位置。
缓存有不少实现方法,全部这些能够被分为两类,基于内存的缓存和基于磁盘的缓存:
一、 内存驻留缓存——包含在内存中临时存储数据的全部实现方法,一般在如下状况下使用:
a) 应用程序频繁使用一样的数据;
b) 应用程序须要常常获取数据;
经过将数据保留在内存中,你能够有效下降昂贵的磁盘访问操做,也能够经过将数据保留在使用者进程中来最大程度的减小跨进程的数据传输。
二、 磁盘驻留缓存——这种技术包含全部使用磁盘做为存储介质的缓存技术,如文件和数据库。在如下状况下基于磁盘的缓存是颇有效的:
a) 处理大数据量时;
b) 应用服务提供的数据可能并非总能使用(好比离线的状况);
c) 缓存的数据必须能在进程回收和机器重启的状况下保持有效;
经过缓存处理过的数据,你能够有效下降数据处理的负担,同时可减小数据交互的代价。
应用程序中的每一个逻辑层的组件都会处理数据,下图标识了一些通用组件:
当使用这些组件进行工做时,你须要考虑哪些数据能够被缓存起来,还有以哪一种方式进行缓存会对程序的总体性能和可用性有帮助,以上的这些元素均可以缓存相应的数据。固然,要考虑的远不止这些。
当设计一个缓存方案时,不但要考虑缓存哪些数据、数据缓存到哪里,还有其它的因素须要考虑。
当决定是否缓存一个对象时,关于数据的格式和访问机制,你须要考虑三个主要问题:
一、 线程安全——当缓存的内容能够被多个线程访问时,使用某种锁定机制来保证数据不会被两个线程同时操做;
二、 序列化——将一个对象缓存时,须要将它序列化以便保存,因此包缓存的对象必须支持序列化;
三、 规格化缓存数据——缓存数据时,相对于要使用的数据格式而言,要保证数据的格式是优化过的。
在使用缓存数据前,必须将数据加载到缓存中,有两种机制来加载数据:
·提早加载Proactive Load——使用这种方式时,你提早将全部的状态数据加载到缓存中,可能在应用程序或线程启动时进行,而后在应用程序或线程的生存期内一直缓存;
·动态加载Reactive Load——或称反应式加载,当使用这种方法时,在应用程序请求数据时取到数据,而且将它缓存起来以备后续使用。
另一个关键因素是如何保持缓存数据和主数据(文件或数据库或其余的应用程序资源)的一致性,你能够定义过时策略来决定缓存中的内容,如已经缓存的时间或者收到其余资源的通知。
当缓存数据时,须要很是清楚缓存中数据的潜在安全威胁。缓存中的数据可能会被别的进程访问或修改,而此进程对主数据是没有权限的。缘由是当数据存储在原始位置时,有相应的安全机制来保护它,当数据被带出传统的安全边界时,须要有同等的安全机制。
当你缓存数据时,应用系统须要的维护工做加大了。在发布应用程序时,须要配置相应的属性,好比缓存的大小限制和清除策略。同时要使用某种机制来监控缓存的效率(好比事件日志和性能计数器)
第一节内容简单介绍了缓存技术中的概念、缓存数据的缘由和方案、优点、实施缓存方案时的考虑等基本内容。如今你对缓存中涉及的内容有了一个大体了解,下面着重介绍可用的缓存技术。
本节将介绍如下技术:
使用Asp.Net缓存;
使用Remoting Singleton缓存;
使用内存映射文件;
使用SQL Server缓存;
使用静态变量缓存;
使用Asp.net 会话状态(Session State);
使用Asp.net客户端缓存和状态;
使用Internet Explorer缓存。
将经常使用的数据保存在内存中对asp的开发人员来讲并不陌生,Session对象和Application对象提供键值对来缓存数据,Session对象保存和单个用户有关的数据,Application对象可保留和应用程序有关的数据,每一个用户均可以访问。
在Asp.net中,提供了专门用于缓存数据的Cache对象,它的应用范围是应用程序域。生存期是和应用程序紧密相关的,每当应用程序启动的时候就从新建立Cache对象。它域Application对象的主要区别就是提供了专门用于缓存管理的特性,好比依赖和过时策略。
你可使用Cache对象和它的属性来实现高级的缓存功能,同时能够利用Asp.net Cache来对客户端输出的响应内容进行缓存。关于Asp.net中的缓存技术,有如下内容要介绍:
Cache对象定义在System.Web.Caching命名空间,可使用HttpContext类的Cache属性或Page对象的Cache属性来获得Cache的引用,Cache对象除了存储键值对之外,还能够存储.net框架的对象。下面介绍相应的依赖和过时策略。
当向缓存中加数据时,能够指定它的依赖关系来实如今某些状况下强制移除它。可用的方案包括如下几种:
·文件依赖(File Dependency)——当硬盘上的某个(某些)文件更改时,强制移除缓存数据;如:
CacheDependency cDependency = new
CacheDependency(Server.MapPath("authors.xml"));
Cache.Insert("CachedItem", item, cDependency);
·键值依赖(Key Dependency)——指定缓存中的某个数据项更改时移除。如:
// Create a cache entry.
Cache["key1"] = "Value 1";
// Make key2 dependent on key1.
String[] dependencyKey = new String[1];
dependencyKey[0] = "key1";
CacheDependency dependency = new CacheDependency(null, dependencyKey);
Cache.Insert("key2", "Value 2", dependency);
·基于时间的过时策略——按照预先定义的时间策略来使数据失效,能够是绝对时间(如某个日期的18:00)也能够是相对如今的相对时间。如:
/// Absolute expiration
Cache.Insert("CachedItem", item, null, DateTime.Now.AddSeconds(5),Cache.NoSlidingExpiration);
/// Sliding expiration
Cache.Insert("CachedItem", item, null, Cache.NoAbsoluteExpiration,
TimeSpan.FromSeconds(5));
使用过短和太长的过时时间都不行,不是形成用不上的缓存数据,就是缓存了陈旧的数据并加剧了缓存负担,因此可使用高并发的测试来决定过时时间的最佳值。
·另外有个问题就是如何实现对数据库的依赖,这就要求实现本身的通知机制,当数据库数据改变时可以通知你的缓存数据改变。可参考http://www.gotdotnet.com/team/rhoward的示例。
因为数据会过时,因此当使用缓存中的数据时,必须检查数据的有效性。如如下代码:
string data = (string)Cache["MyItem"];
if (data == null)
{
data = GetData();
Cache.Insert("MyItem", data);
}
DoSomeThingWithData(data);
依赖和过时策略指定了缓存中数据的移除方式,有时候你可能须要在移除发生时作一些工做,这能靠写代码来实现这一点,这就是咱们要讲到的。
你能够定义回调,这样当移除自动发生时, 你能够不移除它或者使用新的数据来替换它。如:
CacheItemRemovedCallback onRemove = new CacheItemRemovedCallback(this.RemovedCallback);
Cache.Insert("CachedItem",
item,
null,
Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
onRemove);
// Implement the function to handle the expiration of the cache.
public void RemovedCallback(string key, object value, CacheItemRemovedReason r)
{
// Test whether the item is expired, and reinsert it into the cache.
if (r == CacheItemRemovedReason.Expired)
{
// Reinsert it into the cache again.
CacheItemRemovedCallback onRemove = null;
onRemove = new CacheItemRemovedCallback(this.RemovedCallback);
Cache.Insert(key,
value,
null,
Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
onRemove);
}
}
当运行应用程序的服务器内存不足时,会自动清除缓存中的数据,称为“清除scavenging”。此时,Cache对象根据缓存项的优先级来决定先移除哪些缓存数据,你能够在代码中指定缓存项的优先级。参看MSDN中“CacheItemPriority 枚举”,如:
Cache.Insert("DSN", connectionString, null, d, t, CacheItemPriority.High, onRemove);
没有直接的方法来刷新Asp.net的输出缓存,可是有替代方法(设置全部数据失效),好比:
Response.Cache.SetExpires(DateTime.Now)
这能够清除缓存,但页面上并不马上体现出来,直到最初的缓存期结束,好比:
<%@ OutputCache Duration="10" VaryByParam="none" %>指令指定的缓存只会在10秒后才清除。一般并不须要清除全部缓存项,你只要从新加载数据更新缓存就够了。
你可使用两种方式的输出缓存来缓存须要传输和显示到客户端浏览器上的数据——页面输出缓存(Page Output Cache)和页面片段缓存(Page Fragment Cache)。当整个页面相对变化较少时,能够缓存整个页面;若是只是页面的一部分常常变化,可使用片段缓存。
Page Output Caching将对页面请求的响应放入缓存中,后续对此页面的请求将直接从缓存中获得信息而不是重建此页面。能够经过添加Page指令(高级别,声明实现)来实现,也可使用HTTPCachePolicy类来实现(低级别,程序实现)。本指南不打算介绍技术细节,只给出如何更好使用的指南和最佳实践。有四方面的内容:
一、决定缓存的内容
页面输出缓存可缓存各类信息,缓存这些信息意味着你不须要常常处理一样的数据和结果,包括:
·常常被请求但不不改变的静态页面;
·更新频率和时间已知的页面(如显示股票价格的页面);
·根据HTTP参数,有几个可能输出的页面(如根据城市的代号显示该城市天气状况的页面);
·从Web Service返回的结果;如:
[WebMethod(CacheDuration=60)]
public string HelloWorld()
{
return "Hello World";
}
二、缓存动态页面
基于输入参数、语言和浏览器类型改变的动态网页常常用到。你可使用OutputCache的如下属性来实现对动态页面的缓存:
VaryByParam——基于输入参数不一样缓存同一页面的多个版本;
VaryByHeader——基于Page Header的内容不一样缓存页面的多个版本;
VaryByCustom——经过声明属性和重载GetVaryByCustomString方法来定制缓存处理页面的多个版本;
VaryByControl——基于控件中asp对象属性的不一样来缓存控件。
对多个版本页面的缓存会下降可用内存,因此要仔细衡量缓存策略。s
三、控制缓存的位置
你可使用@OutputCache指令的OutputCacheLocation属性的枚举值来指定缓存的位置,如:
<%@ outputcache duration="10" varybyparam="none" Location="Server" %>
四、配置页面输出缓存
有两种方式控制,你可使用Page指令,也可使用Cache API编程实现。参考如下两段代码:
//代码1,使用指令
<%@ OutputCache Duration="20" Location="Server" VaryByParam="state" VaryByCustom="minorversion" VaryByHeader="Accept-Language"%>
//代码2,编程实现
private void Page_Load(object sender, System.EventArgs e)
{
// Enable page output caching.
Response.Cache.SetCacheability(HttpCacheability.Server);
// Set the Duration parameter to 20 seconds.
Response.Cache.SetExpires(System.DateTime.Now.AddSeconds(20));
// Set the Header parameter.
Response.Cache.VaryByHeaders["Accept-Language"] = true;
// Set the cached parameter to 'state'.
Response.Cache.VaryByParams["state"] = true;
// Set the custom parameter to 'minorversion'.
Response.Cache.SetVaryByCustom("minorversion");
…
}
有时候缓存整个页面并不灵活,同时内存的发但也比较大,这时候应考虑片段缓存。页面片段缓存适合如下类型的数据:
·建立开销很大的页面片段(控件);
·包含静态数据的页面片段;
·可被多个用户使用的页面片段;
·多个页面共享的页面片段(如公用菜单条)
如下是缓存部分页面的例子:
// Partial caching for 120 seconds
[System.Web.UI.PartialCaching(120)]
public class WebUserControl : System.Web.UI.UserControl
{
// Your Web control code
}
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;
.Net Remoting提供了跨应用程序域、跨进程、跨计算机的程序运行框架。服务器激活的对象有两种激活模式,其中Singleton类型任什么时候候都不会同时具备多个实例。若是存在实例,全部客户端请求都由该实例提供服务。若是不存在实例,服务器将建立一个实例,而全部后继的客户端请求都将由该实例来提供服务。因为 Singleton类型具备关联的默认生存期,即便任什么时候候都不会有一个以上的可用实例,客户端也不会总接收到对可远程处理的类的同一实例的引用。因此将数据缓存起来能够在多个客户端之间共享状态信息。
为了使用.Net Remoting实现缓存方案,要保证远程对象的租约不过时,而且远程对象没有被垃圾回收器销毁(对象租约是指在系统删除该对象前它在内存中的生存期)。当实现缓存时,重载MarshalByRefObject的InitializeLifetimeService方法而且返回null,这样就能保证租约永远不过时而且相关的对象生存期是无限的。如下代码是一个示例:
public class DatasetStore : MarshalByRefObject
{
// A hash table-based data store
private Hashtable htStore = new Hashtable();
//Returns a null lifetime manager so that GC won't collect the object
public override object InitializeLifetimeService() { return null; }
// Your custom cache interface
}
注意:因为这种方案的成本较高、性能上的限制而且可能形成系统不稳定,一般采用基于Sql Server的方案来替代。
内存映射文件提供独一无二的特性,容许应用程序经过指针来访问磁盘上的文件——与访问动态内存趣的方式同样。因此你能够将应用程序进程中的某个地址段的数据映射到文件中,供多个跨应用程序域或跨进程访问。
在windows中,代码和数据是以以种方式处理的,表现形式都是内存页,而在内存页背后都是磁盘上的文件。惟一的不一样磁盘上的文件类型不一样。代码后面是可执行的镜像,而数据后面则是系统的页面文件。当多个应用程序共享内存时,系统的性能会有明显提高。
你可使用内存映射文件的这种特性来实现同一台机器上的跨进程和跨应用程序域的缓存解决方案。基于内存映射文件的缓存方案包含如下组件:
·windows NT服务——启动时建立内存映射文件,中止时删除它。功能是向使用缓存的进程提供句柄。固然,也可使用命名的内存映射文件来提供操做接口;
·缓存托管组件(Cache Management Dll)——实现特定的缓存功能,好比:
a. 插入和删除数据项到缓存中;
b. 使用算法清除缓存,好比最后使用算法(Least Recently Used);
c. 保证数据不被篡改;
基于内存映射文件的缓存方案能够用在应用程序的每一个层中,但因为使用win32 API调用,因此并不容易实现。.Net 框架不支持内存映射文件,因此只能以非托管代码的方式运行,固然也不能利用.Net框架的有力特性,好比垃圾回收等。同时缓存数据项的管理功能须要定制开发,还要开发性能计数器来监控缓存的效果。
若是须要在进程回收(重启)、机器重启或电源故障的过程当中保持缓存数据的有效,基于内存的方案并不能知足要求。你可使用基于永久数据存储的方案,如SQL server数据库或NTFS文件系统。
SQL Server在使用sql语句或存储过程获得数据时,对varchar和varBinary类型的数据有8k的大小限制,你必须使用.Net 框架提供的Ado.Net SQLDataAdapter对象来访问datatable或dataset。
使用SQL Server缓存数据的优势:
·易于实现——使用.Net 框架和Ado.Net访问数据库至关方便;
·完善的安全模型和很高的健壮性;
·数据很是方便的共享;
·数据的持久保留。
·支持很大的数据量。
·方便的管理工具
固然,也有缺点:
·须要安装SQL Server,对小型应用来讲不合适;
·从新构造数据的性能和读取数据库的性能比较;
·网络负担。
静态变量经常使用来记录类的状态,你能够用它来建立定制的缓存对象。在定制的缓存类中将你的数据存储器声明为静态变量,而且提供维护接口(插入、删除和访问等)。若是没有特殊的缓存需求(好比依赖、失效策略等),使用静态变量缓存数据是很方便的。因为是在内存中,这种方案可提供对缓存数据的直接、高速的访问,当没有替代方案解决键值对的存储且对速度要求很高时,可使用静态变量。固然,在asp.net中,应该使用Cache对象。
你可使用这种方案保存大数据的对象,前提是它不常常更改。因为没有清除机制,大数据的内存消耗会影响性能。
你须要保证定制线程安全机制,或者使用.Net框架提供的同步对象,好比Hashtable。如下代码是使用Hashtable实现的例子:
static Hashtable mCacheData = new Hashtable();
应用范围:本方案的应用范围能够限制到类、模块或整个项目。若是变量定义为public,整个项目中的代码都能访问它,范围是整个应用程序域,实现了高效的共享。而它的生存期是和范围紧密相关的。
你可使用基于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有三种操做模式:
一、 进程内模式InProc——Session State信息在asp.net工做进程aspnet_wp.exe的进程的内存中存储。这是默认选项,这种状况下,若是进程或应用程序域被回收,则Session 状态信息也被回收;
二、 进程外模式State Server——状态信息序列化后保存在独立的状态进程中(AspNet_State.exe),因此状态信息能够保存在专门的服务器上(一个状态服务器State Server);
三、 Sql server模式——状态信息序列化后保存在SQL Server数据库中。
你能够经过调整配置文件中<sessionState>标签的mode属性来设置要使用的状态模式,好比使用SQL Server模式来在Web server场中共享状态信息。固然,这个优点也有缺点,就是状态信息须要序列化和反序列化,同时多了对数据库的写入和读取,因此性能上有开销,这是要仔细评估的。
当使用进程内模式时,状态信息保存在aspnet_wp.exe的进程中。因为在web场的状况下aspnet_wp.exe的多个实例在同一台服务器上运行,因此进程内模式不适用与web场的状况。
进程内模式是惟一支持Session_End事件的session模式,当用户会话超时或停止时,能够运行Session_End中的事件处理代码来清除资源。
StateServer模式使用指定的进程储存状态信息。由于它也是一种进程外模式,因此要保证你存储的对象是可序列化的,以支持跨进程传输。
当使用Session对象在web场的状况下使用时,必须保证web.config文件中的<MachineKey>元素在全部服务器上是惟一的。这样全部的服务器使用一样的加密方式,才能访问缓存中的数据。参考msdn中的“MachineKey元素”。
SQL Server模式下,当你使用信任链接(trusted_connection=true 或integrated security=sspi)访问Session state信息时,不能在asp.net中使用身份用户模拟。
默认状况下,SQL Server将状态信息存储在TempDb数据库中,它在每次Sql server服务启动时会自动从新建立,固然,你能够指定本身的数据库以便在数据库重启的过程当中也能保持数据。
你可使用Session对象缓存任何类型的.net框架数据,可是要了解对某种类型来讲最好的方式是什么。有如下几点须要说明:
一、 对基本类型(好比Int,Byte,String)来讲,可使用任何方式。由于在选用进程外方式时,asp.net使用一个优化的内部方法来序列化和反序列化基本类型的数据;
二、 对复杂类型(如ArrayList)来讲,只选用进程内方式。由于asp.net使用BinaryFormatter来序列化和反序列化这类数据,而这会影响性能的。固然,只有在State Server和SQL Server的方式下,才会进行序列化操做;
三、 缓存的安全问题,当在缓存中存储敏感数据时,须要考虑安全性,其它页面能够访问到缓存中的数据;
四、 避免缓存大数据,那会下降性能;
五、 这种缓存方式不支持过时策略、清除和依赖。
Asp.net提供了简单接口来操做Session State,并可以使用Web.Config进行简单设置,当配置文件中的设置改变时,可以在页面上马上体现出来,而不须要从新启动asp.net进程。
如下代码演示了使用SQL Server来实现Session数据的存储和使用。
<sessionState
mode="SQLServer"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1; Integrated Security=SSPI"
cookieless="false"
timeout="20"
/>
private void SaveSession(string CartID)
{
Session["ShoppingCartID"] = CartID;
}
private void CheckOut()
{
string CartID = (string)Session["ShoppingCartID"];
if(CartID != null)
{
// Transfer execution to payment page.
Server.Transfer("Payment.aspx");
}
else
{
// Display error message.
}
}
你还可使用客户端存储页面信息的方式来下降服务器的负担,这种方法提供最低的安全保障,但却有最快的性能表现。因为须要将数据发送到客户端存储,因此数据量有限。
实现客户端缓存的机制有如下五种,接下来将依次介绍:
·隐藏栏位(Hidden Field)
·View State
·隐藏帧(Hidden Frame)
·Cookies
·Query String
这五种方式分别适合于存储不一样类型的数据。
你能够将常常改变的少许数据保存在HtmlInputHidden中来维护页面的状态。当每次页面回送的过程当中,这些数据都会包含在表单中大送到服务器,因此你要使用HTTP POST方式来提交页面。
使用这种方式的优势以下:
缺点:
示例:
<input id="HiddenValue" type="hidden" value="Initial Value" runat="server" NAME="HiddenValue">
全部的Web Form页面和控件都包含有一个ViewState属性,在对同一页面屡次请求时能够保持页面内的值。它的内部实现是维护相应的hidden field,只不过是加密了的,因此比hidden field的安全性要好。
使用View State的性能表现很大程度上依赖于服务器控件的类型。通常来讲,Label,TextBox,CheckBox,RadioButton,HyperLink的性能要好一些,而DropdownList,ListBox,DataGrid和DataList就要差不少,由于包含的数据量太大,因此每次页面回送都很耗时间。
有些状况下不推荐使用ViewState,好比:
一、 不须要回送的页面避免使用;
二、 避免使用ViewState保存大数据量;
三、 在须要使用会话超时的状况下避免使用它,由于它没有超时操做。
ViewState的性能表现和Hidden Field的是相似的,可是具备更高的安全性。
优势:
缺点:
示例代码以下:
public class ViewStateSample : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
if (!Page.IsPostBack)
{
// Save some data in the ViewState property.
this.ViewState["EnterTime"] = DateTime.Now.ToString();
this.ViewState["UserName"] = "John Smith";
this.ViewState["Country"] = "USA";
}
}
…
private void btnRefresh_Click(object sender, System.EventArgs e)
{
// Get the saved data in the view state and display it.
this.lblTime.Text = this.ViewState["EnterTime"].ToString();
this.lblUserName.Text = this.ViewState["UserName"].ToString();
this.lblCountry.Text = this.ViewState["Country"].ToString();
}
}
你可使用Hidden Frame在客户端缓存数据,这就避免了使用hidden field和使用view state时每次页面回送时的缓存数据往返。好比你能够秘密的加载多个页面所须要的图片,这并不会消耗服务器资源。
优势:
a. 能够加载较多数据而不仅是单个栏位的值;
b. 避免了没必要要的屡次回送中的数据往来;
c. 能够缓存和读取在不一样表单中存储的数据项(能够同时缓存多个页面的数据);
d. 能够访问同一站点不一样frame中的客户端脚本数据。
缺点:
a. 有些浏览器不支持frame;
b. 源代码能够在客户端看到,有潜在的安全威胁;
c. 隐藏frame的数量没有限制,若是框架页面包含较多hidden frame的话,在首次加载时速度会有限制。
示例代码以下:
<FRAMESET cols="100%,*">
<FRAMESET rows="100%,*">
<FRAME src="contents_of_frame1.html">
</FRAMESET>
<FRAME src="contents_of_hidden_frame.html">
<FRAME src="contents_of_hidden_frame.html" frameborder="0" noresize scrolling="yes">
<NOFRAMES>
<P>This frameset document contains:
<A href="contents_of_frame1.html" TARGET="_top">Some neat contents</A>
</NOFRAMES>
</FRAMESET>
Cookie是能够在客户端存储数据另外一种方案,这里不过多介绍。
优势:
缺点:
参看示例代码:
public class CookiesSample : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
if (this.Request.Cookies["preferences1"] == null)
{
HttpCookie cookie = new HttpCookie("preferences1");
cookie.Values.Add("ForeColor","black");
cookie.Values.Add("BackColor","beige");
cookie.Values.Add("FontSize","8pt");
cookie.Values.Add("FontName","Verdana");
this.Response.AppendCookie(cookie);
}
}
private string getStyle(string key)
{
string val = null;
HttpCookie cookie= this.Request.Cookies["preferences1"];
if (cookie != null)
{
val = cookie.Values[key];
}
return val;
}
}
Query String是在用户请求的URL后加上相应的参数来使用的,只能在使用HTTP GET方式调用URL时可用。
优势:
d. 不须要服务器资源,参数附在URL里面;
e. 应用面广,几乎全部浏览器都支持;
f. 实现简单,服务端使用Request对象可直接读取。
缺点:
a. 参数直接对用户可见,不安全;
b. URL长度的限制,多数浏览器不支持超过255字符的URL。
示例代码:
http://www.cache.com/login.asp?user=ronen
string user = Request.QueryString["User"];
下表是使用客户端缓存的建议:
缓存机制 |
适用状况 |
Hidden Field |
当安全性要求不高时,在页面中存储少许数据以提交到服务器上的本页面或其它页面。 |
ViewState |
在单个页面中存储少许信息知足页面屡次回传的要求。提供基本的安全机制。 |
Hidden Frame |
在客户端存储数据,避免了数据到服务器的回传。 |
Cookie |
当安全性要求不高时,存储少许数据在客户端。 |
Query String |
当使用页面地址链接页面时传输少许参数。 |
IE提供了缓存机制,能够实现对页面的数据进行缓存,同时能够指定过时时间。用户在IE中请求此页面,若是当过时时间没有到,则自动从缓存中提取并呈现;不然,就到服务器上获取新版本。IE对页面的缓存能够在IIS中设置。
适合在Internet Explorer中缓存的内容
优势:
缺点:
示例代码:
<META HTTP-EQUIV="expires" CONTENT="Tue, 23 Jun 2002 01:46:05 GMT">
本文档介绍了缓存和状态数据存储的相关概念,以及可供使用的缓存技术,介绍了各类技术的适用范围,并对其优缺点进行了说明,另外有简单的性能比较和简单的示例代码。更多内容请参看相应的参考资料。