使用 InProc Session 导致的性能问题
🏷️ ASP.NET MVC
现象
最近生产环境偶尔会卡顿,服务器连接数飙升,ThreadAbortException
异常增多。客户端上页面经常打不开,但是关掉浏览器后再打开就又好了。
根据 会话状态 Session 做了个类似的 Sample,确实会出现性能问题。
在官方文档 Chapter 10 — Improving Web Services Performance # State Management 中查到了相关的描述。
Maintaining session state has an impact on concurrency. If you keep data in session state, Web services calls made by one client are serialized by the ASP.NET runtime. Two concurrent requests from the same client are queued up on the same thread in the Web service — the second request waits until the first request is processed. If you do not use session data in a Web method, you should disable sessions for that method.
Note Enabling session state pins each session to one thread (to protect session data). Concurrent calls from the same session are serialized once they reach the server, so they have to wait for each other, regardless of the number of CPUs.
从上可以看出多个同 Session Id 的请求同时访问时,后执行的请求会等待前面占用 Session 的请求结束后才会执行。(类似于多线程使用同一个实例时的锁等待)
解决方案
MVC 4 在 Controller 上增加
SessionState
注解。csharp[SessionState(SessionStateBehavior.ReadOnly)]
WebForm 中在
Page
标签中设置EnableSessionState
属性(该属性有 3 个值:False、ReadOnly 和 True(参考 PagesEnableSessionState Enum))。javascriptEnableSessionState="ReadOnly"
在 Web.config -> pages 标签中设置
enableSessionState
属性。在 Web.config 的 system.web -> pages 标签中设置
enableSessionState
为 ReadOnly 后,所有页面的 Session 都将变成只读,不能保存 Session。即使在页面的代码里向 Session 中赋了值,也不会将 SessionId 设置到客服端(客户端还没有 SessionId 的情况下)。xml<system.web> <pages enableSessionState="ReadOnly"> </pages> </system.web>
在 Web Services 中通过
WebMethod
特性的EnableSession
来禁用 Session。csharp[WebMethod(EnableSession=true)] YourWebMethod() { ... }
如果使用了 WebService,由于
WebMethod
特性仅可以通过EnableSession
属性设置是否启用 Session,所以无法将其设置为 ReadOnly。由于我们的项目采用的是通过 SessionId + Redis 来保存用户信息,可以采用如下方法来解决。
首先,在 Web.config -> pages 中设置
enableSessionState
为ReadOnly
;其次,在 Global.asax 中增加
Session_Start
方法。无论页面的处理中是否使用了 Session,总是会将 SessionId 设置到客户端 Cookie(即使在 Web.config 将enableSessionState
设置为了 ReadOnly);csharpprotected void Session_Start(object sender, EventArgs e) { }
最后,将所有的
WebMethod
设置成EnableSession = false
,并通过如下方法获取当前请求的 Session Id;csharp// Get the Web application configuration object. System.Configuration.Configuration configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/"); // Get the section related object. System.Web.Configuration.SessionStateSection sessionStateSection = (System.Web.Configuration.SessionStateSection) configuration.GetSection("system.web/sessionState"); // Get the session state's cookie name.(configed in Web.config) string cookieName = sessionStateSection.CookieName; // Get the current session id. string sessionId = HttpContext.Current.Request.Cookies[sessionStateSection.CookieName].Value;
参考
- Asp.net mvc 中处理同一个 session 的并行请求的问题
- asp.net Global.asax 注册 session_start 事件后引发的性能问题
- WebMethodAttribute.EnableSession Property
- Chapter 10 — Improving Web Services Performance
- Web Service 是否可以配置类似页面的 EnableSessionState
- Page 指令 的 EnableSessionState="ReadOnly",怎么在 web.config 里面设置
- 会话状态 Session
- 【异常记录 (九)】System.Threading.ThreadAbortException: 正在中止线程
- HttpRuntimeSection.ExecutionTimeout Property
- 如何设置 ASP.NET 页面的运行超时时间
- SessionStateModule Class
- PagesSection.EnableSessionState Property
- 会话状态事件
- 会话状态模式
- 性能概述
- WebMethodAttribute.EnableSession Property
- SessionStateSection Class
- SessionStateSection.CookieName Property