【问题标题】:How can multiple ASP.NET requests with same session can be executed concurrently by default?默认情况下如何同时执行具有相同会话的多个 ASP.NET 请求?
【发布时间】:2020-10-31 14:11:43
【问题描述】:

一个 ASP.NET MVC 4.0 应用程序在我们的生产环境中不时冻结。 在尝试使用 Windbg(+ SOS、SOSEX、NETEXT 和 MEX)和两个生产进程内存转储分析问题时,我注意到问题总是在同时处理两个请求(正在执行.NET 业务代码)时出现相同的会话。据我所知,如果不自定义会话行为(使用配置、属性或 ControllerFactory),这是不可能的。此应用程序中(过度)使用了会话,并且尚未自定义会话行为。我能找到的唯一设置(控制器/代码/配置)是 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 匹配的会话持有相同的 Data(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 并确认了奇怪的行为(两个请求具有 必需 会话状态行为和 same session立刻)。有什么我误解了吗?我不敢相信这样的错误会在没有人知道的情况下存在(我在网上找不到任何类似的问题):

!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+

【问题讨论】:

  • 你的App.DALApp 会不会返回一个非线程安全的、两个线程都在迭代的缓存集合?也许这会导致无限循环?
  • 感谢您的建议。我已经检查过了,但我找不到这些集合可以被多个线程引用的方法。它们是在每个线程调用期间从 DB 重新创建的。无论如何,我会仔细检查。我仍然对这两个线程在同一个会话中同时执行感到惊讶......
  • 事实上,我认为你是对的。一些代码是这样迭代的:collection.SelectMany(c =&gt; things).SelectMany(t =&gt; things2).SelectMany(t2 =&gt; things3)(在 GetData() 方法中)。我发现 t2.Things3 在不同的线程上总是不同的 List 实例,但它们有时包含相同的 _items 数组引用。我不确定这怎么可能(?),但我想我走在正确的轨道上。
  • 我指的 List._items 共享实例实际上是 List 私有单例(静态)emptyArray...我的问题在其他地方。
  • 关于挂起,我检查了正在枚举的对象引用(所有这些都从根目录到当前项)并且在两个线程之间找不到任何共享引用。 (线程 27 堆栈跟踪给出了当前项)

标签: asp.net-mvc iis windbg session-state freeze


【解决方案1】:

我刚刚找到了我自己问题的答案。 HttpRuntime executionTimeout 设置(对于 ASP.NET 2+ 默认为 110 秒)控制最大请求线程持续时间和会话状态锁定持续时间。因此,在处理 110 秒后,由于会话锁已被释放,因此可能会处理来自同一会话的另一个请求。就我而言,正如@user2116910 在下面的 SO 链接中所述,第一个请求处理线程永远不会被杀死(可能是由于应用程序已使用调试配置部署!:-/)

参考资料:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 2023-03-12
    相关资源
    最近更新 更多