8

.NET Core dump 分析

 3 years ago
source link: https://beckjin.com/2021/03/08/dotnet-dump/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

服务 CPU 或 内存偶尔飙高是部署环境中经常遇到的问题,一般会采用记录日志的方式来诊断,不过有些情况靠日志可能并不能分析出个所以然,面对实在无头绪的问题也只能暂时使用重启大法先恢复。

为了尽可能精准的定位问题,掌握通过 dump 分析服务运行堆栈信息也是非常必要的,本文将分别介绍如何对 .NET Core 2.2 和 .NET Core 3.1 项目进行 dump 分析(这里只针对 Linux 下使用容器部署的方式)。

创建 dump 文件

在创建 dump 文件之前,最好先查看具体是服务中哪些线程引发的异常,然后针对特定线程进行分析,不然全扫一遍将是一件非常耗时的工作。

进入容器后,安装 htop:

apt-get update
apt-get install htop

通过 htop 查看资源使用情况:

以上是测试程序模拟的状况,可知 PID 12 是需要关注的线程

执行以下命令即可创建 dump 文件(这里以 2.2.8 为例,另外可通过 createdump --help 查看更多参数设置,容器内默认 dotnet 进程对应 pid 均为 1):

/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/createdump 1

命令执行完成后,将生成 dump 文件 /tmp/coredump.1,我们需要通过 docker cpkubectl cpcoredump.1 文件复制到主机目录下,然后下载到用于 dump 分析的机器上。

注意:在 Docker 部署模式下,createdump 命令执行需要有容器特权,所以在容器启动时需要加 --privileged = true 参数。另外 dump 文件生成需要使用较大内存,需适当调整容器内存限制参数。

.NET Core 2.2

目前大多使用 lldb 进行分析,但从零开始搭建环境实在有些折腾,不推荐。网上已有封装好的镜像可直接使用,如:6opuc/lldb-netcore6opuc/lldb-netcore 默认是基于 .NET Core SDK 2.2.8 构建的镜像,如果当前要 dump 的服务 .NET Core 版本非 2.2.8,则需要修改 lldb-netcore 源码 重新构建镜像。

执行以下命令进入 lldb:

docker run --rm -it -v /root/coredump.1:/tmp/coredump 6opuc/lldb-netcore

查看当时运行的线程:

clrthreads -live

指定需要分析的线程编号(PID 12 的线程对应的 16 进制为 c,所以找到 OSID 为 c 的记录,对应编号为 7【第一列】

thread select 7

查看当前线程在托管代码中的堆栈信息

clrstack

更多命令可通过执行 soshelp 查看

.NET Core 3.1

.NET Core 3 开始,官方已提供 dotnet-dump 工具进行 dump 分析,使用起来也相对简单,当然我们依然可以继续使用 lldb 的方式。

安装 dotnet-dump

dotnet tool install --global dotnet-dump --version 3.1.141901


dotnet-dump analyze /root/coredump.1

如果出现以下错误,说明 .NET Core SDK 没有安装到 /usr/shard/dotnet 路径下,可通过 DOTNET_ROOT 单独指定或重新安装。

查看正在运行的托管线程:

clrthreads

如果出现以下错误,是因为当前安装的 .NET Core SDK 版本与容器内 createdump 使用的 SDK 版本不一致(如:createdump 使用 3.1.3,分析使用 3.1.12)。

指定当前需要分析的线程 DBG

setthread 7

查看当前线程在托管代码中的堆栈信息

clrstack

更多 dotnet-dump 命令请查看:https://docs.microsoft.com/zh-cn/dotnet/core/diagnostics/dotnet-dump#analyze-sos-commands

以下是生产环境中遇到的一个具体案例,有一服务运行一段时间就会出现 CPU 100%,而且也降不下来,如下监控:

通过锁定异常线程后,多次 dump 并对堆栈信息进行分析,发现出问题时都和以下代码相关:

这里使用了一个表达式计算的开源组件 NCalc ,初步判断可能是表达式本身的不合法引起的循环解析,通过 dumpobj 对方法参数的查看,发现都是很正常的表达式,所以猜测并不成立。

继续在 Github 项目中的 issues 进行查找可能存在的类似问题,发现在较早版本中,确实存在卡死的现象 https://github.com/sklose/NCalc2/issues/22 ,这个问题在新版本中已修复,而我们出问题的这个服务使用的 NuGet 包确实是比较老的一个版本,所以问题基本上可以定位,在经过 NuGet 包版本升级后,这种现象终于消失了。

实际在遇到棘手问题的时候,可能经常毫无头绪,太多问题都不是那么容易定位的。在构建服务支持业务能力的同时,要注意代码本身的健壮性,在使用外部组件时,需要多关注其生态情况,dump 分析只是一种协助解决问题的手段。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK