Kubernetes 可观测性教程:使用 Elastic APM 监测应用程序性能

本篇博文是我们 Kubernetes 可观测性教程系列的第三篇,本系列教程将带您探索如何实现对 Kubernetes 中运行的应用程序的全面监测,包括:

我们将讨论利用 Elastic 可观测性,使用 Elastic APM 执行应用程序性能监测(APM)。

开始前:以下教程需要设置有以下教程需要对 Kubernetes 环境进行设置。我们已经编写一篇补充博文,指导您设置单节点 Minikube 环境和演示应用程序的流程,从而运行其余活动。

应用程序性能监测

APM 的重点是自动测量面向用户的关键服务水平指标 (SLI):请求/响应延迟和面向用户的错误。通过有效监测这些指标,您可以快速锁定导致性能下降或错误增加的组件(甚至是代码块)。APM 提供绝佳的初级分类工具,可以定位造成问题的根本原因,减少平均响应时间 (MTTR)。

Elastic APM 的分布式跟踪

Elastic APM 支持分布式跟踪,可以测量参与服务同一用户请求的不同分布式应用程序组件的端到端请求/响应延迟。APM 应用可以展示总跟踪时长以及参与分布式跟踪组件相关延迟的细分信息。让我们前往 Kibana 中的 APM 应用,查看跟踪和事务。注意:请务必先在 petclinic 应用中随便单击,生成一些用户流量!

Elastic APM 中的分布式跟踪

日志和指标相关的跟踪

在将应用程序部署到 Kubernetes 中时,分布式跟踪和 APM 依然能够显示快速分类问题的优势,同时也能捕获和交叉引用可观测性难题的其他部分:日志和指标。随着对每一部分的掌握了解,通过缩小调查范围至某个使用 APM 的组件,可以开始延迟峰值故障排除,并轻松与某个特定 Kubernetes pod 的 CPU 和内存利用率指标和错误日志条目相关联,所有过程均可在 Kibana 中进行。

现在,得益于 Beats 中的处理器以及 APM 代理收集的元数据,Kibana 中的所有可观测性均可交叉引用。您可以开始查看 APM 跟踪,检查处理该跟踪流程中涉及的 pod 指标,以及查看跟踪处理时,并行组件遗留的日志,一处便可实现所有这些功能。

有了 Elastic APM,可以便捷实现跟踪和日志数据的关联。

快速从 APM 跟踪跳转到 Kibana 中的基础架构指标

Elastic APM 代理部署

APM 代理与其监测的应用程序组件联合部署。有了 Kubernetes,应用程序组件成为了 pod 中运行的代码的一部分。本教程中,我们使用两个代理:APM 真实用户监测 (RUM) JavaScript 代理和 APM Java 代理。

Elastic APM Java 代理

这是 APM Java 代理在 petclinic pod 部署描述符 $HOME/k8s-o11y-workshop/petclinic/petclinic.yml 中的初始部分:

          env:
          - name: ELASTIC_APM_SERVER_URLS
            valueFrom:
              secretKeyRef:
                name: apm-secret
                key: apm-url
          - name: ELASTIC_APM_SECRET_TOKEN
            valueFrom:
              secretKeyRef:
                name: apm-secret
                key: apm-token
          - name: ELASTIC_APM_SERVICE_NAME
            value: spring-petclinic-monolith
          - name: ELASTIC_APM_APPLICATION_PACKAGES
            value: org.springframework.samples

APM 代理作为依赖项包含在 petclinic 应用程序的 pom.xml 文件中 $HOME/k8s-o11y-workshop/docker/petclinic/pom.xml

<!-- Elastic APM dependencies -->
        <dependency>
            <groupId>co.elastic.apm</groupId>
            <artifactId>apm-agent-attach</artifactId>
            <version>${elastic-apm.version}</version>
        </dependency>
        <dependency>
            <groupId>co.elastic.apm</groupId>
            <artifactId>apm-agent-api</artifactId>
            <version>${elastic-apm.version}</version>
        </dependency>
        <dependency>
            <groupId>co.elastic.apm</groupId>
            <artifactId>elastic-apm-agent</artifactId>
            <version>${elastic-apm.version}</version>
        </dependency>
        <!-- End of Elastic APM dependencies -->

在 Java 代理中,这种部署方式可作为一个 Maven 依赖项予以添加。还有其他方式部署 APM 代理,例如 Java 代理运行时附件。详细信息请查阅 Elastic APM Java 代理文档

Elastic APM 真实用户监控 (RUM) 代理

RUM 代理作为用户浏览器应用程序的一部分运行,直接从浏览器提供所有面向用户的指标。本次教程中,我们会将其用于此种用途,并会作为分布式跟踪的起点。这是在 Javascript 用户端代码中实例化 APM 代理的情况 $HOME/k8s-o11y-workshop/docker/petclinic/src/main/resources/templates/fragments/layout.html

 <script th:inline="javascript">
...
    var serverUrl = [[${apmServer}]];
    elasticApm.init({
     serviceName: 'petclinic-frontend',
     serverUrl: serverUrl,
     distributedTracingOrigins: [],
     pageLoadTransactionName: pageName,
     active: true,
     pageLoadTraceId: [[${transaction.traceId}]],
     pageLoadSpanId: [[${transaction.ensureParentId()}]],
     pageLoadSampled: [[${transaction.sampled}]],
     distributedTracing: true,
    })
...
 </script>

Petclinic 是服务器端渲染的应用程序,Thymeleaf 是一款结合 Spring Boot 使用的模板渲染框架,因此,它会在控制器 Java 代码中填充一些发送到前端的值。此处示例展示如何填充事务模型属性 $HOME/k8s-o11y-workshop/docker/petclinic/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java

    @ModelAttribute("transaction")
    public Transaction transaction() {
        return ElasticApm.currentTransaction();
    }

监测错误

APM 代理也可以捕获未处理的异常。请尝试在“ERROR”(错误)菜单位置单击,查看 Kibana 中的 APM 应用,获取引发的异常详细信息。

样例应用程序

只需单击一次,Elastic APM 便可向您呈现所有的应用程序错误

这是处理 APM 代理如何捕获应用程序引发的未处理异常的 Java 代码。$HOME/k8s-o11y-workshop/docker/petclinic/src/main/java/org/springframework/samples/petclinic/system/CrashController.java

    @GetMapping("/oups")
    public String triggerException() {
        throw new RuntimeException("Expected: controller used to showcase what "
                + "happens when an exception is thrown");
    }

监测运行时指标

代理与应用程序组件在运行时中同时部署,并收集运行时指标。例如,除了实现指标收集外,Java 代理还可以在投入使用的当下,立即收集上述信息,且无需提供任何代码或配置。

Elastic APM 中的运行时指标

服务地图

Elastic APM 7.7 引入了服务地图公测版,一种表示 APM 跟踪中所呈现关系的图表。该视图显示了 APM 应用中所展示跟踪的相关组件。我们的应用程序非常简单,只有一个包含 Java 和 MySQL 后端的浏览器客户端,所以生成的地图也十分简单易懂。

Elastic APM 中的服务地图

使用 Elastic APM 代理收集 JMX 指标

可以配置 Java 代理收集应用程序公开的 JMX 指标。本次教程中的 Petclinic 组件配置用来收集以下指标 $HOME/k8s-o11y-workshop/petclinic/petclinic.yml:

- name: ELASTIC_APM_CAPTURE_JMX_METRICS
  value: >-
   object_name[java.lang:type=GarbageCollector,name=*]    
     attribute[CollectionCount:metric_name=collection_count] 
     attribute[CollectionTime:metric_name=collection_time],
   object_name[java.lang:type=Memory] attribute[HeapMemoryUsage:metric_name=heap]

使用 Lens 可视化定制指标

并非所有指标都在 AMP 应用中有所体现。如上述示例,JMX 指标为应用程序特有,因此不能在 APM 应用内予以可视化呈现。此外,有时指标需要与其他可视化相组合,或以不同的方式可视化,才能实现价值体现。Kibana 可视化和仪表板当然可以用于这些指标的可视化,但本次教程希望向大家展示一种更快捷的全新方式,为各位带来耳目一新的体验。

近期,Kibana 中引入了 Lens,作为一种更直观的分析人员驱动可视化工具。本示例将展示如何使用 Lens 实现代理收集的定制 JMX 指标的可视化。

Lens 示例

为了让展示更有趣,我们运行一个 scale-out 命令,增加 petclinic 组件的 pod 计数,这样每个运行的 JVM 就可以实现多行。

$ kubectl scale --replicas=3 deployment petclinic-deployment
# Validate the scale-out did what it was supposed to
$ kubectl get pods

您将看到以下信息:

NAME                                    READY   STATUS    RESTARTS   AGE
mysql-deployment-7ffc9c5897-grnft       1/1     Running   0          37m
nginx-7ff654f859-xjqgn                  1/1     Running   0          28m
petclinic-deployment-86b666567c-5m9xb   1/1     Running   0          9s
petclinic-deployment-86b666567c-76pv7   1/1     Running   0          9s
petclinic-deployment-86b666567c-gncsw   1/1     Running   0          30m
theia-86d9888954-867kk                  1/1     Running   0          43m

现在我们来见识下 Lens 的神奇之处:

Lens 启动!

大家都知道搜索栏的用途是进行搜索

当然,Elastic APM 应用也有搜索栏。对于大海捞针式的搜索问题症结,此功能可以缩小排查范围,是您得力的助手。此处的示例将为大家展示 APM UI 视图如何缩小至特定的浏览器类型:

Elastic APM 拥有强大的搜索功能,因为它基于 Elasticsearch 打造

APM 跟踪和日志关联

另外一个有用的示例是关联 APM 跟踪与所跟踪代码生成的日志条目,该示例可以显示出事半功倍的效果。可以通过其 trace.id<code> 字段,将日志条目与 APM 跟踪相关联。而且这一切无需繁琐的操作,只需一些简单的配置即可。首先,我们来看一个此类关联的示例。

看一下这项跟踪:

一键实现跟踪和日志关联

此项跟踪展示了不同的代码部分如何执行的时间线视图,现在我们看一下刚才跟踪的代码生成的日志内容。我们将选择 Actions(操作)菜单中的 Trace logs(跟踪日志)。然后我们会看到日志 UI,预选跟踪数据捕获时的时间,并将使用 trace.id 筛选使用相同 trace.id 注释的日志数据:

您的跟踪日志流

详细了解跟踪 id

显而易见,trace.id 为 APM 跟踪固有,但我们可以如何对其进行管理,以扩充日志数据呢?首先,由于正在使用 Elastic APM Java 代理,我们使用了其实施的日志关联功能。实际上,它填充了 Java 日志记录框架(如使用 Spring Boot,则为 logback)的 MDC 上下文映射中的 trace.idtransaction.id 字段。而这只需要在 petclinic ConfigMap petclinic/petclinic.yml 中设置这一环境变量:

          - name: ELASTIC_APM_ENABLE_LOG_CORRELATION
            value: "true"

然后,使用 ECS 日志记录配置 petclinic 应用日志记录,使用与 Elastic Common Schema 对应的其他字段(例如 log.level、 transaction.id 等)扩展发送到 Elastic Stack 中的日志条目。为了实现这点,我们在 petclinic 应用程序的 pom.xml 中添加了以下依赖项:

        <dependency>
            <groupId>co.elastic.logging</groupId>
            <artifactId>logback-ecs-encoder</artifactId>
            <version>${ecs-logging-java.version}</version>
        </dependency>

还有 docker/petclinic/src/main/resources/logback-spring.xml 文件,其中 ECS 日志记录配置为以 JSON 形式写入 stdout:

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
      <encoder class="co.elastic.logging.logback.EcsEncoder">
        <serviceName>petclinic</serviceName>
      </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="console"/>
    </root>

最后,petclinic ConfigMap (petclinic/petclinic.yml) 中的注释利用 Beats 自动发现指示 Filebeat(解析 petclinic 生成的 JSON):

container:
      annotations:
...
        co.elastic.logs/type: "log"
        co.elastic.logs/json.keys_under_root: "true"
        co.elastic.logs/json.overwrite_keys: "true"

所以为了实现这一关联,我们需要启用 Java 代理和日志记录框架来记录跟踪关联,以及将这两部分可观测性数据相关联。

系列总结

日志、指标和 APM,我们都一一进行了讲解!本系列博文中,我们讲解了使用 FilebeatMetricbeatAPM 收集其日志、指标和 APM 跟踪(结合 Elastic Stack)。本教程还介绍了如何使用相同组件收集 Kubernetes 日志和指标。Elastic 生态环境中还有其他组件可以添加更多详尽信息,完善 Kubernetes 环境的可观测性布局:

  • Heartbeat:衡量应用程序和整体 Kubernetes 环境运行时间和响应能力的最佳途径。它可以部署在集群之外,更靠近用户所在的位置。Heartbeat 可以为您呈现用户视角的应用程序运行状态,用户正在经历哪种网络和响应延迟,以及用户会面临的错误数量。
  • Packetbeat:获得内部 Kubernetes 集群网络流量、TLS 证书握手、DNS 查找等视图。
  • 我已经随附一个 Jupyter 记事本样例部署,添加了一个样例记事本,向您展示如何访问存储在 Elasticsearch 中的原始可观测性数据,这样您就可以在数据科学方面更加游刃有余:
    k8s-o11y-workshop/jupyter/scripts/example.ipynb
        

欢迎您为 Github 存储库 贡献内容,或者如果您遇到任何异常问题,欢迎在 Github 中提出问题。

您可以立即开始监测自己的系统和基础架构。您可以在 Elastic Cloud 上注册免费试用 Elasticsearch Service,或者下载 Elastic Stack 并自行托管。配置完成并开始运行后,您便可以利用 Elastic 运行状态监测对主机可用性进行监测,使用 Elastic APM 检测在主机上运行的应用程序。这样您便可以顺利朝着全方位可观测系统的发展方向行进,实现全新指标集群的完整集成。如果您遇到任何困难或问题,请跳转至我们的讨论论坛,我们时刻准备为您服务。