一:背景
1. 講故事
這個案例有點特殊,以前dump分析都是和軟體工程師打交道,這次和非業內人士交流,隔行如隔山,從指導dump怎麼抓到問題解決,需要一個強大的耐心。
前幾天有位朋友在微信上找到我,說他們公司採購的MES系統登入的時候出現了異常,讓我幫忙看一下,我在想解鈴還須繫鈴人,怎麼的也不應該找到我呀,據朋友反饋專案已經驗收,那邊給了回饋是網路的問題,可能沒有幫他們更深入的分析吧,找我的目的應該就是驗證下對方公司說的對不對 ???
二:WinDbg 分析
1. 真的是網路問題嗎
在沒有專案原始碼和日誌的情況下,最好的方式就是抓dump,一樣可以找出問題所在,讓朋友在程式登入卡死的時候抓了一個dump,接下來看下是不是對方工程師所說的網路問題。
因為有卡死發生,必然有一個執行緒在等待什麼,我們可以用 ~*e !clrstack
看下所有的執行緒的執行緒棧。
0:000:x86> ~*e !clrstack
...
OS Thread Id: 0x2094 (14)
Child SP IP Call Site
0f94e888 0000002b [GCFrame: 0f94e888]
0f94e938 0000002b [HelperMethodFrame_1OBJ: 0f94e938] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)
...
0f94ead0 6b53d7b6 System.Threading.Tasks.Task.Wait(Int32, System.Threading.CancellationToken) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 3167]
0f94eae0 1468ae6b MySql.Data.Common.Ssl.StartSSL(System.IO.Stream ByRef, System.Text.Encoding, System.String)
0f94eb38 14687a55 MySql.Data.MySqlClient.NativeDriver.Open()
0f94ec04 14686e63 MySql.Data.MySqlClient.Driver.Open()
0f94ec28 14686ac7 MySql.Data.MySqlClient.Driver.Create(MySql.Data.MySqlClient.MySqlConnectionStringBuilder)
0f94ec50 146869ec MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection()
0f94ec58 14686957 MySql.Data.MySqlClient.MySqlPool.GetPooledConnection()
0f94ec8c 146863e9 MySql.Data.MySqlClient.MySqlPool.TryToGetDriver()
0f94ecac 146862ca MySql.Data.MySqlClient.MySqlPool.GetConnection()
0f94ece0 146817c1 MySql.Data.MySqlClient.MySqlConnection.Open()
0f94ed18 0ca28753 xxx.GetMySqlConnection()
...
0f94efec 0ca21902 xxx.UserLogin(System.String, System.String)
...
0f94f4ac 6b4ae9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
0f94f6cc 6c500556 [DebuggerU2MCatchHandlerFrame: 0f94f6cc]
...
透過觀察發現 14
號執行緒在一個 xxx.UserLogin
方法中,應該就是朋友點選的登入按鈕的邏輯,通讀一下執行緒棧可以看到它是在 MySql.Data.Common.Ssl.StartSSL
方法中等待,看樣子是在這裡超時了。
一般來說 mysql 是內網的話,不會特別去配什麼 ssl 證照,這個太麻煩了,接下來驗證下 mysql 是內網還是外網,可以用 !dso
檢視mysql 的連線串。
從上面的 192.168
字首來看果然是內網,這時候猜測走 SSL 肯定是意料之外的場景。
2. 真的要走 SSL
記得大概3-4年前在上海上班的時候,曾經有一個專案升級之後使用了nuget上的 mysql 8.0,然後專案就無法訪問了,報了什麼授權錯誤,看樣子應該就是目前這個專案遇到的場景。
接下來要驗證下這個 mysql 的sdk 是 8.0 的版本嗎? 可以用 lm 找下 MySQL.Data
模組。
0:014:x86> lm
start end module name
...
12b40000 12ca6000 MySql_Data (deferred)
...
0:014:x86> lm vm MySql_Data
Browse full module list
start end module name
12b40000 12ca6000 MySql_Data (deferred)
Image path: C:\Users\xxxx\MySql.Data.dll
Image name: MySql.Data.dll
Browse all global symbols functions data
Has CLR image header, track-debug-data flag not set
Image was built with /Brepro flag.
Timestamp: 95CE4983 (This is a reproducible build file hash, not a timestamp)
CheckSum: 001611FF
ImageSize: 00166000
File version: 8.0.29.0
Product version: 8.0.29.0
File flags: 0 (Mask 3F)
File OS: 4 Unknown Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0000.04b0
Information from resource tables:
CompanyName: Oracle
ProductName: MySql.Data.Core
InternalName: MySql.Data.dll
OriginalFilename: MySql.Data.dll
ProductVersion: 8.0.29
FileVersion: 8.0.29.0
FileDescription: MySql.Data
LegalCopyright: Copyright © 2016, 2020, Oracle and/or its affiliates. All rights reserved.
LegalTrademarks:
Comments: ADO.Net driver for MySQL for .Net Framework and .Net Core
從上面的 Product version
來看果然是 8.0
版本,驗證了我的猜想,接下來就是讓朋友在連線串中加上 SslMode=None
標記,類似下面這樣。
<add key="上報平臺1" value="mysql|Database = drp; Data Source = 192.168.xx.xx; port = 3306; User Id = xxx; Password = xxx;SslMode=None" />
把結果告訴朋友之後,朋友第二天反饋問題搞定。
不過他做了一個大膽的操作,禁用了 MySQL 的 hava_openssl
。
說實話這個影響面太大了,副作用小一點的話加上一個字尾就好,不管怎麼樣解決了問題就行。
三:總結
總的來說這個問題對一個開發來說很簡單,但如果溝通物件是一個非開發,沒有原始碼,沒有日誌 還能準確定位問題,是一件挺有挑戰的事情。