一:背景

1. 讲故事

大概有两个月没写博客了,关注我的朋友应该知道我最近都把精力花在了星球,这两个月时间也陆陆续续的有朋友求助如何分析dump,有些朋友太客气了,给了大大的红包,哈哈????,手里面也攒了10多个不同问题类型的dump,后续也会逐一将分析思路贡献出来。

这个dump是一位朋友大概一个月前提供给我的,由于wx里面求助的朋友比较多,一时也没找到相关截图,不得已破坏一下老规矩。????????????

既然朋友说api接口无响应,呈现了hangon现象,从一些过往经验看,大概也只有三种情况。

  • 大量锁等待

  • 线程不够用

  • 死锁

有了这种先入为主的思想,那就上windbg说事呗。

二:windbg 分析

1. 有大量锁等待吗?

要想看是否锁等待,老规矩,看一下 同步块表


0:000> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info  SyncBlock Owner
-----------------------------
Total           1673
CCW             3
RCW             4
ComClassFactory 0
Free            397

扑了个空,啥也没有,那就暴力看看所有的线程栈吧。

不看还好,一看吓一跳,有339个线程卡在了 System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object) 处,不过转念一想,就算有339个线程卡在这里,真的会导致程序hangon吗?也不一定,毕竟我看过有1000+的线程也不会卡死,只不过cpu爆高而已,接下来继续研判一下是不是线程不够用导致,可以从 线程池任务队列 上面入手。

2. 探究线程池队列

可以用 !tp 命令查看。


0:000> !tp
CPU utilization: 10%
Worker Thread: Total: 328 Running: 328 Idle: 0 MaxLimit: 32767 MinLimit: 4
Work Request in Queue: 74Unknown Function: 00007ffe91cc17d0  Context: 000001938b5d8d98Unknown Function: 00007ffe91cc17d0  Context: 000001938b540238Unknown Function: 00007ffe91cc17d0  Context: 000001938b5eec08...Unknown Function: 00007ffe91cc17d0  Context: 0000019390552948Unknown Function: 00007ffe91cc17d0  Context: 0000019390562398Unknown Function: 00007ffe91cc17d0  Context: 0000019390555b30
--------------------------------------
Number of Timers: 0
--------------------------------------
Completion Port Thread:Total: 5 Free: 4 MaxFree: 8 CurrentLimit: 4 MaxLimit: 1000 MinLimit: 4

从输出信息看,线程池中328个线程全部打满,工作队列中还有74位客人在等待,综合这两点信息就已经很清楚了,本次hangon是由于大量的客人到来超出了线程池的接待能力所致。

3. 接待能力真的不行吗?

这个标题我觉得很好,真的不行吗?到底行不行,可以从两点入手:

  • 是不是代码写的烂?

  • qps是不是真的超出了接待能力?

要想找出答案,还得从那 339 个卡死的线程说起,仔细研究了下每一个线程的调用栈,大概卡死在这三个地方。

<1>. GetModel


public static T GetModel<T, K>(string url, K content)
{T result = default(T);HttpClientHandler httpClientHandler = new HttpClientHandler();httpClientHandler.AutomaticDecompression = DecompressionMethods.GZip;HttpClientHandler handler = httpClientHandler;using (HttpClient httpClient = new HttpClient(handler)){string content2 = JsonConvert.SerializeObject((object)content);HttpContent httpContent = new StringContent(content2);httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");string mD5ByCrypt = Md5.GetMD5ByCrypt(ConfigurationManager.AppSettings["SsoToken"] + DateTime.Now.ToString("yyyyMMdd"));httpClient.DefaultRequestHeaders.Add("token", mD5ByCrypt);httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));HttpResponseMessage result2 = httpClient.PostAsync(url, httpContent).Result;if (result2.IsSuccessStatusCode){string result3 = result2.Content.ReadAsStringAsync().Result;return JsonConvert.DeserializeObject<T>(result3);}return result;}
}

<2>. Get

public static T Get<T>(string url, string serviceModuleName)
{try{T val3 = default(T);HttpClient httpClient = TryGetClient(serviceModuleName, true);using (HttpResponseMessage httpResponseMessage = httpClient.GetAsync(GetRelativeRquestUrl(url, serviceModuleName, true)).Result){if (httpResponseMessage.IsSuccessStatusCode){string result = httpResponseMessage.Content.ReadAsStringAsync().Result;if (!string.IsNullOrEmpty(result)){val3 = JsonConvert.DeserializeObject<T>(result);}}}T val4 = val3;val5 = val4;return val5;}catch (Exception exception){throw;}
}

<3>. GetStreamByApi


public static Stream GetStreamByApi<T>(string url, T content)
{Stream result = null;HttpClientHandler httpClientHandler = new HttpClientHandler();httpClientHandler.AutomaticDecompression = DecompressionMethods.GZip;HttpClientHandler handler = httpClientHandler;using (HttpClient httpClient = new HttpClient(handler)){httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));string content2 = JsonConvert.SerializeObject((object)content);HttpContent httpContent = new StringContent(content2);httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");HttpResponseMessage result2 = httpClient.PostAsync(url, httpContent).Result;if (result2.IsSuccessStatusCode){result = result2.Content.ReadAsStreamAsync().Result;}httpContent.Dispose();return result;}
}

4. 寻找真相

上面我罗列的这三个方法的代码,不知道大家可看出什么问题了?对,就是 异步方法同步化,这种写法本身就很低效,主要表现在2个方面。

  • 开闭线程本身就是一个相对耗费资源和低效的操作。

  • 频繁的线程调度给了cpu巨大的压力

而且这种写法在请求量比较小的情况下还看不出什么问题,一旦请求量稍大一些,马上就会遇到该dump的这种情况。

三:总结

综合来看这次hangon事故是由于开发人员 异步方法不会异步化 导致,改法很简单,进行纯异步化改造 (await,async),解放调用线程,充分利用驱动设备的能力。

这个dump也让我想起了 CLR Via C# 书中(P646,647) 在讲用 await,async 来改造 同步请求 的例子 。

我觉得这个dump就是该例子的最好佐证!????????????

END

工作中的你,是否已遇到 ...

1. CPU爆高

2. 内存暴涨

3. 资源泄漏

4. 崩溃死锁

5. 程序呆滞

等紧急事件,全公司都指望着你能解决...  危难时刻才能展现你的技术价值,作为专注于.NET高级调试的技术博主,欢迎微信搜索: 一线码农聊技术,免费协助你分析Dump文件,希望我能将你的踩坑经验分享给更多的人。

记一次 .NET 某云采购平台API 挂死分析相关推荐

  1. 记一次 .NET 某纺织工厂 MES系统 API 挂死分析

    一:背景 1. 讲故事 这个月中旬,有位朋友加我wx求助他的程序线程占有率很高,寻求如何解决,截图如下: 说实话,和不同行业的程序员聊天还是蛮有意思的,广交朋友,也能扩大自己的圈子,朋友说他因为这个b ...

  2. 大型企业采购云管理平台的诉求分析-行云管家

    不同规模的企业对于云管理平台的诉求是不同的,今天我们就一起来简单分析一下大型企业采购云管理平台的诉求. 大型企业采购云管理平台的诉求分析-行云管家 诉求一.运维提效,操作方便 提高运维人员的工作效率, ...

  3. 汽修采购业务线上化,数商云采购平台系统实现企业采购高效协同

    在汽修行业,汽车配件的车型规格繁多,技术业务性强,各种商品采购过程的艰难性.销售状况的复杂性等等,汽修企业在采购环节中往往会陷入种种困境,极大地降低了汽修企业的运营效率. 随着供应链成为企业竞争的新引 ...

  4. 建筑建材数字化采购优化|数商云采购平台整合供应商协同管理/供应商考核体系

    建筑建材行业作为社会一个举足轻重的组成部分,承担着城市建设的重要使命,扮演着提供基础服务的角色.随着数字化的快速发展,建材行业和其他行业一样,正在经历商业模式的巨大变化,企业必须对市场上的变化做出及时 ...

  5. 梦网云通讯平台API单条短信发送接口single_send说明POST请求实例

    urlencode userid=J10003&pwd=26dad7f364507df18f3841cc9c4ff94d&mobile=13800138000&content= ...

  6. 记一次 .NET 某新能源汽车锂电池检测程序 UI挂死分析

    一:背景 1. 讲故事 这世间事说来也奇怪,近两个月有三位朋友找到我,让我帮忙分析下他的程序hangon现象,这三个dump分别涉及:医疗,新能源,POS系统.截图如下: 那这篇为什么要拿其中的 新能 ...

  7. 记一次 .NET WPF布草管理系统 挂死分析

    一:背景 1. 讲故事 这几天看的 dump 有点多,有点伤神伤脑,晚上做梦都是dump,今天早上头晕晕的到公司就听到背后同事抱怨他负责的WPF程序挂死了,然后测试的小姑娘也跟着抱怨...嗨,也不知道 ...

  8. 数商云企业采购平台方案丨直联多家供应商,打造一站式采购商城前端

    企业采购存在的难题: 1.蓬勃发展的消费侧互联网平台和封闭的供给侧企业采购系统之间存在鸿沟 消费侧互联网平台面向个人用户,在商务条件方面和企业采购并不匹配,系统之间更是难以集成. 2.传统模式的供应链 ...

  9. 全球及中国混合云监控平台行业行业运营态势及投资规划报告2022-2028年

    全球及中国混合云监控平台行业行业运营态势及投资规划报告2022-2028年 详情内容请咨询鸿晟信合研究院! [全新修订]:2022年3月 [撰写单位]:鸿晟信合研究网 2021年全球混合云监控平台市场 ...

最新文章

  1. git配置报错fatal: Authentication failed for ‘‘问题解决
  2. 性能优化-Bitmap内存管理及优化
  3. Java进阶:CountDownLatch倒计时
  4. C/C++头文件规整
  5. 【css】文字垂直居中
  6. linuxMint下安装ftp工具--filezilla
  7. java猜拳游戏代码_Java实现简单猜拳游戏
  8. 如何在Windows 10上限制Wi​​ndows Update的下载带宽
  9. solr cloud 更新 solrconfig 配置_Solr各版本新特性「4.x,5.x,6.x,7.x」
  10. 车刀 matlab,可转位车刀的结构
  11. mysql 触发器 sql日志_触发器实现记录操作表的日志
  12. 【毕业答辩】学位论文答辩ppt指南!
  13. 【Android】proguard混淆代码
  14. AD09画pcb板时遇到的问题
  15. HTTP下载龙卷风系列Office/Photoshop/金山词霸快译/
  16. 迅捷音频转换器怎么使用?
  17. python写植物大战僵尸简单版_写个最简单的植物大战僵尸修改器吧!c和python
  18. [计算机毕业设计]深度学习的图标型验证码识别系统
  19. 1000m交叉网线最简单做法
  20. JdbcTemplate数据库连接耗尽问题排查

热门文章

  1. Java发送邮件(带附件)
  2. 上传jar包到nexus私服
  3. iOS AVPlayer 简单应用
  4. 个人作业-Week2
  5. android数据持久化存储(2)
  6. PHP开发学习-Apache+PHP+MySQL环境搭建
  7. 创业95%失败不是因项目本身
  8. DropDownList 選項改變確認腳本
  9. linux备份mysql需要暂停服务吗_【MySQL运维】线上MySQL数据库停服迁移流程
  10. 4 关卡流 进阶_全息武器全解析,记住4个点全区第一就是你!