prometheus-net.DotNetRuntime 获取 CLR 指标原理解析

prometheus-net.DotNetRuntime 介绍

Intro

前面集成 Prometheus 的文章中简单提到过,prometheus-net.DotNetRuntime 可以获取到一些 CLR 的数据,比如说 GC, ThreadPool, Contention, JIT 等指标,而这些指标可以很大程度上帮助我们解决很多问题,比如应用执行过程中是否经常发生 GC,GC 等待时间时间是否过长,是否有发生死锁或竞争锁时间过长,是否有发生线程池饿死等等一系列问题,有了这些指标我们就可以清晰的在运行时了解到这些信息。

来看一下官方介绍

A plugin for the prometheus-net package, exposing .NET core runtime metrics including:

  • Garbage collection collection frequencies and timings by generation/ type, pause timings and GC CPU consumption ratio

  • Heap size by generation

  • Bytes allocated by small/ large object heap

  • JIT compilations and JIT CPU consumption ratio

  • Thread pool size, scheduling delays and reasons for growing/ shrinking

  • Lock contention

  • Exceptions thrown, broken down by type

These metrics are essential for understanding the peformance of any non-trivial application. Even if your application is well instrumented, you're only getting half the story- what the runtime is doing completes the picture.

支持的指标

Contention Events

只要运行时使用的 System.Threading.Monitor 锁或 Native锁出现争用情况,就会引发争用事件。

一个线程等待的锁被另一线程占有时将发生争用。

NameDescriptionType
dotnet_contention_seconds_total发生锁争用的耗时(秒)总计Counter
dotnet_contention_total锁争用获得锁的数量总计Counter

Thread Pool Events

Worker thread 线程池和 IO thread 线程池信息

NameDescriptionType
dotnet_threadpool_num_threads线程池中活跃的线程数量Gauge
dotnet_threadpool_io_num_threadsIO 线程池中活跃线程数量(WindowsOnly)Gauge
dotnet_threadpool_adjustments_total线程池中线程调整总计Counter

Garbage Collection Events

Captures information pertaining to garbage collection, to help in diagnostics and debugging.

NameDescriptionType
dotnet_gc_collection_seconds执行 GC 回收过程耗费的时间(秒)Histogram
dotnet_gc_pause_secondsGC 回收造成的 Pause 耗费的时间(秒)Histogram
dotnet_gc_collection_reasons_total触发 GC 垃圾回收的原因统计Counter
dotnet_gc_cpu_ratio运行垃圾收集所花费的进程CPU时间的百分比Gauge
dotnet_gc_pause_ratio进程暂停进行垃圾收集所花费的时间百分比Gauge
dotnet_gc_heap_size_bytes当前各个 GC 堆的大小 (发生垃圾回收之后才会更新)Gauge
dotnet_gc_allocated_bytes_total大小对象堆上已分配的字节总数(每100 KB分配更新)Counter
dotnet_gc_pinned_objectspinned 对象的数量Gauge
dotnet_gc_finalization_queue_length等待 finalize 的对象数Gauge

JIT Events

NameDescriptionType
dotnet_jit_method_totalJIT编译器编译的方法总数Counter
dotnet_jit_method_seconds_totalJIT编译器中花费的总时间(秒)Counter
dotnet_jit_cpu_ratioJIT 花费的 CPU 时间Gauge

集成方式

上面的列出来的指标是我觉得比较重要的指标,还有一些 ThreadPool Scheduling 的指标和 CLR Exception 的指标我觉得意义不是特别大,有需要的可以去源码里看一看

集成的方式有两种,一种是作者提供了一个默认的 Collector 会去收集所有支持的 CLR 指标信息,另外一种则是可以自己自定义的要收集的 CLR 指标类型,来看示例:

使用默认的 Collector 收集 CLR 指标

DotNetRuntimeStatsBuilder.Default().StartCollecting();

使用自定义的 Collector 收集 CLR 指标

DotNetRuntimeStatsBuilder.Customize().WithContentionStats() // Contention event.WithGcStats() // GC 指标.WithThreadPoolStats() // ThreadPool 指标// .WithCustomCollector(null) // 你可以自己实现一个自定义的 Collector.StartCollecting();

上面提到过默认的 Collector 会收集支持的所有的 CLR 指标,且看源码怎么做的

构建了一个 Builder 通过建造者模式来构建复杂配置的收集器,类似于 .net core 里的 HostBuilder/LoggingBuilder ...,像极了 Host.CreateDefaultBuilder,做了一些变形

源码地址:https://github.com/djluck/prometheus-net.DotNetRuntime/blob/master/src/prometheus-net.DotNetRuntime/DotNetRuntimeStatsBuilder.cs

实现原理

那它是如何工作的呢,如何实现捕获 CLR 的指标的呢,下面我们就来解密一下,

在项目 README 里已经有了简单的介绍,是基于 CLR 的 ETW Events 来实现的,具体的 CLR 支持的 ETW Events 可以参考文档:https://docs.microsoft.com/en-us/dotnet/framework/performance/clr-etw-events

而 ETW Events 是通过 EventSource 的方式使得我们可以在进程外获取到进程的一些运行信息,这也是我们可以通过 PerfMonitor/PerfView 等方式进程外获取进程 CLR 信息的重要实现方式,同样的微软的新的诊断工具 dotnet diagnostic tools 的实现方式 EventPipe 也是基于 EventSOurce

EventSource 的事件不仅仅可以通过进程外的这些工具来消费,我们也可以在应用程序中实现 EventListener 来实现进程内的 EventSource 事件消费,而这就是 prometheus-net.DotNetRuntime 这个库的实现本质方法

可以参考源码:https://github.com/djluck/prometheus-net.DotNetRuntime/blob/master/src/prometheus-net.DotNetRuntime/DotNetEventListener.cs

具体的事件处理是在对应的 Collector 中:

https://github.com/djluck/prometheus-net.DotNetRuntime/tree/master/src/prometheus-net.DotNetRuntime/StatsCollectors

Metrics Samples

为了比较直观的看到这些指标可以带来的效果,分享一下我的应用中用到的一些 dashboard 截图

Lock Contention

GC

从上面的图可以清晰的看到这个时间点发生了一次垃圾回收,此时 GC Heap 的大小和 GC 垃圾回收的CPU 占用率和耗时都可以大概看的出来,对于我们运行时诊断应用程序问题会很有帮助

Thread

Thread 的信息还可以拿到一些 threadpool 线程调度的数量以及延迟,这里没有展示出来,

目前我主要关注的是线程池中线程的数量和线程池线程调整的原因,线程池线程调整的原因中有一个是 starvation,这个指标尤其需要关注一下,应避免出现 threadpool starvation 的情况,出现这个的原因通常是因为有一些不当的用法,如:Task.WaitTask.Resultawait Task.Run() 来把一个同步方法变成异步等不好的用法导致的

DiagnosticSource

除了 EventSource 之外,还有一个 DiagnosticSource 可以帮助我们诊断应用程序的性能问题,目前微软也是推荐类库中使用 DiagnosticSource 的方式来让应用诊断类库中的一些性能问题,这也是目前大多数 APM 实现的机制,Skywalking、ElasticAPM、OpenTelemetry 等都使用了 DiagnosticSource 的方式来实现应用程序的性能诊断

如果是进程外应用程序的性能诊断推荐首选 EventSource,如果是进程内推荐首选 DiagnosticSource

通常我们都应该使用 DiagnosticSource,即使想进程外捕获,也是可以做到的

关于这二者的使用,可以看一下这个 Comment https://github.com/dotnet/aspnetcore/issues/2312#issuecomment-359514074

More

除了上面列出来的那些指标还有一些指标,比如 exception,threadpool scheduling,还有当前 dotnet 的环境(系统版本,GC 类型,Runtime 版本,程序 TargetFramework,CPU 数量等),有兴趣的可以用一下试一下

exception 指标使用下来感觉帮助不大,有一些即使是已经处理的或者忽略的 Exception 也会被统计,这些 Exception 大多并不会影响应用程序的运行,如果参考这个的话可能会带来很多的困扰,所以我觉得还是需要应用程序来统计 exception 指标更为合适一些

prometheus-net.DotNetRuntime 作为 prometheus-net 的一个插件,依赖于 prometheus-net 去写 metrics 信息,也就是说 metrics 的信息可以通过 prometheus-net 来获取

集成 asp.net core 的时候和之前集成 prometheus-net 是一样的,metrics path 是同一个,可以参考我这个项目: https://github.com/OpenReservation/ReservationServer/tree/dev/OpenReservation

注意:作者推荐 .netcore3.0 以上使用,.netcore 2.x 会有一些 BUG,可以在 Issue 里看到

Reference

  • https://github.com/djluck/prometheus-net.DotNetRuntime

  • https://docs.microsoft.com/en-us/dotnet/framework/performance/clr-etw-events

  • https://github.com/dotnet/aspnetcore/issues/2312#issuecomment-359514074

  • https://github.com/OpenReservation/ReservationServer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/306494.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

错误代码1500什么意思_啊早安打工人是什么梗???

早安打工人是什么梗?最近打工人这个词成为了大家口中最为常见的一个词语,打工人的爆火也引起了很多人的关注,这样一个词语在很多人看来很有可能还有点嘲讽的含义,却突然火遍全网,究竟打工人是什么梗?看起来…

java实用教程——组件及事件处理——MouseEvent事件

MouseEvent事件 任何组件上都可以发生鼠标事件,如鼠标进入组件、退出组件、在组件上方单击鼠标、拖动鼠标等都触发鼠标事件,即导致MouseEvent类自动创建一个 事件对象,事件源注册监视器的方法是addMouseListener(MouseListener listener); …

这个世界,正在悄悄惩罚那些不注意身体的人

这是头哥侃码的第226篇原创上周四,整个网络被 “马拉多纳去世” 的消息刷屏了。虽然我从不看足球,而且没有看过马拉多纳踢球,但关于他的故事、他的传奇、他的丰功伟绩,倒是听过不少。所以在听到这个消息的时候,我感到深…

tcp拥塞控制_网络TCP的拥塞控制算法简介

作为网络中使用最广泛的传输协议,TCP的拥塞控制机制是学术界和工业界关注的焦点问题之。然而,目前广泛使用的TCP传输协议的拥塞控制算法仍然使用相对固定的窗口调节策略,无法根据动态变化的场景自适应地调整参数,从而造成不可避免…

java实用教程——组件及事件处理——对话框(消息对话框,输入对话框,确认对话框)

消息对话框:(这个对话框提供一些信息) 无模式:可多线程的执行 有模式:用户必须处理这个一个对话框。必须解决这个问题后才可以继续相处下去 对话框分为无模式和有模式两种。如果一个对话框 是有模式的对话框,那么当这个对话框处于…

11张图演进SeviceMesh服务网格

本周和大家聊聊架构进化史-大家可文末扫码加入随着互联网持续高歌猛进,相关技术名词也是层出不穷,ServiceMesh服务网格这两年尤为火爆,然而很少有讲清楚的文章。笔者这里用心整理了一篇文章,用11张图演绎ServiceMesh的进化历程&am…

java实用教程——组件及事件处理——对话框(颜色对话框,自定义对话框)

颜色对话框: 可以用javax.swing包中的JColorChooser类的静态方法 public staticColorshowDialog (Component component, String title, Color initialColor) 创建一个有模式的颜色对话框,其中参数component指定颜色对话框可见时的位置,颜色对…

.NET Core/.NET 5.0 析构函数依然有效?

【导读】最近看到小伙伴在.NET Core中用到了析构函数,不禁打一疑问,大部分情况下,即使在.NET Framework中都不会怎么用到析构函数,我想在.NET Core中是否还依然有效呢?随着时间推移,迭代版本更新&#xff0…

java实用教程——常用实用类——String类(字符串类)

JAVA把String类定义为final类(因此用户不能扩展String类,即String类不可以有子类) String对象可以用""进行并置运算 identityHashCode会返回对象的hashCode,而不管对象是否重写了hashCode方法。 public class Example8_1 {public static void…

sqlserver 事务日志 异常增长原因排查_小白入门学习打日志

前言只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y记得之前写过一篇:《阿里巴巴 Java开发手册》读后感,之前自学时由于没怎么接触过打“日志”,所以《手册》中的“日志…

在 k8s 中部署 Prometheus 和 Grafana

部署 Prometheus 和 Grafana 到 k8sIntro上次我们主要分享了 asp.net core 集成 prometheus,以及简单的 prometheus 使用,在实际在 k8s 中部署的时候就不能在使用前面讲的静态配置的方式来部署了,需要使用 Prometheus 的服务发现。部署规划Pr…

EntityFramework Core 5.0 VS SQLBulkCopy

【导读】EF Core 5.0伴随着.NET 5.0发布已有一段时日,本节我们来预估当大批量新增数据时,大概是多少区间我们应该考虑SQLBulkCopy而不是EF CoreSQLBulkCopy早出现于.NET Framework 2.0,将数据批量写入利用此类毫无疑问最佳,虽其来…

小心使用 Task.Run 续篇

关于前两天发布的文章:为什么要小心使用 Task.Run,对文中演示的示例到底会不会导致内存泄露,给很多人带来了疑惑。这点我必须向大家道歉,是我对导致内存泄漏的原因没描述和解释清楚,也没用实际的示例证实,是…

java实用教程——组件及事件处理——设置组件的位置(相对于窗口具体位置和布局)

1: 相对于窗口的具体位置 关键点: JButton组件添加到JPanel时,如果想自己位置,需要对JPanel进行如下设置,才能自定义按钮位置 需要将组件添加到画板上去,才可以设置组件的相对具体位置 button1.setBounds…

usb接口定义引脚说明_PerfDogService使用说明

令牌申请教程:https://bbs.perfdog.qq.com/article-detail.html?id55安装包下载:https://perfdog.qq.com/sdk一、 概述PerfDog性能狗服务组件,用户可基于service组件二次开发自己PerfDog性能工具或自动化服务。本文档主要对PerfDogService提…

java实用教程——组件及事件处理——布局管理(五种)

1.流式布局FlowLayout public void pack()调整此窗口的大小,以适合其子组件的首选大小和布局。如果该窗口或其所有者仍不可显示,则两者在计算首选大小之前变得可显示。在计算首选大小之后,将会验证该Window。窗口自动适应大小,使…

个人博客前端模板_腾讯前端开发工程师,教你极速搭建一个个人博客网站

作者: bookerzhao,腾讯 CSIG web前端开发工程师Github 为开源项目提供了用于静态页面展示的 Pages 服务,很多开发者都在上面托管了自己的静态网站和博客,不少开源项目的案例和文档页面也采用了这种方式。不过由于 Pages 的 CDN 节…

云原生时代 给予.NET的机会

.NET诞生于与Java的竞争,微软当年被罚款20亿美元。Java绝不仅仅是一种语言,它是COM的替代者!而COM恰恰是Windows的编程模型。而Java编程很多时候比C编程要容易的多,更致命的是他是跨平台的。微软所推行.NET战略,并且C#…

java实用教程——组件及事件处理——布局的一个小实例

import javax.swing.*; import java.awt.*;public class BasicComponentDemo {Frame frame new Frame("这里测试基本组件");//定义一个按钮Button ok new Button("确认");//定义一个复选框组CheckboxGroup cbg new CheckboxGroup();//定义一个单选框&am…

非极大值抑制_非极大值抑制(non-maximum suppression)

摘自https://blog.csdn.net/qq_38906523/article/details/80195119摘自https://blog.csdn.net/xiexu911/article/details/80609298非极大值抑制NMS在目标检测,定位等领域是一种被广泛使用的方法。对于目标具体位置定位过程,不管是使用sliding Window还是…