APM是一种应用性能监控工具,可以帮助理解系统行为, 用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题, 通过汇聚业务系统各处理环节的实时数据,分析业务系统各事务处理的交易路径和处理时间,实现对应用的全链路性能监测。

组成结构

  • 探针(Agent):负责在客户端程序运行时搜索服务调用链路信息,发送给收集器
  • 收集器(Collector):负责将数据格式化,保存到存储器
  • 存储器(Storage):保存程序数据
  • UI界面(Dashboard):多维度展示数据

本文会主要针对 探针 (Agent), 分享下在.NET 程序中收集程序数据的几种方式,如果需要自研 APM 系统或者收集数据来进行系统分析,希望能可以给大家一些帮助,以下几种方式,大家可以针对自己的场景去选择,我们的目的只是收集数据。

手动埋点

手动埋点比较简单,我们需要在一些操作前后可以手动包裹我们的埋点代码,比如 Http,RPC,DB, MQ 等调用,非常灵活,可以在任意的地方添加我们的埋点信息,然后汇总数据,按批发送,缺点是对程序的侵入性较高,不太优雅。

Middleware 中间件 & 过滤器 Filter

得益于 .NET Core 优秀的框架设计, 它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求。ASP. NET Core应用的很多特性,比如路由、认证、会话、缓存等,也同时定制消息处理管道来实现的,所以我们需要编写自定义的拦截中间件 InterceptMiddleware,获取到请求上下文 HttpContext, 来拦截所有的Http请求收集数据,注意这里中间件的位置要放到 UseEndpoints() 的上面,同样可以借助 过滤器 AcitonFilter,来完成同样的效果, 但是这种方式可获取的信息有限,只能拦截到 Http 请求的一些信息

DiagnosticSource

实现:

SkyApm-dotnet https://github.com/SkyAPM/SkyAPM-dotnet

HttpReports APM https://github.com/dotnetcore/HttpReports

诊断 DiagnosticSource 我们不经常用,可能都有点陌生,但是它的功能是非常强大的,它本身是一个基于发布订阅模式的工作模式,我们可以异步的去收集信息,比如 中间件的进入和退出,HttpClient 调用的开始和结束,并且有很多第三方的库都支持了 DiagnosticSource,这也是微软目前推荐的方式,在改动极少代码的情况下,采集到丰富的运行数据。

引用 AOP

额,面向切面编程,这个需要在我们的 .NET 程序中引用 AOP 框架,如果是内部系统的话,我觉的还是可以接受的,常见的框架 AspectCore, Castle.Core, 通过 AOP 的特性,我们可以拦截需要获取数据的方法,如果你在项目中,普遍使用依赖注入的话,可以达到方法级别的监控,获取到的信息非常可观,另外需要注意的是,获取的信息越详细,数据量也越大,是全量采集数据还是抽样采集也是要考虑的点

EWT(Event Tracing for Windows)

ETW是Event Tracing for Windows的简称,它是Windows提供的原生的事件跟踪日志系统。由于采用内核(Kernel)层面的缓冲和日志记录机制,所以ETW提供了一种非常高效的事件跟踪日志解决方案。

这个库我还没怎么用过,生而为人,我很抱歉 〒▽〒

Mono.Cecil

Mono.Cecil:一个可加载并浏览现有程序集并进行动态修改并保存的.NET框架, Mono Cecil十分强大,可以静态注入程序集(注入后生成新的dll程序集)和动态注入程序集(注入后不改变目标程序集,只在运行时改变程序集行为,腾讯开源的Unity热更解决方案xLua有一个非常吸引人的特性就是Hotfix,其原理是使用Mono.Cecil库对进行C#层编译出来的dll程序集进行IL代码注入。

CLR Profiling API

实现

听云APM(商业)OneAPM (商业)Datadog (商业)

https://docs.microsoft.com/en-us/archive/blogs/yirutang/clr-profiling-api

这个真的是一个很棒的方案,你可以看到,很多的 商业APM 系统,都采用了这种方式,因为它是一种无侵入的收集方式,CLR Profiling (分析) API 是CLR中最酷的东西之一, 分析 API 提供 CLR 中发生的各种事件和操作的相关信息, 你可以使用此信息来监视进程的内部工作情况,也可分析 .NET 应用程序的性能

支持的功能如下:

  • CLR 启动和关闭事件。
  • 应用程序域创建和关闭事件。
  • 程序集加载和卸载事件。
  • 模块加载和卸载事件。
  • COM vtable 创建和析构事件。
  • 实时 (JIT) 编译和代码间距调整事件。
  • 类加载和卸载事件。
  • 线程创建和析构事件。
  • 函数入口和退出事件。
  • 异常。
  • 托管和非托管代码执行之间的转换。
  • 不同运行时上下文之间的转换。
  • 有关运行时挂起的信息。
  • 有关运行时内存堆和垃圾回收活动的信息。

这可能要求你掌握 C++ 和 C#, 另外需要注意的是,Profiler 是一个非托管的 DLL 库,会在应用运行时被加载到 CLR 中并与应用处于同一进程空间下,所以 Profiler DLL 实质上是不受托管代码的访问控制的,还有,Profiler DLL 作为 CLR 的一个插件,其运行错误可能会引起 CLR 本身的崩溃,所以你必须要知道这些风险,并且足够小心,最后祝你好运

另外

HttpReports 是针对.Net Core 开发的APM系统, 基于MIT开源协议,针对于微服务场景,感兴趣的同学可以点个 Star 支持下,谢谢, 我们

Github:https://github.com/dotnetcore/HttpReports

在.NET Core 中收集数据的几种方式的更多相关文章

  1. sql server中备份数据的几种方式

    当我们在写sql脚本要对数据表中的数据进行修改的时候,为了防止破坏数据,通常在开发前都会对数据表的数据进行备份,当我们sql脚本开发并测试完成后,再把数据恢复回来. 目前备份数据,我常用的方法有以下几 ...

  2. Solr 16 - 增删改Solr中索引数据的几种方式 (在URL上或Web页面中操作)

    目录 1 添加/更新索引数据 1.1 JSON格式的操作 1.2 XML格式的操作 2 删除索引数据 2.1 删除符合特定条件的数据 2.2 删除指定ID的数据 2.3 删除全部索引数据 3 在doc ...

  3. Android中查看SQLite中字段数据的两种方式

    方式一:ADB Pull 通过adb pull导出*.db文件到PC的文件夹中,通过可视化工具 SQLiteExpertPers 进行查看.编辑: adb pull /data/data/com.jo ...

  4. spark sql中保存数据的几种方式

    从官网来copy过来的几种模式描述: Scala/Java Python Meaning SaveMode.ErrorIfExists(default) "error"(defau ...

  5. ACTION中获得数据的几种方式

    1.第一种是通过公司封装的方法. 2.第二种:是通过IF方法判断 3.第三种是通过:set/get获得

  6. Day20-单表中获取表单数据的3种方式

    1. 搭建环境请参考:http://www.cnblogs.com/momo8238/p/7508677.html 2. 创建表结构 models.py from django.db import m ...

  7. Solr 删除数据的几种方式

    原文出处:http://blog.chenlb.com/2010/03/solr-delete-data.html 有时候需要删除 Solr 中的数据(特别是不重做索引的系统中,在重做索引期间).删除 ...

  8. 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)

    原文地址:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF 6 Code-F ...

  9. 文章翻译:ABP如何在EF core中添加数据过滤器

    原文地址:https://aspnetboilerplate.com/Pages/Documents/Articles%5CHow-To%5Cadd-custom-data-filter-ef-cor ...

随机推荐

  1. 牛客编程巅峰赛S2第4场

    牛客编程巅峰赛S2第4场 牛牛摆玩偶 题目描述 牛牛有\(n(2 \leq n \leq 10^5)(2≤n≤105)\)个玩偶,牛牛打算把这n个玩偶摆在桌子上,桌子的形状的长条形的,可以看做一维数轴 ...

  2. equals的推荐写法

    我们在重写equals的时候必须满足几个原则,否则,类在容器和其他场景下会出现奇怪的行为: 1.A.equals(A)=true, 2.对称性.即A.equals(B)=true;则B.equals( ...

  3. dubbo 扩展点里自动包装

    在看protrocol扩展点时,发现很费解的一点:当前invoker的url是register协议,在export的时候都会从qos->lister->filer这3个包装类开始,看了一下 ...

  4. 论如何优雅的抛出SpringBoot注解的异常

    平时我们在写代码的时候肯定要进行很多参数验证,最开始的时候我们一般都是这样处理的  如下图   看起来好像也没什么,但是  如果参数多了呢?你就会看到这样的校验 OMG!!!  有没有感觉稍微有点视觉 ...

  5. JVM 堆中对象分配、布局和访问

    本文摘自深入理解 Java 虚拟机第三版 对象的创建 Java 是一门面向对象的语言,Java 程序运行过程中无时无刻都有对象被创建出来.从语言层面看,创建对象只是一个 new 关键字而已,而在虚拟机 ...

  6. 「刷题笔记」AC自动机

    自动AC机 Keywords Research 板子题,同luoguP3808,不过是多测. 然后多测不清空,\(MLE\)两行泪. 板子放一下 #include<bits/stdc++.h&g ...

  7. shiro利用过期时间,解决用户冻结踢出问题

    背景 shiro中需要冻结某个用户,但是此时此刻这个用户在线,如果冻结只是改变状态的话,只会导致用户不满,所以要改变这个办法. 在查找过程中发现都是告诉shiro写自定义过滤器,那么我如果自定义过滤器 ...

  8. 第7.22节 Python中使用super调用父类的方法

    第7.22节 Python中使用super调用父类的方法 前面章节很多地方都引入了super方法,这个方法就是访问超类这个类对象的.由于super方法的特殊性,本节单独谈一谈super方法. 一.su ...

  9. 第12.4节 Python伪随机数数生成器random模块导览

    random模块实现了各种分布的伪随机数生成器,常用功能包括: random.seed(a=None, version=2):初始化随机数生成器,如果 a 被省略或为 None ,则使用当前系统时间. ...

  10. APP非功能测试

    1.移动APP启动时间测试 问题:如何获取启动时间? 答:通过adb的logcat来获取Activity启动时间.用户体验时间=Activity启动时间+启动中异步UI绘制的时间. 启动时间的测试主要 ...