首页 > .NET/C开发 > 缓存技术(二)

缓存技术(二)

2009年10月19日 发表评论 阅读评论

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         总结
本文档介绍了缓存和状态数据存储的相关概念,以及可供使用的缓存技术,介绍了各种技术的适用范围,并对其优缺点进行了说明,另外有简单的性能比较和简单的示例代码。更多内容请参看相应的参考资料。

 

分类: .NET/C开发 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.