记一次 .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<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字样,貌似是在做什么配置,构建啥的。
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都不大,疑惑哈。
4. 对问题的预判断
有了这些思路,但总觉得触发GC的由头太怪了,不过可以肯定的是问题出在了 Z.EntityFramework 插件上,按照 4S店的传统经验,只换不修肯定没问题,由于我对 Z.EntityFramework 不熟悉,也只能这样给到朋友了。
说来也奇怪,朋友第二天发现了一个奇怪现象,说每次 CPU 爆高之前都出现了一次 w3wp 的异常重启,而重启之后由于 Z.EntityFramework 需要预热,导致后续请求阻塞引发的 CPU 阶段性爆高。
从朋友的留言加上刚才的 dump 分析,问题基本就能定位了, Build, Configure 和 banlance 操作都能解释的通,而且还发现这个所谓的预热并没有做到串行化,而是10个线程一起来,直到预热结束,CPU 下降。
三:总结
总的来说,这次CPU阶段性爆高的事故是由于 w3wp 进程的意外重启,导致多线程并发对 Z.EntityFramework 预热,在预热的过程中导致了多次 GC 触发,至于 w3wp 为什么被意外终止,这就是另外一个话题了,不过好消息是朋友在后续的几天中从抓取的 crash dump 中找到了问题代码。

记一次 .NET 某供应链WEB网站 CPU 爆高事故分析的更多相关文章
- 记一次 .NET 某旅行社Web站 CPU爆高分析
一:背景 1. 讲故事 前几天有位朋友wx求助,它的程序内存经常飙升,cpu 偶尔飙升,没找到原因,希望帮忙看一下. 可惜发过来的 dump 只有区区2G,能在这里面找到内存泄漏那真有两把刷子..., ...
- 记一次 .NET 某电商交易平台Web站 CPU爆高分析
一:背景 1. 讲故事 已经连续写了几篇关于内存暴涨的真实案例,有点麻木了,这篇换个口味,分享一个 CPU爆高 的案例,前段时间有位朋友在 wx 上找到我,说他的一个老项目经常收到 CPU > ...
- 记一次 .NET游戏站程序的 CPU 爆高分析
一:背景 1. 讲故事 上个月有个老朋友找到我,说他的站点晚高峰 CPU 会突然爆高,发了两份 dump 文件过来,如下图: 又是经典的 CPU 爆高问题,到目前为止,对这种我还是有一些经验可循的. ...
- 记一次 .NET 某医院HIS系统 CPU爆高分析
一:背景 1. 讲故事 前几天有位朋友加 wx 抱怨他的程序在高峰期总是莫名其妙的cpu爆高,求助如何分析? 和这位朋友沟通下来,据说这问题困扰了他们几年,还请了微软的工程师过来解决,无疾而终,应该还 ...
- 记一次 .NET 某市附属医院 Web程序 偶发性CPU爆高分析
一:背景 1. 讲故事 这个月初,一位朋友加微信求助他的程序出现了 CPU 偶发性爆高,希望能有偿解决一下. 从描述看,这个问题应该困扰了很久,还是医院的朋友给力,开门就是 100块 红包 ,那既然是 ...
- 再记一次 应用服务器 CPU 暴高事故分析
一:背景 1. 前言 大概有2个月没写博客了,不是不想写哈
- 记一次 .NET医疗布草API程序 内存暴涨分析
一:背景 1. 讲故事 我在年前写过一篇关于CPU爆高的分析文章 再记一次 应用服务器 CPU 暴高事故分析 ,当时是给同济做项目升级,看过那篇文章的朋友应该知道,最后的结论是运维人员错误的将 IIS ...
- JAVA WEB快速入门之从编写一个JSP WEB网站了解JSP WEB网站的基本结构、调试、部署
接上篇<JAVA WEB快速入门之环境搭建>,在完成了环境搭建后(JDK.Tomcat.IDE),现在是万事具备,就差写代码了,今天就来从编写一个JSP WEB网站了解JSP WEB网站的 ...
- ASP.NET Web网站中App_Code文件夹的作用及使用场景
原文地址:Web Site项目和ASP.NET Web Application中App_Code文件夹的作用作者:宾的宾 我现在要建一个ASP.NET的网站了,不难吧,开始动手.如下图: 这种方法建立 ...
随机推荐
- PAT 乙级 1004. 成绩排名 (20)(C语言描述)
读入n名学生的姓名.学号.成绩,分别输出成绩最高和成绩最低学生的姓名和学号. 输入格式:每个测试输入包含1个测试用例,格式为 第1行:正整数n 第2行:第1个学生的姓名 学号 成绩 第3行:第2个学生 ...
- 计算机二级考试office专题之绝对引用相对引用
- 【记录一个问题】MariaDB 10.1.9 中with rollup的神器问题
我想统计每天数据的处理状态的汇总,于是写了这样一条语句: 1 select * from ( 2 select ifnull(date(update_time),'_30天汇总') as dtm, i ...
- 访问者模式(Visitor模式)
模式的定义与特点 访问者(Visitor)模式的定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提 ...
- Git使用简单教程,从建库到远程操作
本地库初始化 找到项目文件->右键git bash->git init 设置签名 形式: 用户名 邮箱地址 作用: 区分不同开发人员身份 注意:这里设置的签名和登录的远程库的账号密码没有任 ...
- es6 快速入门 系列 —— 类 (class)
其他章节请看: es6 快速入门 系列 类 类(class)是 javascript 新特性的一个重要组成部分,这一特性提供了一种更简洁的语法和更好的功能,可以让你通过一个安全.一致的方式来自定义对象 ...
- .Net Api 之如何使用Elasticsearch存储文档
.Net Api 之如何使用Elasticsearch存储文档 什么是Elasticsearch? Elasticsearch 是一个分布式.高扩展.高实时的搜索与数据分析引擎.它能很方便的使大量数据 ...
- linux文件详细说明与inode编号
目录 一:文件类型概念说明 1.文件详细信息详解 2.inode编号 一:文件类型概念说明 1.文件详细信息详解 文件详细信息编号 ls - lhi /etc/ 134319695 -rw------ ...
- mysql加强(6)~子查询简单介绍、子查询分类
一.子查询简单介绍 1.什么是子查询? 一个查询之中嵌套了其他的若干查询. 在使用select 语句查询时,有时候where的查询条件中的限制条件不是一个确定的值,而是一个来自于另一个查询的结果. 子 ...
- Python初学笔记列表&元组&字典
一.从键盘获取 1 print("请输入") 2 username = input("姓名:") 3 age = input("年龄:") ...