开源项目大家谈-网站性能调校-Page State Persistence

简介: 之所以用这个题目是因为很多人常常问我研究开源项目的意义,有一些开源项目在别人眼里看起来完全没有搞头,是一些没有实用价值的项目。其实开源项目往往是新技术的试验田,是全世界优秀程序开发者智慧的汇集,如果你仔细研读这些开源项目,得到的不仅仅是这个项目的功能,而是观摩新的技术,学习比你更聪明人的智慧。

之所以用这个题目是因为很多人常常问我研究开源项目的意义,有一些开源项目在别人眼里看起来完全没有搞头,是一些没有实用价值的项目。其实开源项目往往是新技术的试验田,是全世界优秀程序开发者智慧的汇集,如果你仔细研读这些开源项目,得到的不仅仅是这个项目的功能,而是观摩新的技术,学习比你更聪明人的智慧。

我一直研究的一个开源项目是DotNetNuke(简称DNN),也许你不知道这是一个什么系统,不过你不用关心这是一个什么系统,因为我要讨论的技术在任何一个ASP.NET网站里都有可能用到,只是用这个开源项目做示范罢了,不过你会看到在开源项目里,MSDN里那些死板的技术说明是如何巧妙发挥功能。

开源网站系统提供的性能设置选项

在DNN开源项目里,有一些设置可以调校网站的性能,包括以下这几个:

image

我会花几篇文章逐个讨论一下这几个选项对网站性能的影响,并给出一些技术分析。 在这一篇文章里,我讨论Page State Persistence这个设置。

什么是Page Sate Persistence

我想大家对ViewState一定不陌生,ViewState是ASP.NET相对ASP新增的一个强大的功能,能够保存一个页面的state。简单的说,就是保存你提交页面时,文本框,下拉列表等等在页面提交那一时刻的值,这样万一你填写的内容通不过检验,就可以用这些信息来还原之前的状态(当然,用处不止这些)。知道ViewSate的人,一般都知道ViewSate使用一个hidden input来保存页面的state信息。网上有很多这样的文章,大家可以Google一下。那这个ViewSate跟性能又有什么关系呢?因为这个hidden input是要跟随PostBack信息在客户端和服务器之间来回传递的,如果这个值太大,自然会影响性能。当然,除了大小,还有一个方面就是ViewState存储的位置了,如果我们不来回传递ViewState的值,而是存储在服务器这一端,自然会减少ViewState在网络上传输占用的时间,但同时却加重了服务器的负担。

可能很多人不知道ASP.NET 2.0的一个新特性就是可以通过重载PageStatePersister类从而实现自定义page ViewState的存储位置。在ASP.NET v1.x里,ViewState只能是存储在之前提到的那个隐藏input元素中。在ASP.NET 2.0 中,新增的SessionPageStatePersister类就提供了把ViewState存储在session里的功能。

开源项目DNN构架如何利用这一新特性

这个开源项目重写了页面的基类,在它自己的基类中,有一个PageStatePersister只读属性,这个属性会根据用户的设置,返回一个System.Web.UI.PageStatePersister实体,之后运行的页面就会用这个实体去实现ViewState的存储,从而实现由用户选择在哪里存储ViewState,从而调节性能。

代码如下:

Protected Overrides ReadOnly Property PageStatePersister() As System.Web.UI.PageStatePersister
Get
'Set ViewState Persister to default (as defined in Base Class)
Dim _persister As PageStatePersister = MyBase.PageStatePersister
If Not DotNetNuke.Common.Globals.HostSettings("PageStatePersister") Is Nothing Then
Select Case DirectCast(DotNetNuke.Common.Globals.HostSettings("PageStatePersister"), String)
Case "M"
_persister = New CachePageStatePersister(Me)
Case "D"
_persister = New DiskPageStatePersister(Me)
Case "S"
_persister = New SessionPageStatePersister(Me)
End Select
End If
Return _persister
End Get
End Property 

从代码我们可以看到,如果用户选择“Page”,那就使用默认的hidden input元素在页面上存储viewstate(在代码的处理上,是判断其它非选择“Page”项的情况,所以你找不到 Case "P" 这一句);如果用户选用的是"Memory",那么在Case "M"这一句,就会返回一个CachePageStatePersister,这是这个开源系统自定义的一个viewstate处理类。那么DNN开源系统就会使用Cache在服务器端存储viewstate的信息,也就是存储在服务器的“Memory”中。

如果是"D",那么是存储在服务端的文件里,所以是"Disk",但系统似乎保留了这个设置,没有提供界面。

如果是"S",那么是存储在Session里面。这个实现是ASP.NET 2.0 已经提供了的。

如何实现

其实比较简单,在ASP.NET 2.0 里, 抽象类PageStatePersister 实现了存储page state到其它地方的基本功能,你只要重写这个抽象类提供的Load和Save方法就可以了。

我们看看DNN开源项目实现的一个CachePageStatePersister:

Imports System.Text
 
Namespace DotNetNuke.Framework
 
''' -----------------------------------------------------------------------------
''' Namespace:  DotNetNuke.Framework
''' Project:    DotNetNuke
''' Class:      CachePageStatePersister
''' -----------------------------------------------------------------------------
''' <summary>
''' CachePageStatePersister provides a cache based page state peristence mechanism
''' </summary>
''' <history>
'''        [cnurse]    11/30/2006    documented
''' </history>
''' -----------------------------------------------------------------------------
Public Class CachePageStatePersister
Inherits PageStatePersister
 
Private Const VIEW_STATE_CACHEKEY As String = "__VIEWSTATE_CACHEKEY"
 
''' -----------------------------------------------------------------------------
''' <summary>
''' Creates the CachePageStatePersister
''' </summary>
''' <history>
'''     [cnurse]        11/30/2006    Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Sub New(ByVal page As Page)
MyBase.New(page)
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' Loads the Page State from the Cache
''' </summary>
''' <history>
'''     [cnurse]        11/30/2006    Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Overrides Sub Load()
 
' Get the cache key from the web form data
Dim key As String = TryCast(Page.Request.Params(VIEW_STATE_CACHEKEY), String)
 
'Abort if cache key is not available or valid
If String.IsNullOrEmpty(key) Or Not key.StartsWith("VS_") Then
Throw New ApplicationException("Missing valid " + VIEW_STATE_CACHEKEY)
End If
Dim state As Pair = TryCast(DataCache.GetPersistentCacheItem(key, GetType(Pair)), Pair)
 
If Not state Is Nothing Then
'Set view state and control state
ViewState = state.First
ControlState = state.Second
End If
'Remove this ViewState from the cache as it has served its purpose
DataCache.RemovePersistentCacheItem(key)
 
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' Saves the Page State to the Cache
''' </summary>
''' <history>
'''     [cnurse]        11/30/2006    Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Overrides Sub Save()
 
'No processing needed if no states available
If ViewState Is Nothing And ControlState Is Nothing Then
Exit Sub
End If
'Generate a unique cache key
Dim key As New StringBuilder()
With key
.Append("VS_")
.Append(IIf(Page.Session Is Nothing, Guid.NewGuid().ToString(), Page.Session.SessionID))
.Append("_")
.Append(DateTime.Now.Ticks.ToString())
End With
'Save view state and control state separately
Dim state As New Pair(ViewState, ControlState)
 
'Add view state and control state to cache
DataCache.SetCache(key.ToString(), state, Nothing, DateTime.Now.AddMinutes(Page.Session.Timeout), System.Web.Caching.Cache.NoSlidingExpiration, True)
 
'Register hidden field to store cache key in
Page.ClientScript.RegisterHiddenField(VIEW_STATE_CACHEKEY, key.ToString())
End Sub
End Class
End Namespace

对性能有什么影响

性能永远是一个博弈的问题,没有绝对,只有如何平衡。把viewstate放在page的hidden input里面自然会增加客户端的处理时间以及网路传输时间。把viewstate放在服务器端自然会消耗服务器的内存(硬盘)和CPU,所以,没有最好的设置,只有最合适的设置。

  • 如果使用专属的服务器,并且配置较高,使用"Memory"模式,这样会提高网站的速度。
  • 对于一般的应用,使用默认的viewstate设置就可以了,也就是使用hidden input,针对这个开源系统,就是选择"Page"。
  • 如果你发现有一些页面的viewstate特别大,消耗了大量的网络传输时间,你可以选用memory模式,把viewstate放在服务端的Cache里。
  • 很明显,如果使用Disk的方式,会比使用Cache的慢,这种方式也许可以用在那些对反映速度要求不高,viewstate又很大的页面上。
  • 对于存储在Session里的实现方式,之前放在hidden INPUT里的信息会通过BASE64编码在Session里面传递,估计性能上比默认直接使用hidden input的要慢,毕竟你还要进行编码的转换,不过可能对安全性上有帮助,只是我的推测。希望有高手指出错误.
 
参考文档:
ScottGu's Blog: PageStatePersister Extensibility with ASP.NET 2.0
PageStatePersister class in 2.0 - To persist state on page or Session or even on Database.
相关文章
|
机器学习/深度学习 数据可视化 算法
基于深度学习的花卉检测与识别系统(YOLOv5清新界面版,Python代码)
基于深度学习的花卉检测与识别系统(YOLOv5清新界面版,Python代码)
1381 0
|
5天前
|
云安全 人工智能 自然语言处理
|
9天前
|
人工智能 Java API
Java 正式进入 Agentic AI 时代:Spring AI Alibaba 1.1 发布背后的技术演进
Spring AI Alibaba 1.1 正式发布,提供极简方式构建企业级AI智能体。基于ReactAgent核心,支持多智能体协作、上下文工程与生产级管控,助力开发者快速打造可靠、可扩展的智能应用。
863 26
|
4天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
450 4
|
5天前
|
机器学习/深度学习 人工智能 数据可视化
1秒生图!6B参数如何“以小博大”生成超真实图像?
Z-Image是6B参数开源图像生成模型,仅需16GB显存即可生成媲美百亿级模型的超真实图像,支持中英双语文本渲染与智能编辑,登顶Hugging Face趋势榜,首日下载破50万。
382 19
|
12天前
|
数据采集 人工智能 自然语言处理
Meta SAM3开源:让图像分割,听懂你的话
Meta发布并开源SAM 3,首个支持文本或视觉提示的统一图像视频分割模型,可精准分割“红色条纹伞”等开放词汇概念,覆盖400万独特概念,性能达人类水平75%–80%,推动视觉分割新突破。
825 59
Meta SAM3开源:让图像分割,听懂你的话
|
2天前
|
弹性计算 网络协议 Linux
阿里云ECS云服务器详细新手购买流程步骤(图文详解)
新手怎么购买阿里云服务器ECS?今天出一期阿里云服务器ECS自定义购买流程:图文全解析,阿里云服务器ECS购买流程图解,自定义购买ECS的设置选项是最复杂的,以自定义购买云服务器ECS为例,包括付费类型、地域、网络及可用区、实例、镜像、系统盘、数据盘、公网IP、安全组及登录凭证详细设置教程:
176 114