ASP.NET Hang – 通用字典并发问题导致GC死锁

在上个月,我们的ASP.NET网络应用程序已经停止响应请求,我们不得不重新设置应用程序池以备份它。

我们无法确定问题的确切原因,因为服务器的事件日志中没有错误。网站只是停止响应。

所以我们一直在使用WinDbg来尝试分析当网站在Tess Ferrandez的博客条目的帮助下没有响应时使用的内存转储:GC Hangs& High CPU Hang

通过运行!threadpool我可以看到以下内容:

CPU utilization: 81%
Worker Thread: Total: 10 Running: 8 Idle: 2 MaxLimit: 400 MinLimit: 160
Work Request in Queue: 1930
--------------------------------------
Number of Timers: 72
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 8 CurrentLimit: 0 MaxLimit: 400 MinLimit: 120

据Tess在博客文章中,这表明我们被困在一个垃圾收集的中间(通常需要一个纳秒的时间),因为处理器显示了81%这是.NET框架设置为而它是垃圾收集。它被设置为此,因为当该值大于80%时,不能产生新的线程。另外 – 您可以看到队列中有1930个请求,即使可能的400中只有10个工作线程。

通过运行!threads命令,我可以看到两个线程的PreEmptive GC设置为禁用:

PreEmptive   GC Alloc                Lock
       ID  OSID ThreadOBJ    State GC           Context       Domain   Count APT Exception
  10    1  18bc 00000000001b9710   1008220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  16    2   e68 00000000001c0900      b220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Finalizer)
  18    4  1118 00000000001df300   1009220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  19    5  1560 00000000001e9068   100a220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  20    6  11d0 00000000001f14d8      1220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn
  22    9  19d0 000000001bc666d0   1019220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
   9    c  13f4 000000001d173600   8008220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Completion Port)
  24   23  17c4 00000000001a0c40   1009220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  25   24  1088 000000001d205900   1009220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
   6   21  1248 000000001d1f6e80       220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn
   4   27   eb0 000000000019df08       220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn
  27   29   39c 000000001bc720f0   1009220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  28   26  17ec 00000000001a7be0   1019220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  29   2c  1040 000000001d1c8160   1009220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
   3   2a  1788 000000001d22ed48       220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn
  30   1f   830 000000001bc5b180       220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn
  32   1e   b38 000000001d1995a0   1009220 Enabled  0000000000000000:0000000000000000 001f0d80     2 Ukn (Threadpool Worker)
  33   1d  19fc 000000001d199a98   1019220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  34   1c   c84 000000000019f8a8   1009220 Enabled  0000000008d8d880:0000000008d8d88c 001f0d80     1 Ukn (Threadpool Worker)
  35   1a  12e8 000000001d1a1468   10092a2 Disabled 000000000c88e294:000000000c88e6d0 001f0d80     1 Ukn (Threadpool Worker)
   5   22  1a70 000000001d1a6008       220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn
  36   28  1050 000000001d209f18   1019220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  37   25  19f0 000000001d22f738   1019220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  38   2b  15cc 000000001d29b2d0      b220 Enabled  0000000000000000:0000000000000000 001f0d80     1 Ukn
  39   20  1228 000000001d290a88   1019220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  40   1b   c98 000000001d290420   10092a2 Disabled 0000000010adc094:0000000010addcf8 001f0d80     1 Ukn (Threadpool Worker)
  41   19  15dc 000000001d2a3168   1019220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn (Threadpool Worker)
  43   18  1a64 000000001d2c8cc0       220 Enabled  0000000000000000:0000000000000000 001b3b98     0 Ukn

从我的理解,这是坏的,基本上意味着垃圾收集不能完成,直到所有的线程启用,这意味着该进程挂起。

与这个帖子相比,它有一点微小的差异,而这让我感到困惑,因为没有一个标有“(GC)”的线程 – 触发垃圾收集的线程?

但是不管怎样,由于两个线程被设置为禁用,我认为这是问题,而Tess的博客帖子将继续告诉我确切的原因解决这个问题但不幸的是,它暗示了’mixed DLLloading problem‘的问题,在查看禁用线程的堆栈后,既不尝试加载DLL。例如,这里是线程40的kb:

1c93dc74 79142280 0ac30260 0bc85820 00000003 mscorlib_ni+0x29f318
1c93dc88 1e6a8c6c 1c93dc94 00000000 00000001 clr!OnHijackScalarTripThread
WARNING: Frame IP not in any known module. Following frames may be wrong.
1c93dca0 1e6791f7 00000003 00000000 00000000 0x1e6a8c6c
1c93e270 791421bb 0c886820 1bac554d 00000000 0x1e6791f7
1c93e284 7916a553 1c93e354 00000001 1c93e320 clr!CallDescrWorker+0x33
1c93e300 7916a6f4 1c93e354 00000001 1c93e320 clr!CallDescrWorkerWithHandler+0x8e
1c93e450 7916a729 1bd17090 1c93e574 1c93e720 clr!MethodDesc::CallDescr+0x194
1c93e46c 7916a749 1bd17090 1c93e574 1c93e720 clr!MethodDesc::CallTargetWorker+0x21
1c93e484 79190c04 1c93e720 ed47daf9 1c93ea18 clr!MethodDescCallSite::Call_RetArgSlot+0x1c
1c93e648 79190f53 1c85ce30 1bd17090 1b8b6834 clr!CallWithValueTypes_RetArgSlotWrapper+0x5c
1c93e930 79191115 1c85ce30 00000000 0c886b80 clr!InvokeImpl+0x621
1c93e9fc 79b3d839 1d1a1468 00000096 1c93ea18 clr!RuntimeMethodHandle::InvokeMethodFast+0x180
1c93ea50 79b3d52c 0ecc3e60 00000096 1038d084 mscorlib_ni+0x2bd839
1c93ea88 79b3c19d 00000000 00000000 0c885530 mscorlib_ni+0x2bd52c
1c93eab0 79ad6d16 00000000 0c885530 0ec452c4 mscorlib_ni+0x2bc19d
1c93ec04 7a045331 00000000 00000000 00000000 mscorlib_ni+0x256d16
1c93ecbc 672d72b5 0c862b08 00000000 00000000 mscorlib_ni+0x7c5331
1c93ece8 672eb90c 00000000 1c93ed18 0c862b08 System_Web_ni+0x1772b5
1c93ed28 67301e9e 1c93ed54 07f81050 0c863014 System_Web_ni+0x18b90c
1c93ed80 672b5998 1b8b2010 1b8e12c4 1c93f208 System_Web_ni+0x1a1e9e
1c93ed9c 67300602 0c862b08 0ec4af84 0c862b08 System_Web_ni+0x155998
1c93edd8 6730034d 0ac37a80 0c861c1c 1c93ee5c System_Web_ni+0x1a0602
1c93ede8 672ff8fd a65adfcd 79145c50 1c93effc System_Web_ni+0x1a034d
1c93ee5c 67935cdc 00000002 6726b530 00000000 System_Web_ni+0x19f8fd
1c93ee98 791425a1 1c93f228 00000002 028f2b9c System_Web_ni+0x7d5cdc
1c93eeac 79208c9b 67935cc0 6726b530 0ac4ea6c clr!COMToCLRDispatchHelper+0x28
1c93ef40 79208d74 6726b530 0ac4ea6c 00000001 clr!BaseWrapper<Stub *,FunctionBase<Stub *,&DoNothing<Stub *>,&StubRelease<Stub>,2>,&CompareDefault<Stub *>,2>::~BaseWrapper<Stub *,2>+0xfa
1c93ef64 79208dda 1d1a1468 1c93f1f8 1b7affe0 clr!COMToCLRWorkerBody+0xb4
1c93efbc 792098c9 1d1a1468 1c93f1f8 1b7affe0 clr!COMToCLRWorkerDebuggerWrapper+0x34
1c93f1cc 02b3a1aa 1d1a1468 1c93f1f8 a65adfcd clr!COMToCLRWorker+0x614
1c93f1e0 69f5aa4f 00000001 028038c8 00000000 0x2b3a1aa
1c93f544 69f5ab4a 028038c8 69f5aae2 1c93f56c webengine4!HttpCompletion::ProcessRequestInManagedCode+0x1cd
1c93f554 69f5aafe 028038c8 00000000 00000000 webengine4!HttpCompletion::ProcessCompletion+0x4a
1c93f56c 792078af 028038c8 ed47c90d 0000ffff webengine4!CorThreadPoolWorkitemCallback+0x1c
1c93f5bc 79206c5f 1c93f61f 1c93f61e ed47ca9d clr!UnManagedPerAppDomainTPCount::DispatchWorkItem+0x195
1c93f62c 792084c5 00000000 ed47ca25 00000000 clr!ThreadpoolMgr::NewWorkerThreadStart+0x20b
1c93f694 792f76e0 00000000 fff91c00 00000002 clr!ThreadpoolMgr::WorkerThreadStart+0x3d1
1c93ffb8 7d4dfb97 00247430 00000000 00000000 clr!Thread::intermediateThreadProc+0x4b
1c93ffec 00000000 792f7698 00247430 00000000 kernel32!BaseThreadStart+0x34

但后来我注意到有趣的事情。通过使用!eestack -ee -short命令,我看到线程35& 40(与残疾人PreEmptive GC的)都在同一个当前框架:

Current frame: (MethodDesc 798ee360 +0xab System.Collections.Generic.Dictionary`2[[System.Int32,mscorlib],[System.__Canon,mscorlib]].FindEntry(Int32))

这是什么让我到this帖子让我想我一定会找到这个问题。但不幸的是,在使用堆栈追溯到代码后,有问题的Dictionary不是静态的 – 所以我猜这不是问题。

我现在几乎没有想法 – 我不是分析转储文件的专家(实际上我只是从昨天开始:D),所以如果任何人有任何指针,我将下一步做什么,以确定问题的原因会很好。

UPDATE

运行Brian建议的〜* ekb命令后,我发现启动垃圾回收的线程,因为它在堆栈中有GarbageCollectGeneration。

1e61e54c 7d4d8c9e 000003c4 00000000 00000000 ntdll_7d600000!NtWaitForSingleObject+0x15
1e61e5bc 791897da 000003c4 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac
1e61e5f0 7918981b 000003c4 ffffffff 00000000 clr!CLREvent::CreateManualEvent+0xf6
1e61e640 791896f1 00000000 efb5da31 0019f8a8 clr!CLREvent::CreateManualEvent+0x137
1e61e680 79189712 ffffffff 00000000 00000000 clr!CLREvent::WaitEx+0x126
1e61e694 792a05cc ffffffff 00000000 00000000 clr!CLREvent::Wait+0x19
1e61e6b8 792a04e5 ffffffff 00000000 0019f8f0 clr!SVR::gc_heap::wait_for_gc_done+0x6f
**1e61e6e0 792a424b 00000000 00000001 001bc600 clr!SVR::GCHeap::GarbageCollectGeneration+0x14f**
1e61e714 79229fd2 0019f8f0 00000040 00000000 clr!SVR::gc_heap::try_allocate_more_space+0x184
1e61e730 7922a080 0019f8f0 00000040 00000000 clr!SVR::gc_heap::allocate_more_space+0x30
1e61e750 79188f33 0019f8f0 00000040 00000000 clr!SVR::GCHeap::Alloc+0x55
1e61e76c 7915dd44 00000040 00000000 00000000 clr!Alloc+0x8d
1e61e7ac 7915dd84 0000001a 79169a39 79166166 clr!SlowAllocateString+0x42
1e61e7b4 79169a39 79166166 00000019 efb5d4c9 clr!UnframedAllocateString+0x12
1e61e7b8 79166166 00000019 efb5d4c9 00001f3e clr!StringObject::NewString+0x13
1e61e878 79ac139e 00000000 0019f8a8 0515fcd0 clr!COMNlsInfo::InternalChangeCaseString+0x128
1e61e88c 79ac51b4 0515fcd0 1e61e900 20e59f26 mscorlib_ni+0x24139e
1e61e898 20e59f26 1e61e900 08ce6208 050fd8e8 mscorlib_ni+0x2451b4

我还应该提到我们的应用程序是运行在32位模式下,在64位服务器上。不幸的是,当它最后变得无响应时,我们忘记在32位中使用转储,这意味着当我们在WinDbg中加载转储文件时,我们需要运行!wow64exts.sw命令进行分析。不知道这有多少差异(也许这就是为什么我看不到'(GC)’线程),但是我们似乎不能让`!clrstack’命令工作。我们正在等待它再次不响应,所以我们可以在32位转储。

解决方法

所以我们终于找到了问题的底线。原来是我原来提到的两篇文章的结合:

>有两个线程尝试访问相同的通用字典
> GC无法完成,因为两个线程的PreEmptive GC设置为禁用。

多一点细节:

虽然两个线程处于某种僵局,但第三个线程加入了想要在堆上分配一些内存的方。这会触发一个新的GC,但GC无法完成,因为这两个线程的PreEmptive GC设置为禁用。由于GC无法完成,因此IIS进程仍然处于不能为请求产生新的工作线程的状态,这意味着任何后续请求都将排队。队列继续增长,在应用程序池被回收之前不会返回任何响应。

正如我在原来的问题中提到的 – 我们将字典追溯到代码,它不是一个静态字典,所以我们认为这必须是一个红色的鲱鱼;两个线程还能访问同一个对象吗?事实证明,这是可能的,因为字典存储在InProc会话中。

默认情况下,ASP.NET可以防止同一会话ID的并发请求。这是通过对每个请求的会话放置独占锁来设计的,以防止这种确切的情况。但是,这是一个使用旧的AjaxPro框架的“遗留”应用程序,并被配置为绕过此锁定。这允许同一会话的并发AjaxRequests访问同一个会话对象。

原来我们最近在我们的JavaScript中引入了一个bug,多次触发相同的AjaxPro请求,从而导致问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


引言 本文从Linux小白的视角, 在CentOS 7.x服务器上搭建一个Nginx-Powered AspNet Core Web准生产应用。 在开始之前,我们还是重温一下部署原理,正如你所常见的.Net Core 部署图: 在Linux上部署.Net Core App最好的方式是在Linux机器
引言: 多线程编程/异步编程非常复杂,有很多概念和工具需要去学习,贴心的.NET提供Task线程包装类和await/async异步编程语法糖简化了异步编程方式。 相信很多开发者都看到如下异步编程实践原则: 遵守以上冷冰冰的②③条的原则,可保证异步程序按照预期状态正常运作;我们在各大编程论坛常看到违背
一. 宏观概念 ASP.NET Core Middleware是在应用程序处理管道pipeline中用于处理请求和操作响应的组件。 每个组件是pipeline 中的一环。 自行决定是否将请求传递给下一个组件 在处理管道的下个组件执行之前和之后执行业务逻辑 二. 特性和行为 ASP.NET Core处
背景 在.Net和C#中运行异步代码相当简单,因为我们有时候需要取消正在进行的异步操作,通过本文,可以掌握 通过CancellationToken取消任务(包括non-cancellable任务)。 Task&#160;表示无返回值的异步操作, 泛型版本Task&lt;TResult&gt;表示有返
HTTP基本认证 在HTTP中,HTTP基本认证(Basic Authentication)是一种允许网页浏览器或其他客户端程序以(用户名:口令) 请求资源的身份验证方式,不要求cookie,session identifier、login page等标记或载体。 - 所有浏览器据支持HTTP基本认
1.Linq 执行多列排序 OrderBy的意义是按照指定顺序排序,连续两次OrderBy,后面一个有可能会打乱前面一个的排序顺序,可能与预期不符。 要实现sql中的order by word,name类似效果; LINQ 有ThenBy可以紧接使用, ThenBy记住原本排序的值,然后再排其他值,
ASP.NET Core 核心特性:开源、跨平台、高性能是其决战JAVA的必胜法宝,最引人关注的跨平台特性 到底是怎么实现? &#xA; 本文分Unix、Windows剖析跨平台内幕,读完让你大呼过瘾。
前导 Asynchronous programming Model(APM)异步编程模型以BeginMethod(...) 和 EndMethod(...)结对出现。 IAsyncResult BeginGetResponse(AsyncCallback callback, object state
引言 最近在公司开发了一个项目,项目部署架构图如下: 思路 如图中文本所述,公司大数据集群不允许直接访问外网,需要一个网关服务器代理请求,本处服务器A就是边缘代理服务器的作用。 通常技术人员最快捷的思路是在服务器A上部署IISʺpplication Request Routing Module组件
作为一枚后端程序狗,项目实践常遇到定时任务的工作,最容易想到的的思路就是利用Windows计划任务/wndows service程序/Crontab程序等主机方法在主机上部署定时任务程序/脚本。 但是很多时候,若使用的是共享主机或者受控主机,这些主机不允许你私自安装exe程序、Windows服务程序
引言 熟悉TPL Dataflow博文的朋友可能记得这是个单体程序,使用TPL Dataflow 处理工作流任务, 在使用Docker部署的过程中, 有一个问题一直无法回避: 在单体程序部署的瞬间(服务不可用)会有少量流量无法处理;更糟糕的情况下,迭代部署的这个版本有问题,上线后无法运作, 更多的流
合格的web后端程序员,除搬砖技能,还必须会给各种web服务器配置Https,本文结合ASP.NET Core部署模型聊一聊启用Https的方式。 温故知新 目前常见的Http请求明文传输,请求可能被篡改,访问的站点可能被伪造。 HTTPS是HTTP加上TLS/SSL协议构建的可进行加密传输、身份认
长话短说 前文《解剖HttpClientFactory,自由扩展HttpMessageHandler》主要讲如何为HttpClientFactory自定义HttpMessageHandler组件, 现在来完成课后的小作业: 将重点日志字段显示到Nlog的LayoutRenderer上。 本文实现一个
引言问题 作为资深老鸟,有事没事,出去面试;找准差距、定位价值。 面试必谈哈希, Q1:什么是哈希? Q2:哈希为什么快? Q3:你是怎么理解哈希算法利用空间换取时间的? Q4:你是怎么解决哈希冲突的? Q5:你有实际用写过哈希算法吗? 知识储备 哈希(也叫散列)是一种查找算法(可用于插入),哈希算
前言 如题,有感于博客园最近多次翻车,感觉像胡子眉毛一把抓, 定位不了生产环境的问题。 抛开流程问题,思考在生产环境中如何做故障排除,&#160;发现博客园里面这方面的文章比较少。 .Net 本身是提供了sos.dll工具帮助我们在生产中故障排除,通过提供有关内部公共语言运行时(CLR)环境的信息,
.NET程序是基于.NET Framework、.NET Core、Mono、【.NET实现】开发和运行的 ,定义以上【.NET实现】的标准规范称为.NET Standard .NET Standard .NET标准是一组API集合,由上层三种【.NET实现】的Basic Class Library
长话短说 上个月公司上线了一个物联网数据科学项目,我主要负责前端接受物联网事件,并提供 参数下载。 webapp 部署在Azure云上,参数使用Azure SQL Server存储。 最近从灰度测试转向全量部署之后,日志时常收到: SQL Session超限报错。 排查 我在Azure上使用的是 S
临近年关,搜狗,360浏览器出现页面无法成功跳转,同域Cookie丢失? 也许是服务端 SameSite惹的祸。&#xA;本文揭示由于Chrome低版本内核不识别 SameSite= None, 引发的单点登录故障。
本文聊一聊TraceID的作用和一般组成,衍生出ASP. NETCore 单体和分布式程序中 TraceId 的使用方式
通过给 HttpClint请求的日志增加 TraceId,解锁自定义扩展 HttpClientFacroty 的姿势