Observability:应用程序性能监控/管理(APM)实践

168 篇文章 31 订阅
15 篇文章 9 订阅

在今天的文章里,我们将介绍 Elastic 的一个重要的应用:应用程序性能管理(Application Performance Monitoring/Management),简称 APM。那么到底什么是 APM 呢?你已经在 Elasticsearch 中应用了日志和系统指标吗? 使用 Elastic APM 扩展到应用程序指标。 你可以准确了解你的应用程序在哪里花时间,以便你可以快速解决问题并对所推送的代码感到满意。

Elastic APM 动手实践

Elastic APM 动手实践_哔哩哔哩_bilibili

现代应用服务架构

随着时代的发展,我们的 IT 架构越来越复杂,比如:

当今运维监控的挑战 - 复杂的基础设施

  • 基础架构层面是复杂的

  • 多种服务器

  • 多种网络设备

  • 多种安全设备

  • 多种存储设备

我们系统的服务器越来越多,而且更多的设备都部署在云端。复杂的系统甚至有成千个微服务及架构所组成,那么我们的业务请求可能需要一个或成百上千的的微服务来共同来完成。

由于业务的复杂度增加,微服务之间的互相调用也变得更加复杂。那么现在的问题是:如果我们的请求变得很慢,我们想知道到底是哪个环节出现问题了呢?

经验丰富的程序员或者系统设计者,可能从一些log里找到答案:

日志是事件的时间顺序记录。我们可以从这里成千上万的 log 里找到一些蛛丝马迹,比如我们可以通过请求返回的代码。Log 在很多的时候很有用,但是它有一个几个缺点:

  • 你如果在你的应用中不打印 log 信息,你是没有 log 内容可以看
  • Log 只告诉你什么时候发生这个错误了,但有时不能告诉你为什么,比如返回代码都是正确的,但是它不能接受为什么相应的速度这么慢

同时,应用开发者也可以从指标(Metric)里找到答案。指标是对数字 KPI 的定期测量:

在上面,我们可以通过 metric 每x分钟测量一次 CPU 负载并使用元数据进行注释。通过指标,我们可以分析出如果在一个请求发生错误或者响应时间过长的时候 CPU 的负载情况,或者磁盘的使用率是多少等这样的信息:

上面是在 Mac 上面使用 iostat 命令时我们看到的输出。指标在很多我们想要显示趋势或者历史数据时非常有用。在尝试创建简单,可预测,可靠的规则以捕获事件和异常时则很有用。 指标的一个问题是它们倾向于监视基础结构层,获取有关组件实例级别(如主机,容器和网络)的数据,而不是自定义应用程序级别。

但是现在的问题是:在上面的每个事件期间和事件之间到底发生了什么呢?比如上面的三个 log 事件之间,第一个事件发生在16:10:02,第二个事件发生在 16:58:58,第三个事件发生在 16:20:55。我们可以看出来第二个事件和第三个事件之间的间隔是9分钟。这之间到底发生了什么呢?

我们先看一下在第二事件发生时的日志和指标:

日志

指标

可是当我们的 log 变得非常大的时候,而且我们的接口也越来越多时,这个时候,我们再看这些日志和指标时也无能为力。

当我们在设计页面或者请求时,经常会遇到上面的这种等待的情况。可能有个别的工具能有效地解决部分的问题,但是如何能从整个的系统里来完成这种问题的定位及分析。 Elastic 推出的 APM 解决方案可以完美地解决这些问题。为我们的系统设计者或程序员提供了一个快速定位的方法。

运用 Elastic APM,它可以很方便地帮我们定位出为什么我们的每个请求需要花这么多的时间来完成,中间的每一个时间都是花在哪里了?

Elastic Observability (可观测性)

Elastic 通过整合日志,指标及 APM,统一整个生态系统可见性,打造一个完整的可观测性。将你的日志,指标和 APM 跟踪大规模整合到一个堆栈中,以便你可以监视环境中发生的事件并对事件做出反应。按照文章 “Metrics, tracing, and logging” 的描述,打造全面的可观测性,需要如下的三个要素:

在 Elastic Stack 中,我们都有相应的模块处理:

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

Elastic APM 是 Elastic 公司打造全面可观测性的重要一环。它和 Logs,Mertics 以及 Uptime 共同打造 IT 系统的全面可观则性。通过 APM 的运用,我们可以找出系统里的执行速度比较慢的部分以及出错的地方:

比如,对于一个票务搜索系统来说,我们可以找出为什么搜索会比较慢?什么时候慢?在系统的哪一个微服务或数据库的访问出现了问题。为什么客户不能正确地下订单?它们的错误信息是什么?

Elastic Stack 可为所有运营数据提供快速,可靠和相关的搜索,因此无论数据类型如何,你都可以提出自己想要的问题-并获得所需的答案。APM 扩展了日志记录和服务器级别的监视功能,为系统的可观察性增加了新的维度。通 Real User Monitoring (RUM),这也可以扩展到最终用户的体验。运用 Elastic Stack,可以打造一站式的全栈监控:

APM 到底是什么呢?

简单地说:APM 就是监视和管理软件应用程序的性能和可用性。Elastic APM 是基于 Elastic Stack 构建的应用程序性能监视系统。 它使你可以实时监视软件服务和应用程序-收集有关传入请求,数据库查询,对缓存的调用,外部 HTTP 请求等的响应时间的详细性能信息。 这样可以轻松快速地找出并解决性能问题。

Elastic APM 还会自动收集未处理的错误和异常。 错误主要根据堆栈跟踪进行分组,因此你可以在新错误出现时识别它们,并密切注意特定错误发生的次数。

指标是调试生产系统时的另一个重要信息来源。 Elastic APM 代理会自动选择基本主机级别指标和特定于代理的指标,例如 Java 代理中的 JVM 指标和 Go 代理中的 Go 运行时指标。

我们先来看一下如下的这个图:

如上图所示,在不同时刻我们请求时,我们发现为什么在 17:36:38 发生的一个请求需要花将近8秒的时间,而另外在 17:36:31 分发生的一个请求却返回一个错误的代码?

Elastic APM 方案是世界上第一个开源的 APM 解决方案:

  • APM 记录数据库查询,外部 HTTP 请求以及对应用程序的请求期间发生的其他缓慢操作的跟踪

         -  很容易让程序员看到应用在运行时各个部分所花的时间

  • 它收集未处理的错误和异常

         - 很容让程序员调试错误

  • 在客户面对性能瓶颈和错误之前先定位到问题所在
  • 提高开发团队的生产力

APM 应用于 Elastic Stack 的位置

APM 如何把数据存于 Elasticsearch 中,并提供分析呢?我们看一下如下的架构图:

如上图所示,我们看到一个最典型的 APM 架构图:

  • 我们需要架设一台专门的 APM 服务器,虽然也可以和 Elastic Stack 的其它服务器处于同一台服务器中。所支持的版本至少是 6.5 及以上
  • AMP agents 专门收集数据并发送数据到 APM 服务器中。这里的 APM agents 包含:

  • APM 服务器把数据发送到 Elasticsearch 中,并进行数据分析
  • Kibana 可以帮我们把数据进行展示并显示在 Dashboard 之中

总体来说,APM 数据仅仅是另外的 Elasticsearch 索引。在 Kibana 中已经有一个现成的 APM 应用可以被我们所使用。我们也可以根据需求自己定制自己的 Dashboard。APM 可以完美地结合机器学习和告警。

APM术语

  • Service: 在 APM agent 配置中进行设置,以将特定的 APM agent 组标识为单个服务,这是一种逻辑上标识一组事务的方法
  • Span: 事务中的单个事件,例如方法调用,数据库查询或缓存插入或检索,即需要花费时间才能完成的任何事件。从开始到结束记录特定代码路径的单个活动单元。 span 可以有父 span 或子 span,指示代码执行上下文中的事件层次结构。
  • Transaction: 组成一个服务的请求和响应,例如登录 API 调用,每个调用由单独的 span 组成。这些是一种特殊类型的 span,描述了应用程序中的高层次事件。 transactions 可用于对相关 span 进行逻辑分组,并将它们映射到应用程序功能。
  • Erorrs:具有匹配的异常或日志消息的异常组
  • Trace:代表请求的整个过程,是一个端到端的请求。一个 Trace 可以跨多个服务。在这些服务中  trace id 是同一个。
  • Metrics:通过捕获基本的主机级指标(包括系统资源利用率和进程元数据)来补充跟踪(trace)数据。

它们之间的关系可以用如下的图来表示:

在业务逻辑上,可以是这样的一种情形:

从上面我们可以看出来,transaction 从某种程度上也可以被认为是一种特殊的 span。它开始于一个服务的调用。在上面,一个 transaction 始于一个颜色的开始,也就是一个服务调用的开始。Transactions 和 Spans 它们共同组成了 Traces。Traces 不是事件,它们代表一个端到端的请求,并且这些请求跨1个或多个 transactions(也就是多个服务)。

分布式 tracing:

当请求从一个微服务流向另一个微服务时,追踪器添加逻辑以创建唯一的追踪识别代码, 跨度 id。

动手实践

在今天的练习中,我们将以 Java Spring boot 为例来展示如何使用 Elastic APM。

下载 Spring boot 代码

首先,我们在 terminal 中打入如下的命令:

git clone https://github.com/liu-xiao-guo/elastic-apm-demo

上面的一个例子是一个简单的 Spring boot 应用。它有一下的几个特点:

  • 它可以 REST 接口访问 MySQL 的数据库进行添加数据,请求数据
  • 它可以通过 REST 接口进行访问百度天气接口来获得天气数据

下面是它的部分代码:

	@PostMapping(path="/add") // Map ONLY POST Requests
	public @ResponseBody String addNewUser (@RequestParam String name
			, @RequestParam String email) {
		// @ResponseBody means the returned String is the response, not a view name
		// @RequestParam means it is a parameter from the GET or POST request

		User n = new User();
		n.setName(name);
		n.setEmail(email);
		userRepository.save(n);
		return "Saved";
	}

	@GetMapping(path="/all")
	public @ResponseBody Iterable<User> getAllUsers() {
		// This returns a JSON or XML with the users
		return userRepository.findAll();
	}

	@GetMapping(path="/weather")
	public @ResponseBody String getBaiduWeather() throws InterruptedException {
		// Add some random delays before getting the info
		double delay = Math.random() * 10;
		System.out.println("delay: " + delay);
		TimeUnit.SECONDS.sleep((long)delay);

		String weather = getWeatherInform("北京");

		return weather;
	}

在获得天气(weather)的接口中,我故意加入了一下随机数的延迟,这样来模拟每一次请求的时间是不同的。

我们可以在应用的根目录下打入如下的命令:

./mvnw clean package

这样它将会在当前目录下的target子目录下生产一个叫做 accessing-data-mysql-0.0.1-SNAPSHOT.jar 的文件。

你可以打开 localhost:8080 在网页中查看是否有页面的输出。

$ ls ./target/accessing-data-mysql-0.0.1-SNAPSHOT.jar
./target/accessing-data-mysql-0.0.1-SNAPSHOT.jar

如果你想测试这个应用的话,你可以在应用的根目录中打入如下的命令:

java -jar ./target/accessing-data-mysql-0.0.1-SNAPSHOT.jar

你可以打开 localhost:8080 在网页中查看是否有页面的输出。

我们可以把这个文件拷入到我们想要的任何一个目录中。针对我的情况,我把它拷入到我的 home 目录下的 data/apm 目录中。

$ pwd
/Users/liuxg/data/apm
liuxg-2:apm liuxg$ ls accessing-data-mysql-0.0.1-SNAPSHOT.jar
accessing-data-mysql-0.0.1-SNAPSHOT.jar

安装 MySQL

我们可以按照文档的需求来安装我们的 MySQL。我们在一个 terminal 中打入如下的命令:

 mysql -uroot -p

我们打入 root 用户的密码进入到 MySQL 之中。为了创建一个数据库,我们在 MySQL 的 prompt 中打入如下的命令:

mysql> create database db_example; -- Creates the new database
mysql> create user 'springuser'@'%' identified by 'ThePassword'; -- Creates the user
mysql> grant all on db_example.* to 'springuser'@'%'; -- Gives all privileges to the new user on the newly created database

上面的命令创建了一个叫做 db_example 的数据库。同时,它也创建了一个叫做 springuser 的用户及其密码 ThePassword。一定要记住这里的用户名和密码要和我们在上面的 Java 应用中的用户名及密码是一致的:

我们可以通过 MySQL 工具来查看:

请注意在上面的数据库中,我们有三个字段:id, email 及 name。

运行 Elastic Stack

为了使用 APM,我们至少需要安装如下的 Elastic Stack 组件:

  • Elasticsearch
  • Kibana
  • APM Server
  • APM Agents

安装 Elastic Stack,有两种方法。最简单的一种方法是运用 docker 来一键部署 Elasticsearch, Kibana 和 APM 服务器。详细安装步骤请参阅链接 apm-contrib/stack at master · elastic/apm-contrib · GitHub。下面我们采用一种手动的方法来部署Elastic Stack。

我们可以按照我们的文章 “Elastic:菜鸟上手指南” 来安装及运行我们的 Elasticsearch 及 Kibana。

我们也必须安装和 Elasticsearch 一样版本的 APM 服务器。我们打开我们的 Kibana 界面,并点击左上角的部分:

然后,我们按照上面的步骤一步一步地进行安装:

我们按照上面的要求配置好 Elasticsearch 的地址及用户名和密码(如果你已经启动了安全的设置):

上面的步骤非常详细。如果我们希望对 Real User Monitoring (RUM) 进行监控的话,我们必须修改我们的 apm-server.yml 进行修改。我们在 apm-server.yml 文件的最后添加:

apm-server.rum.enabled: true

对于 APM agent 的选择来讲,因为我们是 Java 应用,所以我们选择 Java agent。我们下载相应的 agent jar 文件,并存放于我们上面放置 spring boot 的 jar 文件所处的文件夹。针对我的情况是 home 目录下的 data/apm。

$ pwd
/Users/liuxg/data/apm
liuxg-2:apm liuxg$ ls *.jar
accessing-data-mysql-0.0.1-SNAPSHOT.jar elastic-apm-agent-1.10.0.jar

在这个时候,我们可以开始运行我们的 Spring Java 应用了。我们可以通过如下的命令来运行:

java -javaagent:./elastic-apm-agent-1.10.0.jar \
     -Delastic.apm.service_name=sample_apm \
     -Delastic.apm.server_url=http://localhost:8200 \
     -Delastic.apm.secret_token= \
     -Delastic.apm.application_packages=accessing-data-mysql \
     -jar accessing-data-mysql-0.0.1-SNAPSHOT.jar

注意:这里的 sample_apm 是我给取的一个服务名称。你可以根据自己的需求取一个独特的名字。如果你不想这么麻烦,你可以在当前的目录下生产一个叫做 elasticapm.properties 的文件。它的内容如下:

service_name=sample_apm
application_packages=accessing-data-mysql
server_url=http://localhost:8200

那么我们可以通过如下的命令来运行:

java -javaagent:./elastic-apm-agent-1.10.0.jar \
     -Delastic.apm.secret_token= \
     -jar accessing-data-mysql-0.0.1-SNAPSHOT.jar

另外一种方法是通过设置 OS 的环境变量来实现。这个配置将取代任何在 elasticapm.properties 中的设置,比如:

export ELASTIC_APM_SERVICE_NAME=my_fantastic_service
export ELASTIC_APM_APPLICATION_PACKAGES=org.example
export ELASTIC_SERVER_URL=http://localhost:8200

在上面的几种方式中,使用 java -D 这样的命令行参数定义具有最高的优先级,如果在几种定义方式同时存在的话。使用 elasticapm.properties 配置的优先级最低。任何其它方法的配置都可以覆盖在 elasticapm.properties 中的配置。

等我们的 Spring Boot 应用完全起来后,我们点击 Kibana 中的 “Check agent status” 按钮。这个时候可能显示没有任何的数据。我们可以打开我们的浏览器,并在浏览器的地址栏中输入如下的地址:

我们可以看到我们得到了一下天气的数据信息。那么这个时候我们可以在 Agent status 中看到信息:

我们点击上面的 “Confirm overwrite” 按钮:

启动 APM 应用

如果你已经运行到这里,那么你基本上已经把整个的环境运行起来了。我们可以在 terminal 中打入如下的命令:

curl localhost:8080/demo/add -d name=First -d email=someemail@someemailprovider.com

上面的应用是向我们的数据中写入一条记录。

curl 'localhost:8080/demo/all'

运行上面的命令可以展示已经输入的所有的记录

curl 'localhost:8080/demo/weather'

运行上面的命令可以获得百度天气 API 接口所带给我们的天气信息。

上面的所有的信息我们都可以在浏览器中的地址栏中输入。

点击 Kibana 中的 APM 应用图标

我们点击 sample_apm 链接:

在上面我们可以看到应用的四个接口的统计情况。

我们在这个 APM 应用的 dashboard 上可以看到我们所有的 API 的调用情况。比如:

因为在我的应用中,我故意加入了一些延迟,所以导致我们的整个 getBaiduWeather 的请求时间为9.157秒才完成,而 api.map.baidu.com 的时间只有149ms。我们点击上面的蓝色的线条,我们可以看到这个API的调用情况:

我们点击  “addNewUser” 链接:

我们可以看到如下的画面:

我们可以看到在 addNewUser 调用 MySQL 里的几个命令所花的时间。

我们也可以点击 Error 来看所有的错误信息:

我们点击上面的链接可以产出来我们的错误的 stack:

我们点击上面的 JVM,可以查看出来的目前的 JVM 的使用情况:

到这里我的讲解就完成了。剩下的留给大家自己去挖掘哈!

更多阅读

参考:

【1】Accessing data with MySQL

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值