記一次某制造業ERP系統 CPU打爆事故分析( 二 )


文章插圖
從圖中可以看到 , 有兩個 xxxx/Export 請求運行時間非常高,一個是 4min30s,一個是 50s  , 剛好落在了 4246 號線程上 。

  1. 借助第二個 dump 文件
這就是為什么要抓二個dump的原因了,因為另一個dump會給我們相當有價值的對比信息,同樣使用 !whttp 驗證 。
記一次某制造業ERP系統 CPU打爆事故分析

文章插圖
接下來我們就要調研為什么這兩個線程會運行這么久?
3. 為什么會運行這么久既然是 Export 導出文件,第一時間就應該想到是不是和數據量有關?通過線程棧上的方法 , 發現是一個List 集合,接下來用 !dso 命令找出來看看 。
0:042> !dsoOS Thread Id: 0x146c (42)RSP/REGObjectName00000089ABCFCAC8 0000020683b7c128 System.Drawing.Bitmap00000089ABCFCAF8 0000020683b7c158 System.Drawing.Graphics00000089ABCFCB10 0000020683b7c128 System.Drawing.Bitmap00000089ABCFCB30 0000020683b7c128 System.Drawing.Bitmap00000089ABCFCB40 0000020683b7c4d0 NPOI.XSSF.UserModel.XSSFCellStyle00000089ABCFCB50 0000020683b7c198 NPOI.XSSF.UserModel.XSSFRichTextString00000089ABCFCB68 0000020683b7c198 NPOI.XSSF.UserModel.XSSFRichTextString00000089ABCFCBC0 0000020683b7c198 NPOI.XSSF.UserModel.XSSFRichTextString00000089ABCFCBC8 0000020683b7c2e8 System.String[]00000089ABCFCBD0 0000020683b7c360 System.Drawing.Font00000089ABCFCDE8 0000020666501240 System.Collections.Generic.List`1[[System.Collections.Generic.List`1[[System.Object, mscorlib]], mscorlib]]...0:042> !do 0000020666501240Name:System.Collections.Generic.List`1[[System.Collections.Generic.List`1[[System.Object, mscorlib]], mscorlib]]MethodTable: 00007ffbde342440EEClass:00007ffc36fc2af8Size:40(0x28) bytesFile:C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dllFields:MTFieldOffsetType VTAttrValue Name00007ffc36e4e25040018a08System.__Canon[]0 instance 00000207658592d8 _items00007ffc36e385a040018a118System.Int321 instance44906 _size00007ffc36e385a040018a21cSystem.Int321 instance44906 _version00007ffc36e35dd840018a310System.Object0 instance 0000000000000000 _syncRoot00007ffc36e4e25040018a40System.__Canon[]0sharedstatic _emptyArray>> Domain:Value dynamic statics NYI 0000020563eec3c0:NotInit dynamic statics NYI 0000020795f5b9a0:NotInit<<可以清楚的看到 , 這個list高達 4.5w,這個量級說多也不多,說少也不少 , 言外之意就是代碼寫的也不好不到哪里去 。
4. 用戶代碼要承擔責任嗎要判斷用戶代碼是不是很爛,除了白盒看代碼,也可以黑盒觀察這幾個線程棧,可以發現兩個dump 顯示的棧信息都和 AutoSizeColumn 方法有關 。
00000089abcfcae0 00007ffbdd52ac3f System.Drawing.Image.Dispose(Boolean)00000089abcfcb30 00007ffbdd556b5a System.Drawing.Image.Dispose()00000089abcfcb60 00007ffbe39397c7 NPOI.SS.Util.SheetUtil.GetCellWidth(NPOI.SS.UserModel.ICell, Int32, NPOI.SS.UserModel.DataFormatter, Boolean)00000089abcfcc00 00007ffbe3939654 NPOI.SS.Util.SheetUtil.GetCellWidth(NPOI.SS.UserModel.ICell, Int32, NPOI.SS.UserModel.DataFormatter, Boolean)00000089abcfcd30 00007ffbe39382e1 NPOI.SS.Util.SheetUtil.GetColumnWidth(NPOI.SS.UserModel.ISheet, Int32, Boolean)00000089abcfcdc0 00007ffbe39380bc NPOI.XSSF.UserModel.XSSFSheet.AutoSizeColumn(Int32, Boolean)從名字看是 NOPI 提供的自動調整列寬 的方法,那是不是這個方法的單次性能很慢呢?要尋找答案,只能求助百度啦 。。。
  • 圖一
    記一次某制造業ERP系統 CPU打爆事故分析

    文章插圖
  • 圖二
    記一次某制造業ERP系統 CPU打爆事故分析

    文章插圖
到這里我們基本就搞清楚了,導致 reqeust 高達 5min + 的誘因大概有三個 。
  1. 數據量大
  2. AutoSizeColumn 速度慢
  3. 代碼上的其他因素
跟朋友溝通后,朋友說這塊請求中的 AutoSizeColumn 方法忘了改掉 。
三:總結這個 Dump 分析起來其實非常簡單,思路也比較明朗,重點還是提醒一下大家慎用 NPOI 的 AutoSizeColumn 方法,弄不好就得出個生產事故!
記一次某制造業ERP系統 CPU打爆事故分析

文章插圖

推薦閱讀