ElasticAPM初体验

5,605 阅读9分钟

前言

本文从最根本的可观察性出发,引出实现这种思想的APM(Application Performance Management)框架,通过对APM的核心组件和数据模型的理解,可以加深对ElasticAPM的理解。最后通过实战演练ElasticAPM,来实现应用的性能追踪。

可观察性

“可观察性”不是供应商能够在系统之外单独交付的功能,而是您在构建系统时植根于其中的一个属性,就像易用性、高可用性和稳定性一样。设计和构建“可观察”系统的目标在于,确保当它在生产中运行时,负责操作它的人员能够检测到不良行为(例如,服务停机、错误、响应缓慢),并拥有可操作的信息以有效地确定根本原因(例如,详细的事件日志、细粒度的资源使用信息,以及应用程序跟踪)。这个目标看似平淡无奇,但组织在实现这一目标时会遇到诸多挑战,常见挑战包括:没有收集足够的信息;收集了太多信息,但没有提取出有指导意义的内容;这些信息分别存储在诸多不同的位置。

如上述引用内容可知,可观测性重点是解决运行中的系统在遇到问题时,较难定位问题的问题,尤其是在大规模分布式系统中,一个业务流程依赖上下游众多的系统,更是提高了定位问题的复杂度。而一个具备良好可观测性的系统,能够用很低的成本有效的定位关键问题所在。下图所示可观测性主要有三大支撑:

  • 日志:程序运行产生的事件,可以详细解释其运行状态
  • 指标:一组聚合数值,主要用于监控基础设施(机器、容器、网络等),但也有应用会用于监控业务层面,比如开源搜索系统Elasticsearch就有关于查询或写入量、耗时、拒绝率等应用层面的指标;
  • 应用性能监控(Application Performance Monitor):注意,这里的M代表的是Monitor,是指深入到代码层面的追踪(或监控),包括程序内部执行过程、服务之间链路调用等情况,能轻易的找到程序“慢”的原因。APM最常见被用于对web服务器中一次请求处理过程的追踪,包括内部执行逻辑、外部服务的调用及它们相应的耗时。

可观测性的三大要素

上面说的那么多,通俗一点讲举一个例子,当你负责的系统业务逻辑复杂,依赖的第三方服务或者中间件较多的前提下。有一天,你收到了一连串性能报警,你老板问你**为啥这个接口这么慢?**如果可观察性做的比较差的系统,你就疯狂的打log日志,统计各个代码行之间的耗时情况,然后上线,在茫茫日志的海洋里分析到底哪一行比较慢,如果找到了恭喜你,你是幸运的,只需要去掉日志或者改变日志级别,再上一次线就可以了!

但是,很有可能是没有找到,那会不会当时发生GC?当时带宽占用比较多?会不会当时服务器负载高?等等可能性,你由于没有完备的记录,又复现不了,就会很难保证你负责的接口是不是又会爆发性能报警问题,你的老板就会怀疑你的能力!很难受对嘛?

如果这时,天赐你一套功能完备的APM系统,你通过报警中写明的traceId,在APM平台中搜索出对应的调用链,发现你依赖的接口耗时很高,或者通过你的Metrics发现那段时间GC很频繁,再通过log拿到具体的执行信息,Bingo!相信问题已经八九不离十了,10分钟以内回复老板:“我找到问题了,原因是balabala”,没错,问我为什么要有APM,因为一切尽在掌握

APM简述

通过上一章节的分析,我们知道了什么是可观察性。那一款好的APM产品就是要提高应用的可观察性的。目前市面上大多数APM产品是应用性能监控(Application Performance Monitoring),但是在维基百科中定义的是应用性能管理(Application Performance Management)

APM 在维基百科上的定义是应用性能管理(Application Performance Management),而市面上大多数APM产品定义则是应用性能监控(Application Performance Monitoring)。《What Is Application Performance Monitoring and Why It Is Not Application Performance Management》 此文认为应用性能监控是应用性能管理一部分,前者能帮你找到问题,而后者能帮你分析并解决问题。但实际上大部分APM产品都包含了分析问题的部分,并且业界也没有对两个定义作出明确的区分,所以基本上我们可以将两者视为是相同的。

APM功能维度

  • 最终用户体验监控(End user experience monitoring)。通过监控用户的行为以期优化用户体验。比如:监控用户和web界面/客户端的交互,并记录交互事件的时间。

  • 运行时应用程序架构(Runtime application architecture)。理解服务间的依赖关系、架构中应用程序交互的网络拓扑。

  • 业务事务(Business transaction)。产生有意义的SLA报告,并从业务角度提供有关应用程序性能的趋势信息。

  • 深入组件监控(Deep dive component monitoring)。通常需要安装agent并且主要针对中间层,包括web服务器、应用和消息服务器等。健壮的监控应该能显示代码执行的清晰路径,因为这一维度和上述第二个维度紧密相关,APM产品通常会将这两个维度合并作为一个功能。

  • 分析或报告(Analytics/reporting)。将从应用程序中收集的一系列指标数据,标准化的展现成应用性能数据的通用视图。

Elastic APM简介

具体可以参考官方文档,总结起来,就是ElasticAPM是在ELK的基础之上,做了应用性能监控组件,把本来就存在的Logging,Metrics,和APM引入的Tracing数据,整合起来,变成了一个一站式的应用可观察性平台

ElasticAPM性能监控组件示意图

组件

Elastic APM由四个组件组成:

  • APM agents:以应用程序库的形式提供,收集程序中的性能监控数据并上报给APM server。
  • APM Server:从APM agents接收数据、进行校验和处理后写入Elasticsearch特定的APM索引中。虽然agent也可以实现为:将数据收集处理后直接上报到ES,不这么做官方给出的理由:使agent保持轻量,防止某些安全风险以及提升Elastic组件的兼容性。
  • Elasticsearch:用于存储性能指标数据并提供聚合功能。
  • Kibana:可视化性能数据并帮助找到性能瓶颈。

ElasticAPM组件

数据模型

Elastic APM agent从其检测(instrument)的应用程序中收集不同类型的数据,这些被称为事件,类型包括span,transaction,错误和指标四种。

  • Span 包含有关已执行的特定代码路径的信息。它们从活动的开始到结束进行度量,并且可以与其他span具有父/子关系。
  • 事务(Transaction) 是一种特殊的Span(没有父span,只能从中派生出子span,可以理解为“树”这种数据结构的根节点),具有与之关联的其他属性。可以将事务视为服务中最高级别的工作,比如服务中的请求等。
  • 错误:错误事件包含有关发生的原始异常或有关发生异常时创建的日志的信息。
  • 指标:APM agent自动获取基本的主机级别指标,包括系统和进程级别的CPU和内存指标。除此之外还可获取特定于代理的指标,例如Java agent中的JVM指标和Go代理中的Go运行时指标。

Elastic APM实战

环境安装

安装包准备

采用了最新版的ELK和Apm agent

Java agent: elastic-apm-agent-1.12.0.jar

Apm Server: apm-server-7.5.1-darwin-x86_64

ElasticSearch: elasticsearch-7.5.1

Kibana: kibana-7.5.1-darwin-x86_64

环境搭建

环境启动顺序如下

  • 启动ElasticSearch,默认端口9200

  • 启动Kibana,默认端口5601

    安装好的Kibana

  • 启动APM Server,./apm-server -e,默认端口是8200,由于apm Server使用Golang编写,本地需要安装Go环境。

  • 启动应用,java -javaagent:/Tools/apm/elastic-apm-agent-1.12.0.jar -Delastic.apm.secret_token= -jar apm-0.0.1-SNAPSHOT.jar。如果使用Idea启动应用,可以如下配置

    idea启动应用携带apm参数

    启动之后,如果发现如下日志,则代表织入了apm-java-agent。Java agent采用了Byte Buddy技术动态织入字节码,使得agent变得没有侵入性。

    2020-01-08 15:09:32.603 [apm-server-healthcheck] INFO co.elastic.apm.agent.report.ApmServerHealthChecker - Elastic APM server is available: {  "build_date": "2019-12-16T20:57:12Z",  "build_sha": "348d8d83c3c823b64fc0692be607b1a5a8fac775",  "version": "7.5.1"}
    2020-01-08 15:09:32.779 [main] INFO co.elastic.apm.agent.configuration.StartupInfo - Starting Elastic APM 1.12.0 as sample_wsy on Java 1.8.0_201 (Oracle Corporation) Mac OS X 10.14.6
    
    

Demo开发

POM.xml,项目中需要引入apm-agent依赖,apm-agent默认会收集一些事件,比如HTTP请求和database queries,并且为了不侵入应用,采用了字节码织入技术来实现java-agent,使得apm-agent对业务系统变得透明,但是透明意味着不可控,apm还提供了public API,来手动可控的方式,来告诉agent采集这些信息。

具体的Java-agent有很多功能,本文不赘述,请参考官方文档

<dependency>
	<groupId>co.elastic.apm</groupId>	
	<artifactId>apm-agent-api</artifactId>
	<version>1.12.0</version>
</dependency>

Controller代码

    @GetMapping("/test/{name}")
    public String test(@PathVariable String name) {
        String result = null;
        Transaction transaction = ElasticApm.currentTransaction();
        System.out.println(transaction.getTraceId());
        try {
            transaction.setName("WsyController#test");
            transaction.setType("CUSTOM");
            result = testService.test(name);


        } catch (Exception e) {
            transaction.captureException(e);
        } finally {
            //WARN co.elastic.apm.agent.impl.transaction.AbstractSpan - End has already been called: ''
            //注意,如果调用ElasticApm.currentTransaction();就不需要transaction.end();否则会报如上警告
            transaction.end();
        }

        return result;
    }

Service代码

@Service
public class TestService {
    public String test(String name) {
        Span span = ElasticApm.currentTransaction().startSpan();
        try {
            span.setName("test0-wsy");
            test1(name);
        } catch (Exception e) {
            span.captureException(e);
        } finally {
            span.end();
        }
        return "hello " + name;
    }

    public String test1(String name) {
        Span span = ElasticApm.currentTransaction().startSpan();
        try {
            span.setName("test1-wsy");
            
        } catch (Exception e) {
            span.captureException(e);
        } finally {
            span.end();
        }
        return name;
    }
}

请求Controller之后,刷新Kibana,发现已经拥有了链路追踪

APM追踪示意图

提出问题

1、本文在单机版的环境中,测试通过,但是在分布式环境中,请求会串联起很多应用,那服务跟踪能否实现?实现的原理是什么?

2、Elastic APM可以自动采集http请求,在PRC分布式环境中,Elastic APM能否正常工作?是否必须采用 public API来实现?

总结

1、APM可以提升系统的可观察性

2、ElasticAPM可以借助ElasticSearch和Kibana一站式的解决链路追踪

参考文档

Dapper,大规模分布式系统的跟踪系统

Dapper, a Large-Scale Distributed Systems Tracing Infrastructure

官方APM Java Agent Reference 1.x

官方APM Overview

全链路分布式跟踪系统与APM

使用Elastic APM做应用性能监控

借助Elastic Stack实现可观察性

分布式跟踪、开放式跟踪和ElasticAPM