.NET?CPU爆高事故事故分析某供應鏈WEB網(wǎng)站
一:背景
1. 講故事
年前有位朋友加微信求助,說他的程序出現(xiàn)了偶發(fā)性CPU爆高,尋求如何解決,截圖如下:
我建議朋友用 procdump 在 cpu 高的時候連抓兩個dump,這樣分析起來比較穩(wěn)健,朋友也如期的成功抓到,接下來就用 windbg 一起來分析下吧。
二:Windbg 分析
1. 查看CPU占用率
先用 !tp 查看兩個 dump 的cpu 利用率
0:112> !tp CPU utilization: 100% Worker Thread: Total: 138 Running: 128 Idle: 10 MaxLimit: 2000 MinLimit: 400 Work Request in Queue: 17 Unknown Function: 00007ffe1a6617d0 Context: 000001fd9bcb20c8 ... -------------------------------------- Number of Timers: 2 -------------------------------------- Completion Port Thread:Total: 2 Free: 2 MaxFree: 16 CurrentLimit: 2 MaxLimit: 2000 MinLimit: 400 0:014> !tp CPU utilization: 96% Worker Thread: Total: 173 Running: 67 Idle: 106 MaxLimit: 2000 MinLimit: 400 Work Request in Queue: 1 Unknown Function: 00007ffe1a6617d0 Context: 000001fda1a20be8 -------------------------------------- Number of Timers: 2 -------------------------------------- Completion Port Thread:Total: 7 Free: 7 MaxFree: 16 CurrentLimit: 7 MaxLimit: 2000 MinLimit: 400
果然如朋友所述,接下來就可以試探的看下是不是 GC 觸發(fā)導致 ?
2. 查看是否 GC 觸發(fā)
干脆一點就是用 ~*e !dumpstack 導出所有線程的托管和非托管棧,然后搜索 GarbageCollectGeneration 就好了。
果然是觸發(fā)了 GC,從調(diào)用棧信息看,當前托管層可能正在高頻的 new 操作,導致只往某一個heap上狂寫數(shù)據(jù)從而致 heap 失衡,服務(wù)器模式GC為了讓多 heap 均衡,做了 heap balance 操作,接下來的線索是為什么有狂寫的情況? 還得看下托管層,使用 !clrstack 命令。
0:112> !clrstack OS Thread Id: 0x3278 (112) Child SP IP Call Site 000000b4ddc79098 00007ffe28b9fa74 [HelperMethodFrame: 000000b4ddc79098] 000000b4ddc791a0 00007ffda6c229cb System.Data.Entity.ModelConfiguration.Utilities.EdmPropertyPath.System.Collections.Generic.IEnumerable<System.Data.Entity.Core.Metadata.Edm.EdmProperty>.GetEnumerator() 000000b4ddc79200 00007ffe01a179eb System.Linq.Enumerable.SequenceEqual[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1<System.__Canon>, System.Collections.Generic.IEnumerable`1<System.__Canon>, System.Collections.Generic.IEqualityComparer`1<System.__Canon>) 000000b4ddc79280 00007ffda6c2297e System.Data.Entity.ModelConfiguration.Configuration.Mapping.EntityMappingConfiguration+c__DisplayClass14.b__11(System.Data.Entity.Core.Mapping.ColumnMappingBuilder) 000000b4ddc792b0 00007ffe01a13f8f System.Linq.Enumerable.SingleOrDefault[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1<System.__Canon>, System.Func`2<System.__Canon,Boolean>) 000000b4ddc79330 00007ffda6c2087c System.Data.Entity.ModelConfiguration.Configuration.Mapping.EntityMappingConfiguration.Configure(System.Data.Entity.Core.Metadata.Edm.DbDatabaseMapping, System.Data.Entity.Core.Common.DbProviderManifest, System.Data.Entity.Core.Metadata.Edm.EntityType, System.Data.Entity.Core.Mapping.StorageEntityTypeMapping ByRef, Boolean, Int32, Int32) 000000b4ddc79520 00007ffda6c20128 System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureUnconfiguredType(System.Data.Entity.Core.Metadata.Edm.DbDatabaseMapping, System.Data.Entity.Core.Common.DbProviderManifest, System.Data.Entity.Core.Metadata.Edm.EntityType) 000000b4ddc795a0 00007ffda6c1ffaf System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureTablesAndConditions(System.Data.Entity.Core.Mapping.StorageEntityTypeMapping, System.Data.Entity.Core.Metadata.Edm.DbDatabaseMapping, System.Data.Entity.Core.Common.DbProviderManifest) 000000b4ddc79620 00007ffda6c055c0 System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.ConfigureEntityTypes(System.Data.Entity.Core.Metadata.Edm.DbDatabaseMapping, System.Data.Entity.Core.Common.DbProviderManifest) 000000b4ddc79680 00007ffda6c05474 System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.Configure(System.Data.Entity.Core.Metadata.Edm.DbDatabaseMapping, System.Data.Entity.Core.Common.DbProviderManifest) 000000b4ddc796d0 00007ffda69ae5c2 System.Data.Entity.DbModelBuilder.Build(System.Data.Entity.Core.Common.DbProviderManifest, System.Data.Entity.Infrastructure.DbProviderInfo) 000000b4ddc79740 00007ffda6649ccf System.Data.Entity.DbModelBuilder.Build(System.Data.Common.DbConnection) 000000b4ddc79780 00007ffda7b4b2d3 System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(System.Data.Entity.DbContext, System.Xml.XmlWriter) 000000b4ddc797c0 00007ffda7b4acbe Class125.smethod_0(System.Data.Entity.DbContext) 000000b4ddc79820 00007ffda7b4aba4 Class617.smethod_22(System.Data.Entity.DbContext) 000000b4ddc79860 00007ffda7b4aa90 Class617.smethod_27(System.Data.Entity.DbContext) 000000b4ddc798c0 00007ffda7b3e9ec DbContextExtensions.GetModel(System.Data.Entity.DbContext) 000000b4ddc79910 00007ffda7b3e49b Class124.smethod_0(System.Data.Entity.DbContext, System.String) 000000b4ddc79950 00007ffda7b3d6c3 Class486.smethod_3[[System.__Canon, mscorlib]](System.Data.Entity.DbContext, Z.BulkOperations.BulkOperation`1<System.__Canon>, System.Collections.Generic.IEnumerable`1<System.__Canon>, System.Collections.Generic.List`1<System.Object>) 000000b4ddc79a00 00007ffda7b36871 DbContextExtensions.BulkInsert[[System.__Canon, mscorlib]](System.Data.Entity.DbContext, System.Collections.Generic.IEnumerable`1<System.__Canon>, System.Action`1<Z.EntityFramework.Extensions.EntityBulkOperation`1<System.__Canon>>) 000000b4ddc79ab0 00007ffda7b32c65 xxx.EFRepository`1[[System.__Canon, mscorlib]].BulkInsert(System.__Canon[]) ...
從棧信息看,大概有如下三點信息:
- 正在用 EF 做批量插入操作 BulkInsert。
- 用了 Z.EntityFramework 插件。
- 大量的 Build, Configure 字樣,貌似是在做什么配置,構(gòu)建啥的。
3. 是插入數(shù)據(jù)過多導致的嗎?
第一個能想到的就是 list 過大,為了驗證,可以用 !clrstack -a 把 BulkInsert 方法的 list 參數(shù)給導出來。
0:112> !clrstack -a OS Thread Id: 0x3278 (112) Child SP IP Call Site 000000b4ddc79b90 00007ffda7b31ee8 xxx.BLL.BaseService`1[[System.__Canon, mscorlib]].BulkInsert(System.__Canon[]) PARAMETERS: this (0x000000b4ddc79d10) = 0x000001fa14bbb630 _tArr (0x000000b4ddc79d18) = 0x000001fa14c1a2f8 0:112> !do 0x000001fa14c1a2f8 Name: xxx.EntityModel.xxx[] MethodTable: 00007ffda9437968 EEClass: 00007ffe02f556b0 Size: 56(0x38) bytes Array: Rank 1, Number of elements 4, Type CLASS (Print Array) Fields: None
從輸出看,當前的list.length=4,這就很疑惑了,既然 heap 都在 balance ,那是不是有幾個線程在猛攻? 為了驗證就用 DbContextExtensions.BulkInsert 在所有的托管線程棧上搜關(guān)鍵詞看看。
可以看到當前有 10 處在猛攻,依次看他們的list都不大,疑惑哈??。
4. 對問題的預判斷
有了這些思路,但總覺得觸發(fā)GC的由頭太怪了,不過可以肯定的是問題出在了 Z.EntityFramework 插件上,按照 4S店的傳統(tǒng)經(jīng)驗,只換不修肯定沒問題,由于我對 Z.EntityFramework 不熟悉,也只能這樣給到朋友了。
說來也奇怪,朋友第二天發(fā)現(xiàn)了一個奇怪現(xiàn)象,說每次 CPU 爆高之前都出現(xiàn)了一次 w3wp的異常重啟,而重啟之后由于 Z.EntityFramework 需要預熱,導致后續(xù)請求阻塞引發(fā)的 CPU 階段性爆高。
從朋友的留言加上剛才的 dump 分析,問題基本就能定位了, Build, Configure 和 banlance 操作都能解釋的通,而且還發(fā)現(xiàn)這個所謂的預熱并沒有做到串行化,而是10個線程一起來,直到預熱結(jié)束,CPU 下降。
三:總結(jié)
總的來說,這次CPU階段性爆高的事故是由于 w3wp 進程的意外重啟,導致多線程并發(fā)對 Z.EntityFramework 預熱,在預熱的過程中導致了多次 GC 觸發(fā),至于 w3wp 為什么被意外終止,這就是另外一個話題了,不過好消息是朋友在后續(xù)的幾天中從抓取的 crash dump中找到了問題代碼。
以上就是.NET CPU爆高事故事故分析某供應鏈WEB網(wǎng)站的詳細內(nèi)容,更多關(guān)于.NET WEB網(wǎng)站CPU爆高的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Could not load file or assembly "App_Licenses.dll"
Could not load file or assembly "App_Licenses.dll"的問題2010-03-03基于.NET BitmapImage 內(nèi)存釋放問題的解決方法詳解
本篇文章是對.NET BitmapImage 內(nèi)存釋放問題的解決方法進行了詳細的分析介紹,需要的朋友參考下2013-05-05C#調(diào)用動態(tài)unlha32.dll解壓Lha后綴的打包文件分享
這篇文章介紹了,C#調(diào)用動態(tài)unlha32.dll解壓Lha后綴的打包文件,有需要的朋友可以參考一下2013-09-09強烈推薦一個基于.Net Framework開發(fā)的Windows右鍵菜單管理工具
這篇文章主要介紹了推薦一個基于.Net Framework開發(fā)的Windows右鍵菜單管理工具,今天給大家推薦一個Windows右鍵菜單管理工具,方便我們管理我們的右鍵菜單,需要的朋友可以參考下2023-05-05