前言:

 近期在项目中出现了几次服务内存资源占用较高的情况,特回顾梳理下排查过程以及对相应问题的排查方法总结。

一、Dump抓取

 抓取dump的方式有多种,下面介绍几种常用的:

  1. 任务管理器中找到程序进程,右键菜单:创建转存储文件

   

   注意:需要以程序运行的位数运行任务管理器抓取Dump

  2. DotNet 全局工具:dotnet-dump;工具可适用于Windows、Linux、macOS平台

   a) 安装全局dotnet-dump工具:

dotnet tool install --global dotnet-dump

   b) 使用该工具抓取dump:

dotnet-dump collect [-h|--help] [-p|--process-id] [-n|--name] [--type] [-o|--output] [--diag]
    • -h|--help:显示命令行帮助。
    • -p|--process-id <PID>:指定从中收集转储的进程的 ID 号。
    • -n|--name <name>:指定从中收集转储的进程的名称。
    • --type <Full|Heap|Mini>:指定转储类型,它确定从进程收集的信息的类型。 有三种类型:Full - 最大的转储,包含所有内存(包括模块映像)。Heap - 大型且相对全面的转储,其中包含模块列表、线程列表、所有堆栈、异常信息、句柄信息和除映射图像以外的所有内存。Mini - 小型转储,其中包含模块列表、线程列表、异常信息和所有堆栈。如果未指定,则 Full 为默认类型。
    • -o|--output <output_dump_path>:应在其中写入收集的转储的完整路径和文件名。如果未指定:在 Windows 上默认为 .\dump_YYYYMMDD_HHMMSS.dmp ;在 Linux 上默认为 ./core_YYYYMMDD_HHMMSS ;YYYYMMDD 为年/月/日,HHMMSS 为小时/分钟/秒。
    • --diag:启用转储收集诊断日志记录。

  3、ProcDump抓取Dump工具:自动抓取

    命令语法:

procdump.exe [-mm] [-ma] [-mp] [-mc Mask] [-md Callback_DLL] [-mk]
[-n Count]
[-s Seconds]
[-c|-cl CPU_Usage [-u]]
[-m|-ml Commit_Usage]
[-p|-pl Counter_Threshold]
[-h]
[-e [1 [-g] [-b]]]
[-l]
[-t]
[-f Include_Filter, ...]
[-fx Exclude_Filter, ...]
[-o]
[-r [1..5] [-a]]
[-at Timeout]
[-wer]
[-64]
{
{{[-w] Process_Name | Service_Name | PID} [Dump_File | Dump_Folder]}
|
{-x Dump_Folder Image_File [Argument, ...]}
}

   参数说明:    

参数 说明
-a 避免中断。 需要 -r。 如果触发器会导致目标因超出并发转储限制而长时间挂起,将跳过触发器。
-at 避免超时中断。 在 N 秒时取消触发器的集合。
-b 将调试断点视为异常 (否则忽略它们) 。
-c CPU 阈值,用于创建进程的转储。
-cl CPU 阈值,低于该阈值可创建进程的转储。
-d 调用指定 DLL 的名为 MiniDumpCallbackRoutine 的小型转储回调例程。
-e 当进程遇到未经处理异常时编写转储。 包括 1,以在出现第一机会异常时创建转储。
-f 筛选第一个可能异常。 支持通配符 (*) 。 若要仅显示名称而不进行转储,请使用空白 ("") 筛选器。
-fx 筛选 (排除) 异常内容和调试日志记录。 支持通配符。
-g 在托管进程中作为本机调试器运行, (互操作) 。
-h 如果进程有挂起的窗口, (在至少 5 秒未响应窗口消息时写入) 。
-i 将 ProcDump 安装为 AeDebug 事后调试器。 仅支持使用 -ma、-mp、-d 和 -r 作为附加选项。
-k 克隆到 (-r) 或转储收集结束时终止进程
-l 显示进程的调试日志记录。
-m 内存提交阈值(以 MB 为单位)用于创建转储。
-ma 编写包含所有进程内存的转储文件。 默认转储格式仅包含线程和处理信息。
-mc 编写自定义转储文件。 包括由指定的十六进制MINIDUMP_TYPE掩码 (内存) 。
-md 编写回调转储文件。 包括由指定 DLL 的名为 MiniDumpCallbackRoutine 的 MiniDumpWriteDump 回调例程定义的内存。
-mk 同时编写内核转储文件。 包括进程中线程的内核堆栈。 使用克隆 (-r) 时,OS 不支持内核转储 (-mk) 。 使用多个转储大小时,会针对每个转储大小执行内核转储。
-ml 当内存提交低于指定的 MB 值时触发。
-mm 使用默认模式编写 (转储) 。
-mp 使用线程和句柄信息以及所有读/写进程内存编写转储文件。 为了最大程度地减小转储大小,将搜索大于 512MB 的内存区域,如果找到,则排除最大的区域。 内存区域是大小相同的内存分配区域的集合。 删除此内存 (缓存) 将Exchange和SQL Server转储减少 90% 以上。
-n 退出前要写入的转储数。
-o 覆盖现有的转储文件。
-p 超过阈值时,对指定性能计数器触发。 注意:若要在进程有多个实例运行时指定进程计数器,请使用具有以下语法的进程 ID:"\Process (< name > _ < pid >) \counter"
-pl 当性能计数器低于指定值时触发。
-r 使用克隆进行转储。 并发限制是可选的 (默认为 1,最大为 5) 。
警告:高并发值可能会影响系统性能。
- Windows 7:使用反射。 OS 不支持 -e。
- Windows 8.0:使用反射。 OS 不支持 -e。
- Windows 8.1+:使用 PSS。 支持所有触发器类型。
-s 写入转储之前连续秒 (默认值为 10) 。
-t 在进程终止时写入转储。
-u 将 CPU 使用率视为与 -c (一) 。
作为唯一选项,卸载 ProcDump 作为事后调试器。
-w 等待指定的进程启动(如果该进程未运行)。
-wer 将 (最大) 排队到Windows 错误报告。
-x 使用可选参数启动指定的映像。 如果是应用商店应用程序或包,ProcDump 将在下次激活时启动, (激活) 。
-64 默认情况下,在 64 位进程上运行时,ProcDump 将捕获 32 位进程的 32 位Windows。 此选项将替代 以创建 64 位转储。 仅用于 WOW64 子系统调试。
-? 使用 -? -e 查看示例命令行。

   示例:

    当进程在 5 秒钟内 CPU 使用率超过 50% 时,最多写入 2 个名为"w3wp"的进程的微型转储:

procdump -ma -s 5 -n 2 -c 50 w3wp

二、Dump分析

 根据前面几方式得到的Dump文件,下一步就是对Dump进行分析确认问题原因:

 1、Windbug Preview 分析:

  Windbg Preview是windows平台上的一款相当强大的调试工具,可以从msdn网站下载得到,最新版本包含在windows sdk中,默认会被安装在C:\Program Files\Debugging Tools for Windows 目录中,可以直接把这个目录打包复制到其它机器上使用。

  Windbug常用命令:

    • !analyze -v    自动分析dump
    • kv    查看栈回溯
    • .ecxr    显示当前异常上下文
    • .cxr    切换异常帧上下文
    • .exr    显示异常信息
    • .frame    设置当前栈帧
    • dv    显示当前栈帧局部变量
    • dd    显示内存中的数据
    • r    查看寄存器
    • lmvm    查看模块详细信息
    • r    可以显示系统崩溃时的寄存器,和最后的命令状态
    • dd    显示当前内存地址,dd 参数:显示参数处的内存
    • u    可以显示反汇编的指令
    • kb    显示call stack 内容

   

 2、VS分析Dump:

  a) 使用VS打开dump文件:

   

 可以看到该dump的基本信息,接下来设置符号文件:

   

b) 分析Dump中内存情况:调试托管内存

 

   可以看到当前托管资源中内存占用情况,如果有多个dump还可以对比dump中内存增长变化

   查看对象内容:

   

c) 查看当前运行的进程列表:(设置了符号文件后可以查看当前堆栈信息,以及跳转到代码逻辑)

  

 3、dotnet-dump分析:

  分析命令:

dotnet-dump analyze <dump_path> [-h|--help] [-c|--command]

  SOS命令支持:

命令 函数
soshelp|help 显示所有可用命令
soshelp|help <command> 执行指定的命令。
exit|quit 退出交互模式。
clrstack <arguments> 仅提供托管代码的堆栈跟踪。
clrthreads <arguments> 列出正在运行的托管线程。
dumpasync <arguments> 显示有关垃圾回收堆上异步状态机的信息。
dumpassembly <arguments> 显示有关指定地址处程序集的详细信息。
dumpclass <arguments> 显示有关指定地址处的 EEClass 结构的信息。
dumpdelegate <arguments> 显示有关指定地址处的委托的信息。
dumpdomain <arguments> 显示所有 AppDomain 和指定域中的所有程序集的信息。
dumpheap <arguments> 显示有关垃圾回收堆的信息和有关对象的收集统计信息。
dumpil <arguments> 显示与托管方法关联的 Microsoft 中间语言 (MSIL)。
dumplog <arguments> 将内存中压力日志的内容写入到指定文件。
dumpmd <arguments> 显示有关指定地址处的 MethodDesc 结构的信息。
dumpmodule <arguments> 显示有关指定地址处的模块的信息。
dumpmt <arguments> 显示有关指定地址处的 MethodTable 的信息。
dumpobj <arguments> 显示有关位于指定地址处的对象的信息。
dso|dumpstackobjects <arguments> 显示在当前堆栈的边界内找到的所有托管对象。
eeheap <arguments> 显示有关内部运行时数据结构所使用的进程内存的信息。
finalizequeue <arguments> 显示所有已进行终结注册的对象。
gcroot <arguments> 显示有关对指定地址处的对象的引用(或根)的信息。
gcwhere <arguments> 显示传入参数在 GC 堆中的位置。
ip2md <arguments> 显示 JIT 代码中指定地址处的 MethodDesc 结构。
histclear <arguments> 释放由 hist* 命令系列使用的任何资源。
histinit <arguments> 从保存在调试对象中的压力日志初始化 SOS 结构。
histobj <arguments> 显示与 <arguments> 相关的垃圾回收压力日志重定位。
histobjfind <arguments> 显示在指定地址处引用对象的所有日志项。
histroot <arguments> 显示与指定根的提升和重定位相关的信息。
lm|modules 显示进程中的本机模块。
name2ee <arguments> 显示 <argument> 的 MethodTable 和 EEClass 结构。
pe|printexception <arguments> 显示从 Exception 类派生的 <argument> 的任何对象。
setsymbolserver <arguments> 启用符号服务器支持
syncblk <arguments> 显示 SyncBlock 持有者信息。
threads|setthread <threadid> 设置或显示 SOS 命令的当前线程 ID。

  例如:

dotnet-dump analyze "w3wp (2).DMP"

三、案例:

  问题现象:xxx服务请求响应耗时较长,导致业务无法正常开展

  排查过程:

   1、查看内存情况,Oracle连接数量较大

    

   2、查看线程中都为Oracle连接等待:

    

   3、最终确认请求被卡到了Oracle处理

四、总结

  1、在排查服务相关问题时,分析dump方式是最直接的方式;而vs方式分析dump是最直接、方便、简单的方式。

  2、通过windbug分析dump是最完整的方式

参考:

  windbg命令

.Net Core服务诊断排查的更多相关文章

  1. .NET Core 服务诊断工具

    前言: 前一篇文中介绍了.NET Core-全局性能诊断工具 的使用方法,那么接下来自己实现一个简单.NET Core的诊断工具. 该工具主要包括:.NET Core 程序进程信息查看.性能计数器结果 ...

  2. 异步tcp通信——APM.Core 服务端概述

    为什么使用异步 异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池.就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理.异步操作执行时,会将操作丢给 ...

  3. RPC服务超时排查思路

    RPC服务超时排查思路- 1.查看服务提供者日志相关信息进行排查- 2.查看消费者的超时时间设置是否合理- 3.查看服务提供者业务逻辑是否有DB操作,有的话看是否有慢SQL- 4.查看服务提供者业务逻 ...

  4. net core体系-web应用程序-4net core2.0大白话带你入门-9asp.net core服务的生命周期

    asp.net core服务的生命周期   Transient:每一次GetService都会创建一个新的实例 Scoped:在同一个Scope内只初始化一个实例 ,可以理解为( 每一个request ...

  5. 微服务中的健康监测以及其在ASP.NET Core服务中实现运行状况检查

    1 .什么是健康检查? 健康检查几乎就是名称暗示的.它是一种检查您的应用程序是否健康的方法.随着越来越多的应用程序转向微服务式架构,健康检查变得尤其重要(Health Check).虽然微服务架构有很 ...

  6. 通过dotnet命令行设置asp.net core服务的启动地址

    需求: 通过dotnet命令行启动asp.net core 服务时,自定义监听端口. 方法: 在program.cs中增加命令行参数配置: WebHost.CreateDefaultBuilder(a ...

  7. Vue.js与 ASP.NET Core 服务端渲染功能整合

    http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/ 原作者:Mihály Gyöngyösi 译者:oop ...

  8. 轻量级.Net Core服务注册工具CodeDi发布啦

    为什么做这么一个工具 因为我们的系统往往时面向接口编程的,所以在开发Asp .net core项目的时候,一定会有大量大接口及其对应的实现要在ConfigureService注册到ServiceCol ...

  9. (3)ASP.NET Core 服务生命周期

    1.前言 在ConfigureServices方法中的容器注册每个应用程序的服务,Asp.Core都可以为每个应用程序提供三种服务生命周期:●Transient(暂时):每次请求都会创建一个新的实例. ...

随机推荐

  1. [atAGC022D]Shopping

    称0到$L$的方向为左,同时为了方便,可以假设$0<t_{i}\le 2L$ 当我们确定是进入店中的方向,根据这个店的位置以及购物时间,不难确定出来时火车经过0或$L$的次数,由于$0<t ...

  2. 学以致用 | Redis概念与简单实操

    Redis概念 Redis是一个由C语言编写.基于key-value存储结构的开源NoSQL数据库,其读写速度为10万次/秒,这个速度已经远远大于传统的关系型数据库. 使用场景 在高并发的情况下,可将 ...

  3. 如何删除一个win10的服务

    使用场景: 之前电脑玩腾讯qq微端游戏,后来卸载残留服务一直在后台占用系统资源.那么如何关闭这个服务呢. 1.首先 管理员运行--cmd.exe 2.打开任务管理器,找到服务名称,如果服务开启可以关闭 ...

  4. 从一个简单的Delete删数据场景谈TiDB数据库开发规范的重要性

    故事背景 前段时间上线了一个从Oracle迁移到TiDB的项目,某一天应用端反馈有一个诡异的现象,就是有张小表做全表delete的时候执行比较慢,而且有越来越慢的迹象.这个表每次删除的数据不超过20行 ...

  5. [Cnoi2020]线性生物

    期望入门题.但是我不会做. 考虑设\(E_{x\to{x+1}}\)为\(x\)到\(x+1\)点的期望步数. 则\(ans = \sum_{i = 0}^{n} E_{x\to{x+1}}\) 知\ ...

  6. Codeforces 715E - Complete the Permutations(第一类斯特林数)

    Codeforces 题面传送门 & 洛谷题面传送门 神仙题.在 AC 此题之前,此题已经在我的任务计划中躺了 5 个月的灰了. 首先考虑这个最短距离是什么东西,有点常识的人(大雾)应该知道, ...

  7. 【基因组组装】HiC挂载Juicebox纠错补充

    目录 1. 主要纠错类型 misjoins translocations inversions chromosome boundaries 2. 其他有用操作 撤销与反撤销 移到边角料 1. 主要纠错 ...

  8. 大数据学习day29-----spark09-------1. 练习: 统计店铺按月份的销售额和累计到该月的总销售额(SQL, DSL,RDD) 2. 分组topN的实现(row_number(), rank(), dense_rank()方法的区别)3. spark自定义函数-UDF

    1. 练习 数据: (1)需求1:统计有过连续3天以上销售的店铺有哪些,并且计算出连续三天以上的销售额 第一步:将每天的金额求和(同一天可能会有多个订单) SELECT sid,dt,SUM(mone ...

  9. oracle加密encrypt,解密decrypt

    目录 oracle加密encrypt,解密decrypt 加密 解密 oracle加密encrypt,解密decrypt 有的oracle版本没有加解密函数,以下操作可以手动添加 oracle数据使用 ...

  10. LoadRunner中怎么设置密码参数化与用户名关联

    对密码参数化时从parameter里的"Select next row"列表中选择Same Line As这一选项,意思就是每一个密码参数化取值与对应行的用户名关联起来了