使用 dotnet-counters 观测升讯威客服系统内存占用情况和数据吞吐性能

我是一个独立开发者,已经持续多年开发维护一款自己的产品:升讯威在线客服与营销系统。

在最近给一个大客户制作技术方案时,客户提出了一个要求:对他们已经部署测试运行的环境,分析其运行性能数据,并制作分析报告。

在客户提出这个要求的时候,我还有点犯难,因为没有提前准备,对一个已经运行了一个多月的环境,不停机,直接抽取真实内存数据进行性能分析,该怎么做呢?

经过一番调研,我找到了 dotnet-counters 这个工具。

什么是 dotnet-counters

dotnet-counters 是 .NET Core 3.0 及更高版本引入的一款性能监视命令行工具 ,专用于进行初级健康检查和性能监控。它可以实时观察应用程序的各项指标(Counters),而不会对运行中的程序造成明显的性能衰减。

核心功能与特点

  • 实时监控: 能够以类似 Linux top 命令的交互式界面,实时刷新并显示应用程序的各项性能指标。
  • 低开销: 它是基于 .NET Runtime 的 EventPipe 机制实现的,相比于传统的 Profiler,它的运行开销极低,非常适合在生产环境中直接使用。
  • 跨平台: 完美支持 Windows、Linux 和 macOS。
  • 无需重构代码: 你不需要在代码中引入任何特定 SDK,只要程序正在运行,就能通过进程 ID(PID)或名称直接挂载(Attach)上去。
  • 支持持久化: 除了实时看屏幕,它还能将数据导出为 CSV 或 JSON 格式,方便后续进行离线分析或绘制图表。

如何用它分析升讯威客服系统性能指标

在监控之前,我们找到升讯威客服系统的进程 ID。

bash 复制代码
dotnet-counters ps

输出会列出当前机器上所有正在运行的 .NET 进程及其 PID。

然后我们使用 monitor 命令,这是最常用的命令。默认情况下,它会监控 CPU、内存、GC、线程池等核心指标。

bash 复制代码
# 通过 PID 监控
dotnet-counters monitor -p 12345

# 或者通过进程名称监控
dotnet-counters monitor --name MyWebApi

如果你觉得默认指标不够用(比如你想看 ASP.NET Core 的 HTTP 请求速率,或者 Entity Framework Core 的查询效率),可以指定 providers

bash 复制代码
dotnet-counters monitor -p 12345 --providers Microsoft.AspNetCore.Hosting System.Runtime

.NET 内置了多个 Provider,能让你一眼看穿程序的底层运行状态:

提供者 (Provider) 核心监控指标举例 适用场景
System.Runtime CPU 使用率、GC 堆大小、线程池线程数、异常引发率(Exception Count) 检查内存泄漏、CPU 飙高、死锁或频繁抛异常
Microsoft.AspNetCore.Hosting 每秒请求数 (RPS)、当前并发请求数、请求总耗时 评估 Web 服务的吞吐量与响应延迟
Microsoft-Extensions-DependencyInjection 锁定的范围(Scope)数量、已创建的单例数量 排查依赖注入导致的内存问题

看看升讯威客服系统的直接性能指标

通过以上工具命令,我们就拿到了升讯威客服系统在客户现场跑了一个多月下来的真实性能指标。

我们请 AI 来分析

光有这份指标还不够,我们需要解读它,我自说自话给客户看,肯定没有足够的说服力,我们请 AI 来解读。


这份 dotnet-counters 的快照数据反映了一个高并发、高负载,但目前运行状态极其健康、平稳的 .NET 应用场景。

通过对各项指标的交叉对比,我为你梳理出以下的核心评估与分析结果:

核心指标深度评估

1. 内存与 GC 状态:典型的"老生代积压"或"缓存驱动"型应用

  • GC Heap Size (521.17 MB) vs Working Set (1,174.03 MB)

  • 分析:实际物理内存(Working Set)超过了 1.1 GB,而 .NET 托管堆内存只有约 521 MB。这意味着有接近 650 MB 的内存被非托管资源、代码映像(JIT 编译产物)或元数据占用。

  • Gen 2 Size (约 389.57 MB)

  • 分析:在 521 MB 的堆内存中,Gen 2(老生代)占了接近 75%(3.8957 \\times 10\^8 字节)。

  • 评估:Gen 0 的当前大小为 0,这说明绝大多数存活的对象都是长期对象。这非常符合长期驻留的内存缓存、全局静态对象、或者是维持着大量长连接(如 WebSocket/SignalR 访客端、客服端工作区会话)的系统特征。

GC 效率极高

  • % Time in GCTime paused by GC 均为 0
  • Allocation Rate 约为 10.3 MB/s
  • 评估:每秒 10.3 MB 的分配速率并不算低,但 Gen 0 GC Count 为 0,Gen 0 的预算(Budget)有 93 MB。这意味着当前的分配速度完全在 .NET GC 的承受范围内,甚至还没触发任何一次临时的垃圾回收,系统运行极其流畅。

2. 线程池与并发能力:极高的数据吞吐量

  • ThreadPool Completed Work Item Count (3,311 / 1 sec)

  • 评估:这是一组非常惊人的数据。线程池每秒钟能够处理并完成 3,311 个工作项,说明系统正处于极高频的异步 I/O 或任务调度状态。

  • ThreadPool Thread Count (7) & Queue Length (0)

  • 评估:在每秒处理 3,311 个任务的高压下,线程池居然只用了 7 个线程,且队列长度为 0!这证明代码的异步化(async/await)做得非常彻底,没有任何阻塞线程(Block)的骚操作。任务随到随处理,线程利用率达到了完美的教科书级别。



如果您感兴趣:

升讯威客服系统仍处于不断演进的过程中。

如果您曾经构建或部署过实时聊天系统,我非常期待与您交流心得。

无论您倾向于使用托管版还是自行部署(Self-hosting),都可以免费使用。