记一次 .NET 某供应链 Web 网站 CPU 爆高事故分析

一、记次背景

1. 讲故事

年前有位朋友加微信求助,供应高事故分说他的网站程序出现了偶发性CPU爆高,寻求如何解决,记次截图如下:

我建议朋友用 procdump 在 cpu 高的供应高事故分时候连抓两个dump,这样分析起来比较稳健,网站朋友也如期的记次成功抓到,接下来就用 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 触发导致 ?

2. 查看是否 GC 触发

干脆一点就是用 ~*e !dumpstack 导出所有线程的托管和非托管栈,然后搜索 GarbageCollectGeneration 就好了。服务器租用网站

果然是记次触发了 GC,从调用栈信息看,供应高事故分当前托管层可能正在高频的网站 new 操作,导致只往某一个heap上狂写数据从而致 heap 失衡,服务器模式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.GetEnumerator()

000000b4ddc79200 00007ffe01a179eb System.Linq.Enumerable.SequenceEqual[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1, System.Collections.Generic.IEnumerable`1, System.Collections.Generic.IEqualityComparer`1)

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.Func`2)

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.Collections.Generic.IEnumerable`1, System.Collections.Generic.List`1)

000000b4ddc79a00 00007ffda7b36871 DbContextExtensions.BulkInsert[[System.__Canon, mscorlib]](System.Data.Entity.DbContext, System.Collections.Generic.IEnumerable`1, System.Action`1>)

000000b4ddc79ab0 00007ffda7b32c65 xxx.EFRepository`1[[System.__Canon, mscorlib]].BulkInsert(System.__Canon[])

...

从栈信息看,大概有如下三点信息:

正在用 EF 做批量插入操作 BulkInsert。用了 Z.EntityFramework 插件。大量的 Build, Configure 字样,貌似是在做什么配置,构建啥的网站模板

3. 是插入数据过多导致的吗?

第一个能想到的就是 list 过大,为了验证,可以用 !clrstack -a 把 BulkInsert 方法的 list 参数给导出来。

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 在所有的托管线程栈上搜关键词看看。

可以看到当前有 10 处在猛攻,依次看他们的list都不大,云服务器提供商疑惑哈

系统运维
上一篇:戴尔Precision工作站+solidworks+Vr 带来全新沉浸式体验
下一篇:通过 Docker-compose 快速部署 MinIO 保姆级教程