使用Elastic APM监控你的.NET Core应用

前言

在应用实际的运维过程中,我们需要更多的日志和监控来让我们对自己的应用程序的运行状况有一个全方位的了解。然而对于大部分开发者而言,平时大家所关注的更多的是如何更优雅的实现业务,或者是如何让应用的响应速度更快等等与编码相关的技术,对于应用程序的监控,可能还停留在日志文件的层面,而且大多数是出了事故被人为发现后,才通过日志尝试去定位问题。

本文所准备介绍的Elastic APM是一套用于监控应用各项指标,比如系统响应时间、异常、EF执行的SQL记录等等,并且可以将这些记录组织成一个可追溯的链路,方便查询问题。此外,Elastic APM还可以通过Kibana来做非常漂亮的可视化展示,方便我们定位和发现问题。

废话不再多说,我们开始实战~Elastic APM介绍

Elastic APM的由下面四个组件所组成,如下图:

640?wx_fmt=png

APM Agent

APM Agent是安装到你的.NET Core程序中的一个Nuget包,他用于性能、错误等各类数据的收集,并将收集到的数据缓存起来分批发送到APM Server。当然,除了.NET Core使用的Nuget包,他还可以支持很多其他的语言,比如Java,Node.Js,Python等

支持的语言列表请参考这里:https://www.elastic.co/guide/en/apm/agent/index.html

APM Server

APM Server是部署在服务器端的一个用于接收Agent发来的数据包的应用程序,并根据这些数据包自动创建文档,将数据转存到Elastic Server中。

Elastic Search

这个相信大家都很熟悉了,他就是一个基于Lucene实现的高性能、分布式的全文搜索引擎,用于快速、实时的存储、搜索和分析大量数据。在这里来说,他提供的是数据存储和搜索能力!

Kibana

如果你熟悉Elastic Search,那么你一定多少会了解Kibana,Kibana是开源的分析和可视化平台,他能与Elastic Search进行很好的协同,帮助你快速的可视化存储在Elastic Search中的数据,并做成各种各样漂亮的报表、图形等。

环境准备

在本次的实战过程中,我们需要以下的东西:

  • Elastic Search

  • Kibana

  • APM Server

  • 一个基于.NET Standard 2.0 + 的项目

Elastic Search的安装:https://www.cnblogs.com/baiyunchen/p/11227144.html

Kibana的安装:

我的环境是Centos 7,所以照着https://www.elastic.co/guide/en/kibana/7.3/rpm.html 这个官网教程安装的,整个过程很简单:

  • 下载Kibana RPM包(采用这种方式是因为用yum install网速太慢,所以我用迅雷下载完成rpm文件后上传到Linux机器中)

  • 执行命令rpm --install  “下载的文件名” 进行安装

  • 安装完成后,到/etc/kibana/kibana.yml文件中在文件末尾增加以下配置:

1

2

3

4

5

server.host: 0.0.0.0

server.name: 主机IP

server.port: 一个你喜欢的端口号

elasticsearch.hosts: ["已安装好的ES地址,多个之间用逗号隔开"]

logging.dest: /var/log/kibana.log

  • 将Kibana安装为系统服务并启动

1

2

3

4

sudo /bin/systemctl daemon-reload

sudo /bin/systemctl enable kibana.service

sudo systemctl start kibana.service

这里大家一定要注意Elastic Search的版本和Kibana一定要匹配,不然会报错的。(我的ES是前段时间装的,所以会有这问题,如果大家一口气安装所有的,应该没啥问题)

如果不幸遇到了问题,可以通过配置文件中logging.dest中配置的路径查看日志。

APM Server的安装

APM Server的安装跟Kibana的安装类似,过程如下:

  • 下载RPM包,包在这个页面找你需要的版本,也需要跟ES、Kibana的版本一致,不然你懂得~ https://www.elastic.co/cn/downloads/past-releases#apm-server

  • 执行rpm --install “下载的文件名”进行安装

  • 在文件夹/etc/amp-server中修改配置文件apm-server.yml,将配置文件最开始的host: “localhost:8200”修改成“0.0.0.0:8200”,以便让他能允许通过ip:端口号的方式访问, 并在配置的最后面添加如下配置:

1

2

output.elasticsearch:

    hosts: ["已安装好的ES地址,多个之间用逗号隔开"]

  • 将apm-server安装为系统服务并启动

1

2

3

4

sudo /bin/systemctl daemon-reload

sudo /bin/systemctl enable apm-server.service

sudo systemctl start apm-server.service

执行上述操作完成后,在浏览器中尝试打开服务器Ip:8200,最终如果APM Server安装的没有问题,则浏览器中会打印出类似于如下的内容:

1

2

3

4

5

{

  "build_date": "2019-06-20T14:39:23Z",

  "build_sha": "9a099b63c53eac8c55707df96193143ec66337e9",

  "version": "7.2.0"

}

此时我们在浏览器中打开Kibana,然后点击Add APM

640?wx_fmt=png

然后将新打开的页面往下滚动,点击Check APM Server Status按钮,如果出现You have correctly setup APM Server则说明安装完成~

640?wx_fmt=png

到这里为止,我们的安装工作就全部完成了,接下来,我们尝试将.NET Core与Elastic APM集成起来,一起继续吧~

.NET Core 应用集成

我们创建一个Demo项目,来用于测试APM的各项功能。

项目的地址请参考GitHub:

引用依赖包

我们需要从Nuget引用相关的SDK来与我们的应用做集成,其实就是引用我们最开始说的APM Agent的部分,在Nuget中,我们引用Elastic.Apm.NetCoreAll这个包。

依赖这个包其实相当于自动依赖了如下三个包,你也可以根据需要只依赖其中的一部分。

  • Elastic.Apm

  • Elastic.Apm.AspNetCore

  • Elastic.Apm.EntityFrameworkCore

这里我们为了简单起见,直接印用Elastic.Apm.NetCoreAll这个包

将Agent添加到.NET Core

找到.NET Core的StartUp文件,在里面的Configure方法中添加如下代码:

1

2

3

4

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{

    app.UseAllElasticApm(Configuration);

}

然后在application.json中添加如下内容:

1

2

3

4

5

6

{

  "ElasticApm": {

    "LogLevel": "Error",

    "ServiceName" : "MyApp",

  }

}

此时我们将项目启动起来,随便的刷新几下,然后回到Kibana中,在刚才的页面中往下滚动,选择.NET,然后点击Check Agent Status按钮,如果顺利,就会显示“Data successfully received from one or more agents”,如果不幸没能显示这句话,可以通过VS的Diagnostic Tools中的Event跟踪一下,看看是不是哪里没有配置对

640?wx_fmt=png

 640?wx_fmt=png

监控数据查看

在Kibana的Add APM页面的最下方,找到Load Kibana Objects,来创建索引,然后点击APM dashboard按钮,就可以进入APM数据的查看页面。

640?wx_fmt=png 

点击APM Dashboard按钮后,展示的页面如下:

640?wx_fmt=png

该页面中的功能分为Services、Traces两个大的功能模块,先来简单了解一下这两个Tab页中对应的功能。

Services

下面的列表中显示的XianDotnetCommunity其实就是你在配置文件中配置的ServiceName,点击这个名字进入,又可以看到如下的报表,里面有Transactions,Errors,Metrics三个Tab页。

640?wx_fmt=png

 640?wx_fmt=png

 640?wx_fmt=png

其中

Transactions:展示的当前应用请求情况的概览,包括请求响应时长、请求调用次数等等

Errors:程序中的异常列表

Metrics:应用程序所在机器的CPU/内存使用情况

PS:其实我觉得非常需要一个当前应用程序所消耗的内存和CPU的值,但是貌似.NET Core版本的代理没有实现这些功能,期待未来的更新吧

Traces

里面是用于做链路追踪的视图,首页包含所有事务的名称列表以及响应时间等

640?wx_fmt=png

点击具体的事务进去,可以看到这个事务经过的链路列表以及更详细的一些响应信息,从而帮你分析出整个链路中的瓶颈,更多内容我们在下面细讲。

640?wx_fmt=png

探索更多

Elastic APM还有很多其他的功能,比如链路追踪、数据库调用执行,让我们来一起探索吧~API调用链路追踪

如果你了解过微服务架构,那你一定了解链路追踪这个概念。那什么是链路追踪呢?举个栗子:

有个服务A,他会依赖服务B,C,而服务B又会依赖服务D,E,服务C又依赖F,G(省略无数依赖关系),然后有一天,服务A变得非常慢,那到底该怎么定位是哪个服务慢呢?此时链路最终就派上用场了~

我们来简单模拟一下这种嵌套的调用:

在一个WebAPI项目Demo1中有一个ConsumerController,他里面有一个API A,里面调用了另外一个WEB API项目Demo2中的接口B/C/D/E。代码大致如下:

项目甲:


[Route("api/consumer")]

[ApiController]

public class ConsumerController : ControllerBase

{

    private readonly IHttpClientFactory _httpClientFactory;

    public ConsumerController(IHttpClientFactory httpClientFactory)

    {

        _httpClientFactory = httpClientFactory;

    }

    private const string baseUri = "http://localhost:54597";

    [HttpGet("a")]

    public async Task<string> A()

    {

        var client = _httpClientFactory.CreateClient();

        Thread.Sleep(new Random().Next(1, 1500));

        var b = await client.GetStringAsync($"{baseUri}/api/data-source/b");

        var c = await client.GetStringAsync($"{baseUri}/api/data-source/c");

        var d = await client.GetStringAsync($"{baseUri}/api/data-source/d");

        var e = await client.GetStringAsync($"{baseUri}/api/data-source/e");

        return $"b={b} & c={c} & d={d} & e={e}";

    }

}

项目乙:


[Route("api/data-source")]

[ApiController]

public class DataSourceController : ControllerBase

{

    [HttpGet("b")]

    public async Task<string> B()

    {

        Thread.Sleep(new Random().Next(1, 1500));

        return "B";

    }

    [HttpGet("c")]

    public async Task<string> C()

    {

        Thread.Sleep(new Random().Next(1, 1500));

        return "C";

    }

    [HttpGet("d")]

    public async Task<string> D()

    {

        Thread.Sleep(new Random().Next(1, 1500));

        return "D";

    }

    [HttpGet("e")]

    public async Task<string> E()

    {

        Thread.Sleep(new Random().Next(1, 1500));

        return "E";

    }

}

此时我们请求Demo1中的API A (xxx/api/consumer/a),然后在Kibana中打开APM中的Traces,找到”GET Consumer/A” 这条记录(看起来默认是根据Controller的名字+Action的名字命名的),然后点击查看详情。

640?wx_fmt=png

在详情中的最下方,我们找到TimeLine,可以看到如下图所示的图形:

640?wx_fmt=png

我们可以看到我们在请求API A时的时间分别花费在调用4个API中的时间,也可以看出调用第三个API花费的时间更长,点击蓝色的条可以看到请求的详细信息。

这里不太好的一点是默认显示的名字是GET localhost这样的,其实我们更期望的是显示成调用的api uri对吧?这个我提了一个pr给他们,大家可以关注下:https://github.com/elastic/apm-agent-dotnet/pull/463监控EF执行记录

这个不需要过多的解释,就是在EF执行DB操作时,进行监控,以便发现性能等问题,我的代码大致如下:


[HttpGet("person")]

public void TestEfCore()

{

    using (var db = new ApmDbContext())

    {

        var jax = new Person

        {

            Name = "西安.NET社区",

            Age = 26,

            Remark = "做最好的技术社区~"

        };

        db.Persons.Add(jax);

        db.SaveChanges();

        db.Persons.FirstOrDefault(x => x.Id == jax.Id );

        db.Persons.FirstOrDefault(x => x.Name == "西安.NET社区");

        jax.Name = ".NET西安社区";

        db.SaveChanges();

        db.Persons.Remove(jax);

        db.SaveChanges();

    }

}

当我们使用Kibana查看这次请求时,TimeLine显示如下:

640?wx_fmt=png

我们可以比较清晰直观的看到在这次请求中,执行了哪些SQL语句,各耗时多少,对我们的请求分析来说,还是蛮有用处的。点击具体的蓝条,还可以看到更详细的数据,但比较遗憾的是,数据中并没有记录SQL Params ,这对于我们想完全重现这次请求来说,还是不够友好~

640?wx_fmt=png

自行埋点记录

相对来说,Elastic APM目前生态圈还不够好,比sky walking还是稍微差一些组件的支持,如果要使用Elastic APM,免不了自己去做一些性能数据的埋点记录,或者在为第三方组件、类库做支持时,也需要做一些数据的埋点。接下来我们就在我们的请求中,埋一些我们想额外记录的信息,示例代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

[HttpGet]

public void RecordMyApmData()

{

    var transaction = Agent.Tracer.CurrentTransaction;

    var span1 = transaction.StartSpan("Stage 1", "Customize");

    Thread.Sleep(300);

    span1.End();

    Thread.Sleep(200);

    var span2 = transaction.StartSpan("Stage 2", "Customize");

    Thread.Sleep(100);

    span2.End();           

    Thread.Sleep(100);

    var span3 = transaction.StartSpan("Stage 3", "Customize");

    Thread.Sleep(500);

    span3.End();           

}

最终记录的效果如下:

640?wx_fmt=png

这个Demo虽然写的很简单,但是我相信你已经能大概脑补如何使用Elastic Apm Agent这个类去自定义自己需要捕捉的一些监控数据了~

异常监控

当我们的程序发生了异常时,Elastic APM能帮助你记录,这个功能和日志差不多,但可能比日志稍微好用那么一点点。我们一起来看看吧~

示例代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

[HttpGet]

public void TestException()

{

    try

    {

        throw new Exception("捕获的异常");

    }

    catch (Exception)

    {

    }

    throw new Exception("未捕获的异常");

}

执行代码后,我们可以通过点击Service Name,然后在Errors这个Tab页中查看到这次的异常

640?wx_fmt=png

点击详情,我们能看到详细的堆栈调用信息:

640?wx_fmt=png

此外,我们可以在Trasactions Tab中,找到发生异常的这个请求,然后点击查看详情,在详情中我们也能看到这次异常的发生:

640?wx_fmt=png

总结

本文介绍了如何使用Elastic APM在.NET Core应用中收集性能和异常数据,并使用Kibana进行可视化分析,整体来说,Elastic APM还是挺强大的,对于性能监控、链路追踪、异常监控基本是够用了。

目前来说,Elastic APM 支持的组件还是比较有限,比如对数据库查询还只是支持EF Core,并不支持更多的组件,链路追踪也仅支持HTTP请求的追踪,也没用支持其他的方式。另外,个人认为Elastic APM把监控报警(Watcher) 给放到X-Pack收费包中也是挺让人伤心的,异常监控报警其实还是蛮关键的。

欢迎大家尝试Elastic APM,有问题的地方共同探讨~

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

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

相关文章

ASP.NET Core结合Nacos来完成配置管理和服务发现

前言今年4月份的时候&#xff0c;和平台组的同事一起调研了一下Nacos&#xff0c;也就在那个时候写了.net core版本的非官方版的SDK。虽然公司内部由于某些原因最后没有真正的用起来&#xff0c;但很多人还是挺看好的。在和镇汐大大沟通后&#xff0c;决定写一篇博客简单介绍一…

Java 时间处理

时区、冬令时和夏令时、时间戳 时间戳 距离一个标准参照时间经过的秒数&#xff08;毫秒数&#xff09; 有两个常用参照时间&#xff1a; 1970-01-01 00:00:00 应用最广泛的时间戳参照点2001-01-01 00:00:00 常被苹果系统使用 注意&#xff1a;以上时间节点皆采用UTC的标准时…

试试这个Excel知识测验,得分超过80分算你赢

大家可能都知道&#xff0c;全世界使用Excel的用户超过了10亿。Excel的知识真所谓是博大精深&#xff0c;并且还很有趣味。我最近编写了一个Excel小工具&#xff0c;可以让大家可以在Excel里面进行各种知识小测验&#xff0c;并且与全世界的高手一比高低。这个小工具&#xff0…

自学架构设计?帮你总结了 4 个方法

从编程思维到架构思维的升级&#xff0c;是工作 3、5 年的程序员遇到的第一个槛&#xff0c;特别是当你准备晋升考核时。我有个哥们&#xff0c;技术和业务都很不错&#xff0c;腾讯 T2.3 升 T3.1&#xff0c;就卡在了架构设计这部分。架构这个事儿&#xff0c;不像算法和代码&…

.NET Core 3.0及ASP.NET Core 3.0 前瞻

前几天微软发布了 .NET Core 3.0 Preview 9 &#xff0c;这是.NET Core 3.0 最后一个预览版。[翻译] .NET Core 3.0 Preview 9 发布.NET Core 3.0 正式发布将在.NET Conf 上发布&#xff0c;.NET Conf 时间是9月23日至25日。Visual Studio 2019 16.3预览版3和Visual Studio for…

有了Unicode为啥还需要UTF-8

有了Unicode为啥还需要UTF-8 要回答这个问题&#xff0c;需要吃透“编码”的概念&#xff0c;刚好看到大神阮一峰写的文章&#xff1a;字符编码笔记&#xff1a;ASCII&#xff0c;Unicode 和 UTF-8 抄录如下&#xff0c;便于查找&#xff1a; 一、ASCII 码 我们知道&#xf…

升职却不加薪,为什么我还觉得老板说的挺有道理

前几天晚上&#xff0c;DevOps交流群里&#xff0c;有人抛出这样一个观点&#xff1a;如果有人来找我加薪&#xff0c;我一定告诉他我要给他升职&#xff0c;因为升职是免费的&#xff0c;加薪可是真的要花钱。但是我也会许诺他&#xff0c;如果他能把那个团队搞好&#xff0c;…

细节之中自有天地,整洁成就卓越代码

溪源 | 长沙.NET技术社区开篇我们总是很容易就能写出满足某个特定功能的代码&#xff0c;却很难写出优雅代码。又最欣赏那些优雅的代码&#xff0c;因为优雅代码更能体现一个开发者的积累。就像写一篇散文&#xff0c;有的就像初学者不得其门而入&#xff0c;遣词造句都非常困难…

一次业务网关用ASP.NET Core 2.1重构的小结

前言对于API网关&#xff0c;业界貌似对它进行下划分&#xff0c;有下面几个分类/场景。面向Web App面向Mobile App面向Partner OpenAPI面向Partner ExternalAPI其他。。。在18年8月份的时候&#xff0c;有幸用.NET Core 2.1重构了一个对外的业务网关项目&#xff0c;这个项目的…

推荐几个华为,字节跳动、蚂蚁金服等大佬的公众号

每一个公众号都是一个特色的图书馆&#xff0c;为我们的学习提供优质的服务&#xff0c;珍贵的资源&#xff0c;耐心看完&#xff0c;认真选择适合自己的良师益友吧。Python爱好者社区Python爱好者社区&#xff0c;这里有分类整理好的历史优秀文章数千篇供你学习&#xff0c;内…

使用Ingress来负载分发微服务

目录 使用Ingress来负载分发微服务 Demo规划 准备Demo并完成部署 创建部署&#xff08;Deployment&#xff09;资源 创建服务&#xff08;Service&#xff09;资源 创建Ingress资源并配置转发规则 使用Ingress来负载分发微服务NodePort Service存在太多缺陷&#xff0c;不适合…

并发和并行及多线程基本概念

并发&#xff08;Concurrent&#xff09; 在操作系统中&#xff0c;是指一个时间段中有几个程序都处于已启动运行到运行完毕之间&#xff0c;且这几个程序都是在同一个处理机上运行&#xff0c;但任一个时刻点上只有一个程序在处理机上运行。 并发&#xff0c;本质上是一个物理…

XUnit 依赖注入

XUnit 依赖注入Intro现在的开发中越来越看重依赖注入的思想&#xff0c;微软的 Asp.Net Core 框架更是天然集成了依赖注入&#xff0c;那么在单元测试中如何使用依赖注入呢&#xff1f;本文主要介绍如何通过 XUnit 来实现依赖注入&#xff0c; XUnit 主要借助 SharedContext 来…

程序员自家种水果,新鲜包邮配送!

点击上面“蓝字”关注我们&#xff01;上次猕猴桃的活动一经推出&#xff0c;得到了广大粉丝的支持&#xff0c;我感到十分欣慰&#xff0c;非常感谢大家对我的信任。好多小伙伴&#xff0c;买了一箱尝过后又下单了好几箱。事实证明&#xff0c;品质才是销量的最佳保证。有些粉…

实现一个简单的基于码云(Gitee) 的 Storage

实现一个简单的基于码云(Gitee) 的 StorageIntro上次在 asp.net core 从单机到集群 一文中提到存储还不支持分布式&#xff0c;并立了一个 flag基于 github 或者 开源中国的码云实现一个 storage于是这两天就来填坑了。。实现了一个简单的基于开源中国的码云的 storage准备工作…

Java线程的6种状态

线程的概念&#xff0c;以及线程的创建方式&#xff0c;见我之前写的博文 本篇文章主要讲Java线程的6种状态 6种状态&#xff1a;初始状态&#xff08;new&#xff09; 、可运行状态&#xff08;Runnable&#xff09;、运行状态&#xff08;Running&#xff09;、阻塞状态&am…

.NET Core 微信小程序支付——(统一下单)

最近公司研发了几个电商小程序&#xff0c;还有一个核心的电商直播&#xff0c;只要是电商一般都会涉及到交易信息&#xff0c;离不开支付系统&#xff0c;这里我们统一实现小程序的支付流程&#xff08;与服务号实现步骤一样&#xff09;。目录1、开通小程序的支付能力2、商户…

用.NET写“算命”程序

前言“算命”&#xff0c;是一种迷信&#xff0c;我父亲那一辈却执迷不悟&#xff0c;有时深陷其中&#xff0c;有时为求一“上上签”&#xff0c;甚至不惜重金&#xff0c;向“天神”保佑。我曾看到过有些算命网站&#xff0c;可以根据人的生辰八字&#xff0c;来求得这个人一…

ASP.NET Core 3.0 迁移避坑指南

一.前言.NET Core 3.0将会在 .NET Conf 大会上正式发布&#xff0c;截止今日发布了9个预览版&#xff0c;改动也是不少&#xff0c;由于没有持续关注&#xff0c;今天将前面开源的动态WebApi项目迁移到.NET Core 3.0还花了不少时间踩坑&#xff0c;给大家分享一下我在迁移过程中…

打不死我的,终将使我强大!DevOps黑客马拉松参赛心得

&#xff08;IDCF DevOps黑客马拉松到底是个啥活动&#xff1f;&#xff09;长得丑活得久、长得帅也惹人爱&#xff01;大家好&#xff0c;我是刘威。隆正信息的业务架构师-花名逸云。非常荣幸可以参加在北京举办的第一届DevOps黑客马拉松比赛。黑客马拉松不是突然冒出来的&…