默认情况下如何并发执行具有相同会话的多个 ASP.NET 请求?
How can multiple ASP.NET requests with same session can be executed concurrently by default?
ASP.NET MVC 4.0 应用程序在我们的生产环境中时常会冻结。
在尝试使用 Windbg(+ SOS、SOSEX、NETEXT 和 MEX)和两个生产过程内存转储分析问题时,我注意到问题总是在同时处理两个请求(正在执行 .NET 业务代码)时出现相同的会话。据我所知,如果不自定义会话行为(使用配置、属性或 ControllerFactory),这是不可能的。在此应用程序中(过度)使用了会话,并且尚未自定义会话行为。我能找到的唯一设置 (controllers/code/config) 是 web.config:
中的这个
<sessionState timeout="720" />
如果有人可以帮助我理解这个案例,这里是我的 windbg 会话的结果。
!whttp
HttpContext Thread Time Out Running Status Verb Url
0000002d0c7754b0 26 00:01:50 00:36:55 200 POST /Ctrl/Action
0000002e06a2e7e8 27 00:01:50 00:41:45 200 POST /Ctrl/Action
[...]
这是永远耗时的两个 HTTP 请求。
!DumpAspNetSession -ctx 0000002d0c7754b0
System.Web.SessionState.HttpSessionStateContainer: 0x0000002d0c7a9a38
Key Value
================================ ======================================================
VarSession 0000002e06587000 (App.VarSession)
!DumpAspNetSession -ctx 0000002e06a2e7e8
System.Web.SessionState.HttpSessionStateContainer: 0x0000002e06a3a810
Key Value
================================ ======================================================
VarSession 0000002e06587000 (App.VarSession)
与上面的 HttpContext 匹配的会话持有相同的数据(App.VarSession 类型)。
!wcookie
0000002d0c7754b0 /Ctrl/Action (200 NULL) Running (00:36:55)
======================================================================================
ASP.NET_SessionId=im3clvnd0auw0te3nkzzq1p0
======================================================================================
0000002e06a2e7e8 /Ctrl/Action (200 NULL) Running (00:41:45)
======================================================================================
ASP.NET_SessionId=im3clvnd0auw0te3nkzzq1p0
这个最新的命令显示这两个请求确实与同一个会话相关。
~26s
0:026> !CLRStack
OS Thread Id: 0x122c (26)
Child SP IP Call Site
0000002f2de47750 00007ff91a2042db System.Linq.Enumerable+d__14`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()
0000002f2de477b0 00007ff91a2095b7 System.Linq.Enumerable.FirstOrDefault[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1, System.Func`2)
0000002f2de47810 00007ff8be3ce1fe App.DALApp.GetData(...)
~27s
0:027> !CLRStack
OS Thread Id: 0x313c (27)
Child SP IP Call Site
0000002f2f976f20 00007ff8be5022ef App.DALApp.b__257(...)
0000002f2f976f60 00007ff91a2042ab System.Linq.Enumerable+d__14`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()
0000002f2f976fc0 00007ff91a2095b7 System.Linq.Enumerable.FirstOrDefault[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1, System.Func`2)
0000002f2f977020 00007ff8be501038 App.DALApp.GetSomeData(...)
两个请求都在执行自定义代码(事实上,它们使用了 100% CPU 并且永无止境...)
这种情况可能吗?如果是这样,在什么条件下以及我对会话状态锁定行为有什么误解? (https://docs.microsoft.com/en-us/dotnet/api/system.web.sessionstate.sessionstatebehavior?view=netframework-4.0)
这种奇怪的行为可能是应用程序挂起的原因吗?
谢谢。
编辑:阅读一些 ASP.NET 代码后,我转储了两个 HttpContext 并确认了奇怪的行为(两个请求 required 会话状态行为和 同一会话一次)。我有什么误解吗?我不敢相信这样的错误会在没有人知道的情况下存在(我在网上找不到任何类似的问题):
!wdo 0000002E06A2E7E8
Address: 0000002e06a2e7e8
Method Table/Token: 00007ff919304a98/20003a304
Class Name: System.Web.HttpContext
...
00007ff919346278 System.Web.SessionState.SessionStateBeha +0164 _SessionStateBehavior_k__BackingField 0 (0n0) Default
00007ff91bb9f370 System.Boolean +0175 _requiresSessionStateFromHandler 1 (True)
00007ff91bb9f370 System.Boolean +0176 _readOnlySessionStateFromHandler 0 (False)
00007ff91bb9f370 System.Boolean +0177 InAspCompatMode 0 (False)
00007ff91bb9f370 System.Boolean +0179 _FirstRequest_k__BackingField 0 (False)
00007ff91bbb7af8 System.DateTime +0180 _utcTimestamp -mt 00007FF91BBB7AF8 0000002E06A2E970 28/02/2020 08:16:37
!wdo 0000002D0C7754B0
Address: 0000002d0c7754b0
Method Table/Token: 00007ff919304a98/20003a304
Class Name: System.Web.HttpContext
...
00007ff919346278 System.Web.SessionState.SessionStateBeha +0164 _SessionStateBehavior_k__BackingField 0 (0n0) Default
00007ff91bb9f370 System.Boolean +0175 _requiresSessionStateFromHandler 1 (True)
00007ff91bb9f370 System.Boolean +0176 _readOnlySessionStateFromHandler 0 (False)
00007ff91bb9f370 System.Boolean +0177 InAspCompatMode 0 (False)
00007ff91bb9f370 System.Boolean +0179 _FirstRequest_k__BackingField 0 (False)
00007ff91bbb7af8 System.DateTime +0180 _utcTimestamp -mt 00007FF91BBB7AF8 0000002D0C775638 28/02/2020 08:21:27
编辑 2:也在 ASP.NET MVC 论坛上提出了问题:https://forums.asp.net/t/2169038.aspx?Multiple+concurrent+ASP+NET+MVC+4+requests+for+same+session+possible+without+specific+setting+
我刚刚找到了我自己问题的答案。
HttpRuntime executionTimeout 设置(ASP.NET 2+ 默认为 110 秒)控制最大请求线程持续时间和会话状态锁定持续时间。因此,在处理 110 秒后,由于会话锁已释放,可能会处理来自同一会话的另一个请求。在我的例子中,正如@user2116910 在下面的 SO link 中所述,第一个请求处理线程永远不会被终止(可能是因为应用程序已使用调试配置部署!:-/)
参考文献:
ASP.NET MVC 4.0 应用程序在我们的生产环境中时常会冻结。 在尝试使用 Windbg(+ SOS、SOSEX、NETEXT 和 MEX)和两个生产过程内存转储分析问题时,我注意到问题总是在同时处理两个请求(正在执行 .NET 业务代码)时出现相同的会话。据我所知,如果不自定义会话行为(使用配置、属性或 ControllerFactory),这是不可能的。在此应用程序中(过度)使用了会话,并且尚未自定义会话行为。我能找到的唯一设置 (controllers/code/config) 是 web.config:
中的这个<sessionState timeout="720" />
如果有人可以帮助我理解这个案例,这里是我的 windbg 会话的结果。
!whttp
HttpContext Thread Time Out Running Status Verb Url
0000002d0c7754b0 26 00:01:50 00:36:55 200 POST /Ctrl/Action
0000002e06a2e7e8 27 00:01:50 00:41:45 200 POST /Ctrl/Action
[...]
这是永远耗时的两个 HTTP 请求。
!DumpAspNetSession -ctx 0000002d0c7754b0
System.Web.SessionState.HttpSessionStateContainer: 0x0000002d0c7a9a38
Key Value
================================ ======================================================
VarSession 0000002e06587000 (App.VarSession)
!DumpAspNetSession -ctx 0000002e06a2e7e8
System.Web.SessionState.HttpSessionStateContainer: 0x0000002e06a3a810
Key Value
================================ ======================================================
VarSession 0000002e06587000 (App.VarSession)
与上面的 HttpContext 匹配的会话持有相同的数据(App.VarSession 类型)。
!wcookie
0000002d0c7754b0 /Ctrl/Action (200 NULL) Running (00:36:55)
======================================================================================
ASP.NET_SessionId=im3clvnd0auw0te3nkzzq1p0
======================================================================================
0000002e06a2e7e8 /Ctrl/Action (200 NULL) Running (00:41:45)
======================================================================================
ASP.NET_SessionId=im3clvnd0auw0te3nkzzq1p0
这个最新的命令显示这两个请求确实与同一个会话相关。
~26s
0:026> !CLRStack
OS Thread Id: 0x122c (26)
Child SP IP Call Site
0000002f2de47750 00007ff91a2042db System.Linq.Enumerable+d__14`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()
0000002f2de477b0 00007ff91a2095b7 System.Linq.Enumerable.FirstOrDefault[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1, System.Func`2)
0000002f2de47810 00007ff8be3ce1fe App.DALApp.GetData(...)
~27s
0:027> !CLRStack
OS Thread Id: 0x313c (27)
Child SP IP Call Site
0000002f2f976f20 00007ff8be5022ef App.DALApp.b__257(...)
0000002f2f976f60 00007ff91a2042ab System.Linq.Enumerable+d__14`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()
0000002f2f976fc0 00007ff91a2095b7 System.Linq.Enumerable.FirstOrDefault[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1, System.Func`2)
0000002f2f977020 00007ff8be501038 App.DALApp.GetSomeData(...)
两个请求都在执行自定义代码(事实上,它们使用了 100% CPU 并且永无止境...)
这种情况可能吗?如果是这样,在什么条件下以及我对会话状态锁定行为有什么误解? (https://docs.microsoft.com/en-us/dotnet/api/system.web.sessionstate.sessionstatebehavior?view=netframework-4.0) 这种奇怪的行为可能是应用程序挂起的原因吗?
谢谢。
编辑:阅读一些 ASP.NET 代码后,我转储了两个 HttpContext 并确认了奇怪的行为(两个请求 required 会话状态行为和 同一会话一次)。我有什么误解吗?我不敢相信这样的错误会在没有人知道的情况下存在(我在网上找不到任何类似的问题):
!wdo 0000002E06A2E7E8
Address: 0000002e06a2e7e8
Method Table/Token: 00007ff919304a98/20003a304
Class Name: System.Web.HttpContext
...
00007ff919346278 System.Web.SessionState.SessionStateBeha +0164 _SessionStateBehavior_k__BackingField 0 (0n0) Default
00007ff91bb9f370 System.Boolean +0175 _requiresSessionStateFromHandler 1 (True)
00007ff91bb9f370 System.Boolean +0176 _readOnlySessionStateFromHandler 0 (False)
00007ff91bb9f370 System.Boolean +0177 InAspCompatMode 0 (False)
00007ff91bb9f370 System.Boolean +0179 _FirstRequest_k__BackingField 0 (False)
00007ff91bbb7af8 System.DateTime +0180 _utcTimestamp -mt 00007FF91BBB7AF8 0000002E06A2E970 28/02/2020 08:16:37
!wdo 0000002D0C7754B0
Address: 0000002d0c7754b0
Method Table/Token: 00007ff919304a98/20003a304
Class Name: System.Web.HttpContext
...
00007ff919346278 System.Web.SessionState.SessionStateBeha +0164 _SessionStateBehavior_k__BackingField 0 (0n0) Default
00007ff91bb9f370 System.Boolean +0175 _requiresSessionStateFromHandler 1 (True)
00007ff91bb9f370 System.Boolean +0176 _readOnlySessionStateFromHandler 0 (False)
00007ff91bb9f370 System.Boolean +0177 InAspCompatMode 0 (False)
00007ff91bb9f370 System.Boolean +0179 _FirstRequest_k__BackingField 0 (False)
00007ff91bbb7af8 System.DateTime +0180 _utcTimestamp -mt 00007FF91BBB7AF8 0000002D0C775638 28/02/2020 08:21:27
编辑 2:也在 ASP.NET MVC 论坛上提出了问题:https://forums.asp.net/t/2169038.aspx?Multiple+concurrent+ASP+NET+MVC+4+requests+for+same+session+possible+without+specific+setting+
我刚刚找到了我自己问题的答案。 HttpRuntime executionTimeout 设置(ASP.NET 2+ 默认为 110 秒)控制最大请求线程持续时间和会话状态锁定持续时间。因此,在处理 110 秒后,由于会话锁已释放,可能会处理来自同一会话的另一个请求。在我的例子中,正如@user2116910 在下面的 SO link 中所述,第一个请求处理线程永远不会被终止(可能是因为应用程序已使用调试配置部署!:-/)
参考文献: