一次k8s docker下.net程式的異常行為dump診斷

dotnet程式故障診斷發表於2023-02-28

背景

昨天,一位朋友找到我尋求幫助。他的專案需要呼叫一個第三方專案的webAPI。這個webAPI本身可從header, query string中取相關資訊,但同事發現他在呼叫時,無法按期望的那樣從query string中傳引數給到第三方webAPI (webAPI彷彿忽略了從query string過來的資訊),朋友不知道是這個webAPI的問題,還是自己呼叫程式碼的問題了。。

由於這個webAPI service是他們公司內部的某team的專案,所以朋友雖然可以看到原始碼,但他並不能快速確定原因, 維護專案的人又不好找。透過webAPI service程式碼他自己找到了可疑的原因是webAPI中的這個方法有可能阻擋了他期望的webAPI行為: Instance.EnableFallback() (公司隱私,改了名), 但他無法確定這個方法在實際執行的時候的具體返回值。

聽了朋友介紹,我能想到的一個方法是看一下他們公司的這個第三方的service程式的內部情況 一次k8s docker下.net程式的異常行為dump診斷(非生產環境,許可權是允許的)

分析

透過kubectl exec -it [namespace:pod] /bin/bash,我們成功進入了service的pod裡。雖然是非生產環境,我們也儘量別打擾人家幹活一次k8s docker下.net程式的異常行為dump診斷  那麼…就選擇dump一下執行的dotnet程式嘍一次k8s docker下.net程式的異常行為dump診斷

由於這次的任務是觀察託管環境的某個記憶體位置的值,我選擇了用dotnet-dump

 

然後dotnet-dump analyze core_123 開始分析。

我們想要的是 Instance.EnableFallback 的返回值,而我的朋友已經知道這個Instance的type,所以用dumpheap -type找一下這個instance在哪裡:

 

 

 然後用!do一下instance具體內容:

1 > do 796f3840d080
2 Name:        XXX.Common.XXX.XXXInstance
3 MethodTable: 00007970d459d3a8
4 EEClass:     00007970d45a4fc0
5 Size:        80(0x50) bytes
6 File:        /app/XXX.dll
7 Fields:
8               MT    Field   Offset                 Type VT     Attr            Value Name
9 00007970d459d9e8  4000016       10 ...XXX]]  0 instance 0000796f3840d130 _evs

根據簡化和隱藏敏感資訊後的程式碼:

 

 知道了需要繼續用!do 看這個0000796f3840d130:

 1 > do 0000796f3840d130
 2 Name:        System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[XXX.Common.XXX.XXXEnv, XXX]]
 3 MethodTable: 00007970d459d718
 4 EEClass:     00007970ce610c00
 5 Size:        72(0x48) bytes
 6 File:        /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.32/System.Private.CoreLib.dll
 7 Fields:
 8               MT    Field   Offset                 Type VT     Attr            Value Name
 9 00007970ce636448  4001aec        8       System.Int32[]  0 instance 0000796f384143a8 _buckets
10 00007970ce636250  4001aed       10 ...ivate.CoreLib]][]  0 instance 0000796f384143d0 _entries
11 00007970ce5fa0e8  4001aee       30         System.Int32  1 instance                1 _count

大家如果瞭解.net Dictionary型別的實現,就知道目前這個dictionary是1size且具體的item值可以直接用!dp看:

 

 Dictionary裡的_entries是個陣列,item型別是value type,所以是inlined memory, 所以直接看0000796f38412948, 因為他是陣列中第0個元素裡的key-value pair裡的value(XXXEnv instance的地址)。

1 > do 0000796f38412948
2 Name:        XXX.Common.XXXEnv
3 MethodTable: 00007970d459e700
4 EEClass:     00007970d45a5888
5 Size:        56(0x38) bytes
6 File:        /app/XXX.dll
7 Fields:
8               MT    Field   Offset                 Type VT     Attr            Value Name
9 00007970d340a988  400000a        8 ....Config.XXXConfig  0 instance 0000796f382898f0 _toggleConfig

最後看那個_toggleConfigInstance.EnableFallback()裡面一通呼叫最終會讀它的內容,簡化程式碼如下:

 

 所以繼續!do看一下這個_toggleConfig:

 

 至此原因確定,懷疑的這個方法在當前這個webAPI service下會返回false.

後記

也許有朋友會問,直接dump type是XXXConfig的instance不就行了。是的,不過在這個dump檔案中,我發現了不止一個active的XXXConfig instance, 也就是說不止一處會用到這個不唯一的XXXConfig, 而我需要明確Instance.EnableFallback最終的返回,所以需要耐心探索哈 一次k8s docker下.net程式的異常行為dump診斷

總結

我的朋友知道了他想確定的Instance.EnableFallback在第三方service執行的時候的真實值之後,也明確了他那邊的應對這個webAPI的呼叫方式了。

這次診斷的問題雖不是cpu過高、記憶體洩漏這類資源問題,但還是用上了與排查資源洩漏相同的底層除錯診斷技術來解決。最後我的朋友很高興,吃了個定心丸一次k8s docker下.net程式的異常行為dump診斷

相關文章