記一次 .NET 某券商論壇系統 卡死分析

来源:https://www.cnblogs.com/huangxincheng/archive/2023/11/14/17831401.html
-Advertisement-
Play Games

一:背景 1. 講故事 前幾個月有位朋友找到我,說他們的的web程式沒有響應了,而且監控發現線程數特別高,記憶體也特別大,讓我幫忙看一下怎麼回事,現在回過頭來幾經波折,回味價值太濃了。 二:程式到底經歷了什麼 1. 線上程上找原因 這個程式記憶體高,線程高,無響應,尼瑪是一個複合態問題,那怎麼入手呢?按 ...


一:背景

1. 講故事

前幾個月有位朋友找到我,說他們的的web程式沒有響應了,而且監控發現線程數特別高,記憶體也特別大,讓我幫忙看一下怎麼回事,現在回過頭來幾經波折,回味價值太濃了。

二:程式到底經歷了什麼

1. 線上程上找原因

這個程式記憶體高,線程高,無響應,尼瑪是一個複合態問題,那怎麼入手呢?按經驗推測,大概率是由於高線程數引發的,相信大家都知道每個線程都有自己的棧空間,所以眾人拾柴火焰高,可以用 !address -summary 觀察下線程棧空間。


0:000> !address -summary

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free                                    329     7df9`d4b93000 ( 125.976 TB)           98.42%
<unknown>                               994      205`2ae2e000 (   2.020 TB)  99.81%    1.58%
Stack                                  7215        0`e0d00000 (   3.513 GB)   0.17%    0.00%
Heap                                    956        0`1695f000 ( 361.371 MB)   0.02%    0.00%
Image                                  1468        0`07b34000 ( 123.203 MB)   0.01%    0.00%
TEB                                    2405        0`012ca000 (  18.789 MB)   0.00%    0.00%
Other                                    10        0`001d1000 (   1.816 MB)   0.00%    0.00%
PEB                                       1        0`00001000 (   4.000 kB)   0.00%    0.00%
...

--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE                                329     7df9`d4b93000 ( 125.976 TB)           98.42%
MEM_RESERVE                            3132      203`e925c000 (   2.015 TB)  99.56%    1.57%
MEM_COMMIT                             9917        2`42201000 (   9.033 GB)   0.44%    0.01%

從卦中可以清晰的看到,提交記憶體是9G,同時Stack吃掉了3.5G,一般來說 Stack 不會有這麼大,所以此事必有妖,在 TEB 中可以看到線程數高達 2405 個,這個確實不少哈,可以用 !t 做一個驗證。


0:000> !t
ThreadCount:      2423
UnstartedThread:  0
BackgroundThread: 2388
PendingThread:    0
DeadThread:       34
Hosted Runtime:   no
                                                                                                            Lock  
 DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
   0    1     3344 00000032972B2D90  202a020 Preemptive  0000000000000000:0000000000000000 0000003297125a30 -00001 MTA 
  11    2     1d28 00000037A43B9140    2b220 Preemptive  000000364BC5AD90:000000364BC5C328 0000003297125a30 -00001 MTA (Finalizer) 
  12    5     2a00 00000037A52BF4D0  102a220 Preemptive  00000036527EBDE8:00000036527EDD90 0000003297125a30 -00001 MTA (Threadpool Worker) 
  13    7     3168 00000037A52C1B40  302b220 Preemptive  00000034D1136688:00000034D1137FD0 0000003297125a30 -00001 MTA (Threadpool Worker) 
  15   14     13b8 00000037A542EA50  202b220 Preemptive  00000036527EBCA8:00000036527EBD90 0000003297125a30 -00001 MTA 
...

有了這個入口點,接下來觀察每一個線程的線程棧,使用 ~*e !clrstack發現有大量的線程在 PostMethod 方法中的 Task.Result 上等待,看樣子是在做網路請求,這裡做了一下提前截斷,截圖如下:

由於是知名券商,這裡就儘量模糊了哈。。。請見諒,知道了在 Task.Result 上,一下子就開心起來了,自此也被誤入歧途。。。。

2. 誤入歧途

  1. 是上下文導致的嗎?

過往經驗告訴我,很多時候的 Task.Result 卡死是因為上下文的關係所致,所以重點看下是不是 Asp.NET 的程式,使用 !eeversion 觀察便知。


0:000> !eeversion
6.0.422.16404 free
6,0,422,16404 @Commit: be98e88c760526452df94ef452fff4602fb5bded
Server mode with 8 gc heaps
SOS Version: 7.0.8.30602 retail build

從卦中數據看當前是 .net6 寫的程式,就不存在上下文一說了,這個情況可以排除,只能繼續尋找其他突破口。。。

  1. 下游處理過慢導致的嗎?

是不是下游處理過慢,一個突破點就是觀察下 線程池隊列 是不是有任務積壓,這個可以用 !tp 觀察下隊列即可。

從卦中數據看當前隊列無任何積壓,說明也不是下游處理過慢導致的,我去,太難了。。。

  1. 代理或者伺服器有問題嗎?

既然無上下文,無積壓,接下來只能懷疑是不是server方有問題或者用了什麼代理軟體?要想找這個信息,需要用 !dso 觀察線程棧中的對象。


0:000> ~34s
ntdll!NtWaitForMultipleObjects+0xa:
00007ffe`115c0cba c3              ret
0:034> !dso
OS Thread Id: 0x1ef4 (34)
RSP/REG          Object           Name
00000037B56AC688 000000351f9e4918 System.Threading.Thread
00000037B56AC700 0000003317bb6160 System.Net.Http.DiagnosticsHandler
00000037B56AC708 000000351f9e4918 System.Threading.Thread
00000037B56AC748 0000003617b743c8 System.Net.Http.HttpWindowsProxy
...
00000037B56AD0D0 00000034c8283750 System.String    http://xxx/Article/xxx
00000037B56ACF30 0000003317bb5ad8 System.Net.Http.HttpClient
...

看了下卦中的請求地址:http://xxx/Article/xxx, 同時在 HttpWindowsProxyHttpClient 中也沒有看到所謂的代理IP,這就陷入了迷茫。

事已至此,只能懷疑是網路的問題,讓朋友在程式卡死的那個期間段用 wireshark 或者 tcpdump 去抓下包,看看是不是網路出了問題,tcp握手揮手怎麼樣,事情也就這樣不了了之了。

3. 迷途知返

前些天在給訓練營的朋友準備課件時,優化了一個例子來演示 線程池隊列 的堆積情況,結果意外發現 sos 吐出來的數據是假的,尼媽,如夢初醒,分析dump已經夠難了,為什麼 sos 還要欺騙我,天真的塌下來了。。。

其實在分析 .net core 的dump時,每每發現線程池隊列都是 0 ,雖然有一絲奇怪,但也不敢懷疑sos吐出來的數據權威性。

既然 sos 吐出來的數據是假的,只能自己去線程池中把隊列挖出來,即 ThreadPoolWorkQueue.workItems 欄位,如下所示:


0:034> !DumpObj /d 0000003517b9c1c0
Name:        System.Threading.ThreadPoolWorkQueue
MethodTable: 00007ffd8416d260
EEClass:     00007ffd84196ab8
Tracked Type: false
Size:        168(0xa8) bytes
File:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.4\System.Private.CoreLib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffd83ddbf28  4000c61       18       System.Boolean  1 instance                0 loggingEnabled
00007ffd83ddbf28  4000c62       19       System.Boolean  1 instance                0 _dispatchTimeSensitiveWorkFirst
00007ffd8416dc78  4000c63        8 ...Private.CoreLib]]  0 instance 0000003517b9c268 workItems
00007ffd8416e458  4000c64       10 ...Private.CoreLib]]  0 instance 0000003517b9eea0 timeSensitiveWorkQueue
00007ffd8416d1f0  4000c65       20 ...acheLineSeparated  1 instance 0000003517b9c1e0 _separated

...

0:034> !ext dcq 0000003517b9c268
System.Collections.Concurrent.ConcurrentQueue<System.Object>
   1 - dumpobj 0x00000032c93b7ce0
   2 - dumpobj 0x00000032c93b8ae8
   3 - dumpobj 0x00000032c93b98d8
   ...
54346 - dumpobj 0x00000034d12fb2e8
54347 - dumpobj 0x0000003652805b40
---------------------------------------------
54347 items

從卦中數據看當前線程池堆積了 5.3w 的任務,很顯然是屬於第二種情況,即下游處理不及,既然處理不急,是不是遇到了什麼高峰期呢?這個可以用 .time 觀察下當前時段。

從卦中數據看,看樣子是快到 收盤時間 了,結合今年的大盤形式,看樣子是出現了暴跌,股民們在發泄情緒,哈哈。。。

找到了問題的根,解決方案就比較多了。

  • 做 PostMethod 請求的非同步化,不要用 Result 去硬等待。

  • 儘量做批量化提交,降低請求介面的單次時間。

三:總結

這次生產事故的分析峰迴路轉,本來是一個很容易就能定位出的問題,可我認為權威的sos居然吐出了假數據欺騙了我,讓我誤入歧途,浪費了很多的人力物力,真的很無語。。。再也不相信 sos 了!

圖片名稱
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • NullPointerException(空指針異常):當試圖調用實例方法或訪問實例變數時,對象引用為 null 時拋出。ArithmeticException(算術異常):當試圖做出違反算術規則的操作時拋出,比如除以零。ClassCastException(類轉換異常):當試圖將對象強制轉換為不是... ...
  • 從JDK11到JDK17,到底帶來了哪些特性呢?亞毫秒級的ZGC效果到底怎麼樣呢?值得我們升級嗎?而且升級過程會遇到哪些問題呢?帶著這些問題,本篇文章將帶來完整的JDK11升級JDK17最全實踐。 ...
  • 0 前言 潛心打造國內一流,國際領先的技術乾貨。 文章收錄在我的 GitHub 倉庫,歡迎Star/fork: JavaEdge-Interview 受網路和運行環境影響,應用程式可能遇到暫時性故障,如瞬時網路抖動、服務暫時不可用、服務繁忙導致超時等。 自動重試機制可大幅避免此類故障,保障操作成功執 ...
  • 來源:blog.csdn.net/weixin_42653522/article/details/117151913 1、前言 ApplicationContext 中的事件處理是通過 ApplicationEvent 類和 ApplicationListener 介面提供的。如果將實現了 Appl ...
  • 學習視頻:【孫哥說Spring5:從設計模式到基本應用到應用級底層分析,一次深入淺出的Spring全探索。學不會Spring?只因你未遇見孫哥】 第二章、第一個Spring程式 1.軟體版本 1.JDK1.8+ 2.Maven3.5+ 3.IDEA2018+ 4.SpringFramework 5. ...
  • 目錄1.修飾類時2.修飾方法時3.修飾屬性和局部變數時3.1修飾局部變數時3.2修飾成員變數時3.3修飾類變數時4.final與普通變數的區別5.final用於引用 1.修飾類時 1.只能是公共的(public)就算不寫也是public 2.被final修飾的類不可以被繼承 //前面預設有個publ ...
  • SciPy庫本身是針對科學計算而不是圖像處理的,只是圖像處理也包含了很多數學計算,所以Scipy也提供了一個專門的模塊ndimage用於圖像處理。 ndimage模塊提供的功能包括輸入/輸出圖像、顯示圖像、基本操作(如裁剪、翻轉、旋轉等)、圖像過濾(如去噪、銳化等)、圖像分割、分類、特征提取以及註冊 ...
  • 目錄 Welcome to YARP - 1.認識YARP並搭建反向代理服務 Welcome to YARP - 2.配置功能 2.1 - 配置文件(Configuration Files) 2.2 - 配置提供者(Configuration Providers) 2.3 - 配置過濾器(Confi ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...