背景
昨天,一位朋友找到我尋求幫助。他的專案需要呼叫一個第三方專案的webAPI。這個webAPI本身可從header, query string中取相關資訊,但同事發現他在呼叫時,無法按期望的那樣從query string中傳引數給到第三方webAPI (webAPI彷彿忽略了從query string過來的資訊),朋友不知道是這個webAPI的問題,還是自己呼叫程式碼的問題了。。
由於這個webAPI service是他們公司內部的某team的專案,所以朋友雖然可以看到原始碼,但他並不能快速確定原因, 維護專案的人又不好找。透過webAPI service程式碼他自己找到了可疑的原因是webAPI中的這個方法有可能阻擋了他期望的webAPI行為: Instance.EnableFallback() (公司隱私,改了名), 但他無法確定這個方法在實際執行的時候的具體返回值。
聽了朋友介紹,我能想到的一個方法是看一下他們公司的這個第三方的service程式的內部情況 (非生產環境,許可權是允許的)
分析
透過kubectl exec -it [namespace:pod] /bin/bash,我們成功進入了service的pod裡。雖然是非生產環境,我們也儘量別打擾人家幹活 那麼…就選擇dump一下執行的dotnet程式嘍
由於這次的任務是觀察託管環境的某個記憶體位置的值,我選擇了用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
最後看那個_toggleConfig,Instance.EnableFallback()裡面一通呼叫最終會讀它的內容,簡化程式碼如下:
所以繼續!do看一下這個_toggleConfig:
至此原因確定,懷疑的這個方法在當前這個webAPI service下會返回false.
後記
也許有朋友會問,直接dump type是XXXConfig的instance不就行了。是的,不過在這個dump檔案中,我發現了不止一個active的XXXConfig instance, 也就是說不止一處會用到這個不唯一的XXXConfig, 而我需要明確Instance.EnableFallback最終的返回,所以需要耐心探索哈
總結
我的朋友知道了他想確定的Instance.EnableFallback在第三方service執行的時候的真實值之後,也明確了他那邊的應對這個webAPI的呼叫方式了。
這次診斷的問題雖不是cpu過高、記憶體洩漏這類資源問題,但還是用上了與排查資源洩漏相同的底層除錯診斷技術來解決。最後我的朋友很高興,吃了個定心丸