一:背景

1. 讲故事

在我分析的众多dump中,有一些CPU爆高是因为高频的抛 Exception 导致,比如下面这张图,有 19 个线程都在抛 xxxResultException 异常。

从卦中虽知大量异常的痕迹,但从严谨的角度来说,最好再卜一卦,就是用 perfview 或者 dottrace 在 cpu 爆高的时段记录下异常的数量,这样就稳了,这篇我们就来解决这个棘手的问题。

二:异常诊断 和 Request慢处理

1. 程序异常诊断

有一个项目平时CPU的利用率都是几个点,突然在某段时间CPU明显升高,高达20多个点,我想知道此时程序在干什么?截图如下:

这种问题除了抓dump,还有一个轻量级的途径就是用 dottrace,开启 timeline 模式跟踪,收集一段时间之后,打开跟踪文件。

从卦中可以看出如下信息:

  • 大量的线程池线程正在 Running (灰蓝色)
  • Exceptions 事件个数高达 341w。
  • 产生异常最多的是 ThrowHighFrequencyException 方法。
  • 追踪周期仅为 15s

以上四个信息就能非常确认,程序的CPU爆高就是因为大量抛出异常所致,接下来选择Filters面板中的 Exceptions 进行下钻观察 异常类型异常消息 的分布,截图如下:

从卦中可以看到 InvalidOperationException 异常抛的是最多的,高达 273w,并且还是定位在 ThrowHighFrequencyException 方中,接下来对父子方法 Show Code,代码参考如下:


private static void WorkerThreadProc()
{
Random random = new Random(Thread.CurrentThread.ManagedThreadId); while (running)
{
try
{
// 80%概率抛出高频异常,20%概率抛出其他异常
if (random.Next(100) < 80)
{
ThrowHighFrequencyException();
}
else
{
ThrowLowFrequencyException(random);
}
}
catch (InvalidOperationException)
{
Interlocked.Increment(ref highFrequencyExceptions);
Interlocked.Increment(ref totalExceptions);
}
catch
{
Interlocked.Increment(ref totalExceptions);
}
}
} // 高频异常方法
private static void ThrowHighFrequencyException()
{
throw new InvalidOperationException("高频异常:无效操作");
}

到此问题真相大白,有些朋友可能想知道每个异常发生的时点,这就需要你放大 时间轴 了哈,图中的黑色便是。

还有一种方式就是打开 Event 面板 View -> Events,然后观察左侧的偏移时间(Timestamp),非常清楚加明细,截图如下:

2. Request慢处理

在给web程序做性能优化时,经常要做的一件事情就是查找慢请求,这也是 dotrace 的强项,它用一个 Incoming HTTP Requests 提供了独家支持,刚好手里有一个 dtp 文件,直接打开。

从卦中可以看到当前程序涉及到的 http 请求总时间为 12s,那 12s 都被哪些request 请求分摊着呢? 继续下钻即可,选择 Incoming HTTP Requests,截图如下:

从卦中可以看到当前 WeatherForecast/slow-random 累计时间是最高的,其次是 WeatherForecast/slow-fixed,这里有一个误区,累计时间最高不见得单次时间就高,这是一个很显然的道理。

接下来观察下 WeatherForecast/slow-random 请求的分布情况,观察时间轴可知有两次请求,截图如下:

接下来的问题是这两个请求来自于哪两个方法呢?选中一个时间稍微长的,放大时间轴之后,点击 Plain List 观察 Total Time 最高的一列即可,截图如下:

最后就是 Show Code 观察 GetWithRandomDelay 方法的源代码,参考如下:


// 2. 随机慢速接口 - 延迟2-5秒随机
[HttpGet("slow-random")]
public async Task<IEnumerable<WeatherForecast>> GetWithRandomDelay()
{
// 随机等待2-5秒
var delay = Random.Shared.Next(2000, 5000);
await Task.Delay(delay); return GenerateRandomForecasts(5);
}
// 辅助方法:生成随机天气预报数据
private IEnumerable<WeatherForecast> GenerateRandomForecasts(int count)
{
return Enumerable.Range(1, count).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
});
}

当然其他接口的调查也可以参考同样的方式。

三:总结

dotrace 非常强大,在观测 异常慢Request 处理方面表现优秀,作为一位 .NET高级调试分析师 ,这款工具不可或缺!

作为JetBrains社区内容合作者,如有购买jetbrains的产品,可以用我的折扣码 HUANGXINCHENG,有25%的内部优惠哦。

DotTrace系列:6. 程序异常诊断 和 Request慢处理的更多相关文章

  1. Java基础进阶:时间类要点摘要,时间Date类实现格式化与解析源码实现详解,LocalDateTime时间类格式化与解析源码实现详解,Period,Duration获取时间间隔与源码实现,程序异常解析与处理方式

    要点摘要 课堂笔记 日期相关 JDK7 日期类-Date 概述 表示一个时间点对象,这个时间点是以1970年1月1日为参考点; 作用 可以通过该类的对象,表示一个时间,并面向对象操作时间; 构造方法 ...

  2. C# 程序异常管理方案

    C# 程序异常管理方案 1.程序出现未处理异常(程序中未捕获异常.添加异常处理) 2.程序添加全局异常捕获 tip:程序已处理异常不在捕获范围内. /// <summary> /// 应用 ...

  3. AIX系统程序异常不释放光驱处理

    AIX操作系统有时会出现程序异常不释放光驱,可以用以下命令进行处理: #fuser -kxuc /dev/cd0 或者 #fuser /dev/cd0 以上命令会列出访问光驱设备的所有进程,然后使用k ...

  4. 调试技巧 —— 如何利用windbg + dump + map分析程序异常

    调试技巧 —— 如何利用windbg + dump + map分析程序异常 逗比汪星人2011-09-04上传   调试技巧 —— 如何利用windbg + dump + map分析程序异常 http ...

  5. android捕获程序异常退出

    今天看到迅雷动漫里面一个CrashHandler 的类,我猜是崩溃处理类.进去一看.果然.顺便学习一下. Android系统的"程序异常退出",给应用的用户体验造成不良影响.为了捕 ...

  6. Android系统的“程序异常退出”[转]

    在应用运行过程中,有很多异常可能会发生,而我们希望在异常发生的时候第一时间的保存现场. 如何处理未捕获的异常呢? 首先我们要实现一个接口  java.lang.Thread.UncaughtExcep ...

  7. 在程序异常中记录堆栈信息(使用ExWatcher)

    在我们编写程序的时候可通过IDE自带的调试环境捕捉到异常(Except)错误,并能查看到相关的信息以便我们修正程序中的问题.但当软件被发布出去后,因为所部署运行的环境与我们的调试环境有很大区别,即使在 ...

  8. 【转载】 ISO14229系列之二:诊断指令格式和相关概念

    转载链接:http://www.cnblogs.com/autogeek/p/4458658.html 1. 简单的通信机制 其实诊断通信的机制很简单,可以类比client-server通信方式,即客 ...

  9. 【微信小程序】调用wx.request接口需要注意的问题

    写在前面 之前写了一篇<微信小程序实现各种特效实例>,上次的小程序的项目我负责大部分前端后台接口的对接,然后学长帮我改了一些问题.总的来说,收获了不少吧! 现在项目已经完成,还是要陆陆续续 ...

  10. 【小程序】调用wx.request接口时需要注意的问题

    写在前面 之前写了一篇<微信小程序实现各种特效实例>,上次的小程序的项目我负责大部分前端后台接口的对接,然后学长帮我改了一些问题.总的来说,收获了不少吧! 现在项目已经完成,还是要陆陆续续 ...

随机推荐

  1. 什么是RESTful 或 GraphQL?

    RESTful 与 GraphQL 深度解析 在前端的开发过程中,相信 everyone 对 Get.POST 等请求方式都很熟悉,那么这些请求是归于哪种架构或者设计风格可能又不是很熟.现在在这简单的 ...

  2. 帮客户解决基于surging的物流速运网关内存泄漏问题

    一.概述 有surging企业客户找到我,系统已经在线上环境运行,在使用过程中碰到内存不能释放的问题,每次都要和客户打招呼进行重启造成很坏的影响,问能不能彻底解决掉,然后我打包票可以解决,解决不了不收 ...

  3. Greenplum数据库索引解析

    以下是对greenplum数据库使用总结. 创建索引 CREATE INDEX i_test_tb_state_az ON test_tb(name_en) WHERE name_en = 'AZ'; ...

  4. 使用Python建模量子隧穿

    引言 量子隧穿是量子力学中的一个非常有趣且令人神往的现象.在经典物理学中,我们通常认为粒子必须克服一个势垒才能通过它.但是,在量子力学中,粒子有时可以"穿越"一个势垒,即使它的能量 ...

  5. Spring框架中的单例bean是线程安全的吗?

    1.介绍两个概念 有状态的bean:对象中有实例变量(成员变量),可以保存数据,是非线程安全的 无状态的bean:对象中没有实例变量(成员变量),不能保存数据,可以在多线程环境下共享,是线程安全的 2 ...

  6. 线上救急-AWS限频

    线上救急-AWS限频 问题 在一个天气炎热的下午,我正喝着可口可乐,悠闲地看着Cursor生成代码,忽然各大群聊中出现了加急@全体的消息,当时就心里一咯噔,点开一看,果然,线上服务出问题,多个能源统计 ...

  7. .net6 api添加接口注释

    参照: .NET 6 Swagger添加xml注释 - 凡尘一叶~ - 博客园 (cnblogs.com)[这个比较准] .net core的Swagger接口文档使用教程(一):Swashbuckl ...

  8. 通用型产品发布解决方案(SpringBoot+SpringCloud+Spring CloudAlibaba+Vue+ElementUI+MyBatis-Plus+MySQL+Git+Maven)03

    通用型产品发布解决方案(基于分布式微服务技术栈:SpringBoot+SpringCloud+Spring CloudAlibaba+Vue+ElementUI+MyBatis-Plus+MySQL+ ...

  9. 【记录】smartctl|Linux如何通过smartctl查看有没有坏的磁盘?以及使用时长、电源周期、故障记录等

      smartctl是一个用于监测和分析硬盘健康状态的工具,可以用于检测是否存在坏的磁盘.以下是使用smartctl检查磁盘健康状态的步骤: 安装smartctl软件 在Linux系统中,smartc ...

  10. python简单的time ticker

    在某些时候,我们需要精确的启动一个func,如果用time.sleep简单的轮询,会因为执行的任务阻塞,或者其他原因导致无法精确的定时执行. 例如在采集某些数据的时候,需要精确的每60秒采集一次,如果 ...