Jam*_*mes 272 architecture asp.net iis performance session
我刚刚发现,ASP.Net Web应用程序中的每个请求在请求开始时都会获得一个Session锁,然后在请求结束时释放它!
如果这对你造成影响,就像我一开始对你而言,这基本上意味着以下几点:
任何时候ASP.Net网页需要很长时间才能加载(可能是由于数据库调用速度慢等),并且用户决定他们想要导航到另一个页面,因为他们厌倦了等待,他们不能!ASP.Net会话锁强制新页面请求等待,直到原始请求完成其缓慢的负载.Arrrgh.
任何时候UpdatePanel加载缓慢,并且用户决定在UpdatePanel完成更新之前导航到另一个页面......他们不能!ASP.net会话锁强制新页面请求等待原始请求完成其缓慢的负载.双Arrrgh!
那有什么选择呢?到目前为止,我想出了:
我真的不敢相信ASP.Net微软团队会在版本4.0的框架中留下如此巨大的性能瓶颈!我错过了一些明显的东西吗 为会话使用ThreadSafe集合有多难?
Joe*_*ler 200
如果您的页面未修改任何会话变量,则可以选择退出此锁定的大部分内容.
<% @Page EnableSessionState="ReadOnly" %>
Run Code Online (Sandbox Code Playgroud)
如果您的页面没有读取任何会话变量,则可以完全退出此锁定页面.
<% @Page EnableSessionState="False" %>
Run Code Online (Sandbox Code Playgroud)
如果您的所有页面都没有使用会话变量,只需关闭web.config中的会话状态即可.
<sessionState mode="Off" />
Run Code Online (Sandbox Code Playgroud)
我很好奇,如果它不使用锁,你认为"一个ThreadSafe集合"会如何成为线程安全的?
编辑:我应该通过"选择退出大部分锁定"来解释我的意思.可以同时为给定会话处理任意数量的只读会话或无会话页面,而不会相互阻塞.但是,读写会话页面在完成所有只读请求之前无法开始处理,并且在运行时,它必须具有对该用户会话的独占访问权限才能保持一致性.锁定单个值是行不通的,因为如果一个页面将一组相关值更改为一个组,该怎么办?您如何确保同时运行的其他页面能够获得用户会话变量的一致视图?
如果可能的话,我建议你尽量减少会话变量的修改.这将允许您使大多数页面成为只读会话页面,从而增加了来自同一用户的多个同时请求不会相互阻塞的可能性.
Jam*_*mes 83
好的,这么大的道具给Joel Muller所有的投入.我的最终解决方案是使用本MSDN文章末尾详细介绍的Custom SessionStateModule:
http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx
这是:
这对我们的应用程序的"快照"感觉产生了巨大的影响.我仍然无法相信ASP.Net Session的自定义实现会锁定整个请求的会话.这给网站增加了如此大量的迟缓.从我必须做的在线研究数量(以及与几位经验丰富的ASP.Net开发人员的对话)来看,很多人都经历过这个问题,但是很少有人能够找到原因.也许我会写信给Scott Gu ...
我希望这能帮助那里的一些人!
gre*_*mac 31
我开始使用AngiesList.Redis.RedisSessionStateModule,除了使用(非常快)Redis服务器进行存储(我使用的是Windows端口 - 虽然还有一个MSOpenTech端口),它绝对没有锁定会话.
在我看来,如果您的应用程序以合理的方式构建,这不是问题.如果您确实需要锁定的,一致的数据作为会话的一部分,您应该专门实现锁定/并发检查.
在我看来,MS决定默认锁定每个ASP.NET会话只是为了处理糟糕的应用程序设计,这是一个糟糕的决定.特别是因为大多数开发人员似乎没有/甚至没有意识到会话被锁定,更不用说应用程序显然需要结构化,以便您可以尽可能地执行只读会话状态(在可能的情况下选择退出) .
Der*_*ter 20
我根据这个帖子中发布的链接准备了一个库.它使用MSDN和CodeProject中的示例.感谢詹姆斯.
我也做了Joel Mueller建议的修改.
代码在这里:
https://github.com/dermeister0/LockFreeSessionState
HashTable模块:
Install-Package Heavysoft.LockFreeSessionState.HashTable
Run Code Online (Sandbox Code Playgroud)
ScaleOut StateServer模块:
Install-Package Heavysoft.LockFreeSessionState.Soss
Run Code Online (Sandbox Code Playgroud)
定制模块:
Install-Package Heavysoft.LockFreeSessionState.Common
Run Code Online (Sandbox Code Playgroud)
如果要实现Memcached或Redis的支持,请安装此软件包.然后继承LockFreeSessionStateModule类并实现抽象方法.
该代码尚未在生产中进行测试.还需要改进错误处理.当前实施中没有遇到例外情况.
一些使用Redis的无锁会话提供程序:
Geo*_*kis 11
除非您的应用程序有特殊需求,否则我认为您有两种方法:
会话不仅是线程安全的,而且是状态安全的,您知道在当前请求完成之前,每个会话变量都不会从另一个活动请求更改.为了实现这一点,您必须确保会话将被锁定,直到当前请求完成.
您可以通过多种方式创建类似行为的会话,但如果它不锁定当前会话,则不会是"会话".
对于您提到的具体问题,我认为您应该检查HttpContext.Current.Response.IsClientConnected.这对于防止不必要的执行和在客户端上等待很有用,虽然它不能完全解决这个问题,因为这只能通过池方式而不是异步方式使用.
如果您使用的是更新版本Microsoft.Web.RedisSessionStateProvider
(从开始3.0.2
),则可以将其添加到其中web.config
以允许并发会话。
<appSettings>
<add key="aspnet:AllowConcurrentRequestsPerSession" value="true"/>
</appSettings>
Run Code Online (Sandbox Code Playgroud)
对于 ASPNET MVC,我们做了以下工作:
SessionStateBehavior.ReadOnly
通过覆盖设置所有控制器的操作DefaultControllerFactory
SessionStateBehavior.Required
创建自定义 ControllerFactory 并覆盖GetControllerSessionBehavior
.
protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
{
var DefaultSessionStateBehaviour = SessionStateBehaviour.ReadOnly;
if (controllerType == null)
return DefaultSessionStateBehaviour;
var isRequireSessionWrite =
controllerType.GetCustomAttributes<AcquireSessionLock>(inherit: true).FirstOrDefault() != null;
if (isRequireSessionWrite)
return SessionStateBehavior.Required;
var actionName = requestContext.RouteData.Values["action"].ToString();
MethodInfo actionMethodInfo;
try
{
actionMethodInfo = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
catch (AmbiguousMatchException)
{
var httpRequestTypeAttr = GetHttpRequestTypeAttr(requestContext.HttpContext.Request.HttpMethod);
actionMethodInfo =
controllerType.GetMethods().FirstOrDefault(
mi => mi.Name.Equals(actionName, StringComparison.CurrentCultureIgnoreCase) && mi.GetCustomAttributes(httpRequestTypeAttr, false).Length > 0);
}
if (actionMethodInfo == null)
return DefaultSessionStateBehaviour;
isRequireSessionWrite = actionMethodInfo.GetCustomAttributes<AcquireSessionLock>(inherit: false).FirstOrDefault() != null;
return isRequireSessionWrite ? SessionStateBehavior.Required : DefaultSessionStateBehaviour;
}
private static Type GetHttpRequestTypeAttr(string httpMethod)
{
switch (httpMethod)
{
case "GET":
return typeof(HttpGetAttribute);
case "POST":
return typeof(HttpPostAttribute);
case "PUT":
return typeof(HttpPutAttribute);
case "DELETE":
return typeof(HttpDeleteAttribute);
case "HEAD":
return typeof(HttpHeadAttribute);
case "PATCH":
return typeof(HttpPatchAttribute);
case "OPTIONS":
return typeof(HttpOptionsAttribute);
}
throw new NotSupportedException("unable to determine http method");
}
Run Code Online (Sandbox Code Playgroud)
获取会话锁属性
[AttributeUsage(AttributeTargets.Method)]
public sealed class AcquireSessionLock : Attribute
{ }
Run Code Online (Sandbox Code Playgroud)
将创建的控制器工厂连接到 global.asax.cs
ControllerBuilder.Current.SetControllerFactory(typeof(DefaultReadOnlySessionStateControllerFactory));
Run Code Online (Sandbox Code Playgroud)
现在,我们可以同时read-only
和read-write
在单个会话状态Controller
。
public class TestController : Controller
{
[AcquireSessionLock]
public ActionResult WriteSession()
{
var timeNow = DateTimeOffset.UtcNow.ToString();
Session["key"] = timeNow;
return Json(timeNow, JsonRequestBehavior.AllowGet);
}
public ActionResult ReadSession()
{
var timeNow = Session["key"];
return Json(timeNow ?? "empty", JsonRequestBehavior.AllowGet);
}
}
Run Code Online (Sandbox Code Playgroud)
注意:即使在只读模式下,ASPNET 会话状态仍然可以写入,并且不会抛出任何形式的异常(它只是不锁定以保证一致性),因此我们必须小心标记
AcquireSessionLock
需要写入会话状态的控制器操作。
小智 6
将控制器的会话状态标记为只读或禁用将解决该问题。
您可以使用以下属性装饰控制器以将其标记为只读:
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
Run Code Online (Sandbox Code Playgroud)
System.Web.SessionState.SessionStateBehavior枚举具有以下值:
归档时间: |
|
查看次数: |
113796 次 |
最近记录: |