缓存技术(二)
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数据库中。
你可以通过调整配置文件中<sessionState>标签的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文件中的<MachineKey>元素在所有服务器上是唯一的。这样所有的服务器使用同样的加密方式,才能访问缓存中的数据。参考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数据的存储和使用。
<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.
}
}
2.7 使用Asp.net客户端缓存和状态
你还可以使用客户端存储页面信息的方式来降低服务器的负担,这种方法提供最低的安全保障,但却有最快的性能表现。由于需要将数据发送到客户端存储,所以数据量有限。
实现客户端缓存的机制有以下五种,接下来将依次介绍:
·隐藏栏位(Hidden Field)
·View State
·隐藏帧(Hidden Frame)
·Cookies
·Query String
这五种方式分别适合于存储不同类型的数据。
2.7.1 使用Hidden Field
你可以将经常改变的少量数据保存在HtmlInputHidden中来维护页面的状态。当每次页面回送的过程中,这些数据都会包含在表单中大送到服务器,所以你要使用HTTP POST方式来提交页面。
使用这种方式的优点如下:
不需要服务器资源,直接从页面中读取;
几乎所有的浏览器都支持;
实现简单;
由于数据在页面中,所以在web Farm的情况下也可使用。
缺点:
由于可以通过查看源码看到,所以可能会被篡改;
不支持复杂格式的数据,复杂数据必须使用解析字符串的方式来间接得到;
当存储大数据的时候会影响性能。
示例:
<input id=”HiddenValue” type=”hidden” value=”Initial Value” runat=”server” NAME=”HiddenValue”>
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类似,在客户端数据仍然有潜在的安全威胁。
示例代码如下:
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();
}
}
2.7.3 使用Hidden Frame
你可以使用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>
2.7.4 使用Cookies
Cookie是可以在客户端存储数据另一种方案,这里不过多介绍。
优点:
不需要服务器资源;数据保存在客户端,在用户请求时发送到服务器上。
使用简单。Cookie包含简单的键值对,主要保存轻量级的文本数据。
支持过期策略;可以指定当会话结束时过期,也可指定一个时间策略。
缺点:
数据量的限制;
用户可能设置为拒绝Cookie;
安全问题;用户可能更改机器上的cookie信息,造成基于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;
}
}
2.7.5 使用Query String
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"];
2.7.6 小结
下表是使用客户端缓存的建议:
缓存机制
适用情况
Hidden Field
当安全性要求不高时,在页面中存储少量数据以提交到服务器上的本页面或其它页面。
ViewState
在单个页面中存储少量信息满足页面多次回传的要求。提供基本的安全机制。
Hidden Frame
在客户端存储数据,避免了数据到服务器的回传。
Cookie
当安全性要求不高时,存储少量数据在客户端。
Query String
当使用页面地址连接页面时传输少量参数。
2.8 使用Internet Explorer缓存
IE提供了缓存机制,可以实现对页面的数据进行缓存,同时可以指定过期时间。用户在IE中请求此页面,如果当过期时间没有到,则自动从缓存中提取并呈现;否则,就到服务器上获取新版本。IE对页面的缓存可以在IIS中设置。
适合在Internet Explorer中缓存的内容
页面中的图像文件;
静态的文本内容;
页面的标题栏和页脚内容——改变频率很低,可以给用户一个迅速相应;
网站的首页——更改次数页时相对较少的;
使用动态HTML在客户端保存的特定数据。比如客户自定义的颜色和布局设置信息。
优点:
减少对服务器的请求和网络负担;
支持离线浏览;
可以实现基于XML的客户端复杂应用。
缺点:
客户端的过期时间必须预先指定而不能依赖于服务器更新;IE采用的是Lazy更新机制,优先从缓存中提取数据;
对其它客户端浏览器没有作用;
存储的数据没有加密,不能保证客户端数据安全。
示例代码:
<META HTTP-EQUIV=”expires” CONTENT=”Tue, 23 Jun 2002 01:46:05 GMT”>
3 总结
本文档介绍了缓存和状态数据存储的相关概念,以及可供使用的缓存技术,介绍了各种技术的适用范围,并对其优缺点进行了说明,另外有简单的性能比较和简单的示例代码。更多内容请参看相应的参考资料。

using System.Collections;
class Test 
}
foreach(string item in stackTest) 

using
namespace www.gosoa.com.cn
public class baseClass 
}