Observability:从零开始创建 Java 微服务并监控它 (二)

news/2024/5/14 15:22:55/文章来源:https://blog.csdn.net/UbuntuTouch/article/details/128127768

这篇文章是继上一篇文章 “Observability:从零开始创建 Java 微服务并监控它 (一)” 的续篇。在上一篇文章中,我们讲述了如何创建一个 Java web 应用,并使用 Filebeat 来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用 APM 来监控应用并监督 web 服务的在线情况。

源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。

摄入指标

指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有 1000 个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/最大值以获得更多指示。此外,这意味着你还需要考虑这些指标的持续时间。你需要每分钟一次还是每 10 秒一次?

为了从不同的角度查看你的应用程序,让我们获取一些指标。在此示例中,我们将使用 Metricbeat Prometheus 模块将数据发送到 Elasticsearch。

我们应用程序中使用的底层库是 micrometer.io,这是一个供应商中立的应用程序指标,结合其 Prometheus 支持来实现基于拉取的模型。你可以使用 Elastic 支持来实现基于推送的模型。这将要求用户在我们的应用程序中存储 Elasticsearch 集群的凭证数据。

向应用程序添加指标

1)将依赖项添加到我们的 build.gradle 文件中。

  // metrics via micrometerimplementation 'io.micrometer:micrometer-core:1.5.4'implementation 'io.micrometer:micrometer-registry-prometheus:1.5.4'implementation 'org.apache.commons:commons-lang3:3.11'

2)将 micrometer 插件及其相应的导入添加到我们的 Javalin 应用程序中。

...
import io.javalin.plugin.metrics.MicrometerPlugin;
import io.javalin.core.security.BasicAuthCredentials;
...Javalin app = Javalin.create(config -> {...config.registerPlugin(new MicrometerPlugin());
);

App.java

package de.spinscale.javalin;import io.javalin.Javalin;
import io.javalin.http.Handler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import io.javalin.plugin.metrics.MicrometerPlugin;
import io.javalin.core.security.BasicAuthCredentials;public class App {private static final Logger logger = LoggerFactory.getLogger(App.class);public static void main(String[] args) {Javalin app = Javalin.create(config -> {config.requestLogger((ctx, executionTimeMs) -> {String userAgent = ctx.userAgent() != null ? ctx.userAgent() : "-";logger.info("{} {} {} {} \"{}\" {}",ctx.method(), ctx.req.getPathInfo(), ctx.res.getStatus(),ctx.req.getRemoteHost(), userAgent, executionTimeMs.longValue());});config.registerPlugin(new MicrometerPlugin());});app.get("/exception", ctx -> {throw new IllegalArgumentException("not yet implemented");});app.exception(Exception.class, (e, ctx) -> {logger.error("Exception found", e);ctx.status(500).result(e.getMessage());});app.get("/", mainHandler());app.start(8000);}static Handler mainHandler() {return ctx -> {String userAgent = ctx.userAgent() != null ? ctx.userAgent() : "-";logger.info("This is an informative logging message, user agent [{}]", userAgent);ctx.result("Absolutely perfect");};}
}

3)添加一个新的 metrics 端点并确保 BasicAuthCredentials 类也被导入。

final Micrometer micrometer = new Micrometer();
app.get("/metrics", ctx -> {ctx.status(404);if (ctx.basicAuthCredentialsExist()) {final BasicAuthCredentials credentials = ctx.basicAuthCredentials();if ("metrics".equals(credentials.getUsername()) && "secret".equals(credentials.getPassword())) {ctx.status(200).result(micrometer.scrape());}}
});

在这里,Micrometer 类是一个名为 Micrometer.java 的自写类,它设置了几个指标监视器并为 Prometheus 创建了注册表,它提供了基于文本的 Prometheus 输出。

Micrometer.java

package de.spinscale.javalin;import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.binder.jvm.JvmCompilationMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;public class Micrometer {final PrometheusMeterRegistry registry = new PrometheusMeterRegistry(new PrometheusConfig() {@Overridepublic String get(String key) {return null;}@Overridepublic String prefix() {return "javalin";}});public Micrometer() {Metrics.addRegistry(registry);new JvmGcMetrics().bindTo(Metrics.globalRegistry);new JvmHeapPressureMetrics().bindTo(Metrics.globalRegistry);new JvmThreadMetrics().bindTo(Metrics.globalRegistry);new JvmCompilationMetrics().bindTo(Metrics.globalRegistry);new JvmMemoryMetrics().bindTo(Metrics.globalRegistry);new Log4j2Metrics().bindTo(Metrics.globalRegistry);new UptimeMetrics().bindTo(Metrics.globalRegistry);new FileDescriptorMetrics().bindTo(Metrics.globalRegistry);new ProcessorMetrics().bindTo(Metrics.globalRegistry);}public String scrape() {return registry.scrape();}
}

4)重新编译你的应用程序并轮询指标端点。

curl localhost:8000/metrics -u metrics:secret

 这将返回基于行的响应,每行一个指标。 这是标准的 Prometheus 格式。

安装和配置 Metricbeat

要将指标发送到 Elasticsearch,需要 Metricbeat。 要下载并安装 Metricbeat,请使用适用于你系统的命令。我们可以到 Elastic 的官方网站 Download Metricbeat • Ship Metrics to Elasticsearch | Elastic 下载和你的 Elasticsearch 同样版本的 Metricbeat。针对我的 macOS,我使用如下的命令来进行下载:

curl -L -O https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-8.5.2-darwin-x86_64.tar.gz
tar xzvf metricbeat-8.5.2-darwin-x86_64.tar.gz

在 Merticbeat 的安装根目录下,我们会发现一个叫做 metricbeat.yml 的配置文件。

$ pwd
/Users/liuxg/elastic/metricbeat-8.5.2-darwin-aarch64
$ ls
LICENSE.txt              kibana                   metricbeat_org.yml
NOTICE.txt               logs                     module
README.md                metricbeat               modules.d
data                     metricbeat.reference.yml prometheus.yml
fields.yml               metricbeat.yml

我们需要来配置这个文件。和之前的 Filebeat 的配置类似,我们采用 API key 来进行配置:

metricbeat.yml

metricbeat.config.modules:path: ${path.config}/modules.d/*.ymlreload.enabled: falsename: javalin-metrics-shipperoutput.elasticsearch:hosts: ["localhost:9200"]protocol: "https"# Authentication credentials - either API key or username/password.api_key: "xZ5uyIQBVVocAV-RwzpW:Szm88RvESbm88Bmk0SYFGQ"ssl.certificate_authorities: ["/Users/liuxg/elastic/elasticsearch-8.5.2/config/certs/http_ca.crt"]processors:- add_host_metadata: ~- add_cloud_metadata: ~- add_docker_metadata: ~- add_kubernetes_metadata: ~

在上面,我们使用和 Filbeat 一样的 API key。我们可以使用如下的命令来禁止 system 模块的启用,尽管不必要。

./metricbeat modules disable system
$ ./metricbeat modules disable system
Module system is already disabled

我们需要启动 prometheus 模块。打入如下的命令:

 ./metricbeat modules enable prometheus
$ ./metricbeat modules enable prometheus
Module prometheus is already enabled

我接下来需要多 prometheus 模块进行配置。它的配资文件位于 modules.d 目录下。

vi modules.d/prometheus.yml 

prometheus.yml 

$ pwd
/Users/liuxg/elastic/metricbeat-8.5.2-darwin-aarch64
$ cat  modules.d/prometheus.yml 
- module: prometheusperiod: 10shosts: ["127.0.0.1:8000"]metrics_path: /metricsusername: "metrics"password: "secret"use_types: truerate_counters: true

经过上面的配置后,我们可以使用如下的命令来检查我们的配置是否成功:

./metricbeat test config
$ ./metricbeat test config
Config OK
./metricbeat test output
$ ./metricbeat test output
elasticsearch: https://localhost:9200...parse url... OKconnection...parse host... OKdns lookup... OKaddresses: ::1, 127.0.0.1dial up... OKTLS...security: server's certificate chain verification is enabledhandshake... OKTLS version: TLSv1.3dial up... OKtalk to server... OKversion: 8.5.2

从上面的输出中我们可以看到配置的格式以及连接到 Elasticsearch 都是成功的。我们使用如下的命令来测试 prometheus 模块:

./metricbeat test modules prometheus
$ ./metricbeat test modules prometheus
prometheus...collector...OKresult: {"@timestamp": "2022-12-01T06:29:14.806Z","event": {"dataset": "prometheus.collector","duration": 36580333,"module": "prometheus"},"metricset": {"name": "collector","period": 10000},"prometheus": {"jvm_threads_states_threads": {"value": 10},"labels": {"instance": "127.0.0.1:8000","job": "prometheus","state": "runnable"}},"service": {"address": "http://127.0.0.1:8000/metrics","type": "prometheus"}}

它表明我们的模块 prometheus 是成功的。

为了能在 Kibana 中能生产相应的 metricbeat-* index pattern,我们执行如下的命令:

./metricbeat setup
$ ./metricbeat setup
Overwriting ILM policy is disabled. Set `setup.ilm.overwrite: true` for enabling.Index setup finished.
Loading dashboards (Kibana must be running and reachable)
Loaded dashboards

接下来我们运行 Metricbeat:

sudo chown root metricbeat.yml
sudo chown root modules.d/prometheus.yml 
sudo ./metricbeat -e

注意:你将以 root 身份运行 Metricbeat,因此你需要更改配置文件的所有权,或运行 Metricbeat 指定 --strict.perms=false 。 请参阅配置文件所有权和权限。

验证 Prometheus 事件是否流入 Elasticsearch。

GET metricbeat-*/_search?filter_path=**.prometheus,hits.total
{"query": {"term": {"event.module": "prometheus"}}
}

在 Kibana 中查看 Metrics

由于这是来自我们 Javalin 应用程序的自定义数据,因此没有用于显示此数据的预定义仪表板。

让我们检查每个 log level 的日志消息数。

GET metricbeat-*/_search
{"query": {"exists": {"field": "prometheus.log4j2_events_total.counter"}}
}

我们可以通过如下的命令得到文档的个数:

GET metricbeat-*/_search
{"query": {"range": {"prometheus.log4j2_events_total.counter": {"gte": 0}}}
}

可视化日志消息的数量随时间的变化,按 log level 划分。 从 Elastic Stack 7.7 开始,有一种创建可视化的新方法,称为 Lens。

 

 

 

随着时间的推移可视化打开的文件

第二个可视化是检查我们的应用程序中打开的文件数。

由于没有人能记住所有字段名称,让我们先再次查看指标输出。

curl -s localhost:8000/metrics -u metrics:secret | grep ^process
$ curl -s localhost:8000/metrics -u metrics:secret | grep ^process
process_files_max_files 10240.0
process_start_time_seconds 1.669871554172E9
process_files_open_files 30.0
process_uptime_seconds 6995.98
process_cpu_usage 6.685723040584351E-4

让我们看一下 process_files_open_files 指标。 这应该是一个很少改变的相当静态的值。 如果你运行在 JVM 中存储数据或打开和关闭网络套接字的应用程序,则此指标会根据负载增加或减少。 对于 Web 应用程序,这是相当静态的。 让我们弄清楚为什么在我们的小型 Web 应用程序中打开了 30 个文件。

运行将在进程列表中包含你的应用程序的 jps。

$ jps
22178 Elasticsearch
17443 GradleServer
80996 Jps
17543 GradleDaemon
7754 Launcher
17930 GradleServer
18029 GradleDaemon
21006 javalin-app-all.jar
7278 
17390 gradle-language-server.jar
22096 CliToolLauncher
17459 org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar
19315 GradleDaemon
17907 gradle-language-server.jar
17556 GradleDaemon
51189 Logstash
17945 org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar
17467 GradleDaemon
17628 GradleDaemon

从上面的输出中我们可以看出来 javalin-app-all.jar 对应的 process id 值为 21006。我们使用如下的命令:

lsof -p 21006

你将看到比所有正在打开的文件更多的输出,因为一个文件也是一个正在发生的 TCP 连接。

添加一个端点以通过长时间运行的 HTTP 连接来增加打开文件的数量(每个连接也被视为一个打开的文件,因为它需要一个文件描述符),然后对其运行 wrk。我们在 App.java 中进行如下的修改:

App.java

...
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
...public static void main(String[] args) {
...final Executor executor = CompletableFuture.delayedExecutor(20, TimeUnit.SECONDS);app.get("/wait", ctx -> {CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "done", executor);ctx.result(future);});
...

每个 future 都会延迟 20 秒,这意味着单个 HTTP 请求保持打开状态 20 秒。

让我们运行一个 wrk 工作负载。

wrk -c 100 -t 20 -d 5m http://localhost:8000/wait
$ wrk -c 100 -t 20 -d 5m http://localhost:8000/wait
Running 5m test @ http://localhost:8000/wait20 threads and 100 connections

结果显示只发送了 20 个请求,考虑到处理时间,这是合理的。现在让我们在 Kibana 中使用 Lens 构建可视化。

 

使用 Infrastrucutre 应用

现在让我们看一下 Kibana 中的 Infrastructure 应用程序。 选择 Observability → Infrastructure

你只会看到来自单个 shipper 的数据。 尽管如此,当你运行多个服务时,并且能够按 Kubernetes pod 或主机对其进行分组的能力使你能够发现 CPU 或内存消耗增加的主机。

 

  

这是 Javalin 应用发出的总事件计数器的面积图。 它正在上升,因为有一个组件轮询一个端点,而该端点又会生成另一条日志消息。 更陡峭的窥探是由于发送了更多的请求。 但是,突然下降是从哪里来的呢? JVM 重启。 由于这些指标不会持久化,因此它们会在 JVM 重启时重置。 考虑到这一点,通常最好记录速率而不是计数器字段。 

检测应用程序

可观察性的第三个部分是应用程序性能管理 (APM)。 APM 设置包括一个接受数据的 APM 服务器(并且已经在我们的 Elastic Cloud 设置中运行)和一个将数据传送到服务器的代理。

代理有两个任务:检测 Java 应用程序以提取应用程序性能信息并将该数据发送到 APM 服务器。

APM 的核心思想之一是能够在整个堆栈中跟踪用户会话的流程,无论你是否有数十个微服务或单体应用来响应你的用户请求。这意味着能够在整个堆栈中标记请求。

要完全捕获用户活动,你需要在用户的浏览器中开始使用真实用户监控 (RUM),直至你的应用程序,该应用程序会向你的数据库发送 SQL 查询。

数据模型

尽管 APM 格局非常分散,但术语通常是相似的。两个最重要的术语是 Span 和 Transactions。更为详细的资料可以参考文章 “Observability:应用程序性能监控/管理(APM)实践”。

Transaction 封装了一系列 span,其中包含有关一段代码执行的信息。让我们看一下 Kibana APM 应用程序的屏幕截图。

这是一个 Spring Boot 应用程序。 UserProfileController.showProfile() 方法被调用,被标记为事务。 里面有两个跨度。 首先,使用 Elasticsearch REST 客户端向 Elasticsearch 发送请求,然后使用 Thymeleaf 呈现响应。 在这种情况下,对 Elasticsearch 的请求比渲染要快。

Java APM 代理可以自动检测特定框架。 Spring 和 Spring Boot 支持很好,上面的数据是在 Spring Boot 应用中添加 agent 创建的; 无需配置。

目前有适用于 Go、.NET、Node、Python、Ruby 和浏览器 (RUM) 的代理。 不断添加代理,因此您可能需要查看 APM 代理文档。

将 APM 代理添加到你的代码

你有两个选项可以将 Java 代理工具添加到您的应用程序中。

首先,你可以在调用 java 二进制文件时通过参数添加代理。 这样,它不会干扰应用程序的打包。 该机制在启动时检测应用程序。

首先下载代理,可以查看最新版本。

你也可以使用如下的命令来进行下载:

wget https://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent/1.34.1/elastic-apm-agent-1.34.1.jar

指定启动时的代理以及将 APM 数据发送到的配置参数。 在启动 Java 应用程序之前,让我们为在 Elastic Cloud 中运行的 APM 服务器获取一个 API 密钥。

当你检查你在 Elastic Cloud 中的部署并单击左侧的 APM 时,您将看到可以使用的 APM Server Secret Token。 你也可以从那里复制 APM 端点 URL。

java -javaagent:/path/to/elastic-apm-agent-1.34.1.jar\-Delastic.apm.service_name=javalin-app \-Delastic.apm.application_packages=de.spinscale.javalin \-Delastic.apm.server_urls=$APM_ENDPOINT_URL \-Delastic.apm.secret_token=PqWTHGtHZS2i0ZuBol \-jar build/libs/javalin-app-all.jar

针对我们的本地部署,我们可以参考之前的文章 “Observability:使用 Elastic Agent 提取应用程序跟踪 - Elastic Stack 8.0” 来安装 Elastic Agent 及 APM 集成。

我们可以通过如下的方式来安装 Elastic Agent 及 Fleet Server:

$ sudo ./elastic-agent install \
>   --fleet-server-es=https://192.168.0.3:9200 \
>   --fleet-server-service-token=AAEAAWVsYXN0aWMvZmxlZXQtc2VydmVyL3Rva2VuLTE2Njk4ODAzNjU3MjA6b29rTGZPRExUSGVwTFpHR0RxNEZfZw \
>   --fleet-server-policy=fleet-server-policy \
>   --fleet-server-es-ca-trusted-fingerprint=07b5d9d9b686daacb996df14a25ef22d2385cfd1b66f1bc5dbfb8f4e1983c64a
Password:
Elastic Agent will be installed at /Library/Elastic/Agent and will run as a service. Do you want to continue? [Y/n]:Y
{"log.level":"info","@timestamp":"2022-12-01T15:41:37.693+0800","log.origin":{"file.name":"cmd/enroll_cmd.go","file.line":403},"message":"Generating self-signed certificate for Fleet Server","ecs.version":"1.6.0"}
{"log.level":"info","@timestamp":"2022-12-01T15:41:40.893+0800","log.origin":{"file.name":"cmd/enroll_cmd.go","file.line":792},"message":"Fleet Server - Starting","ecs.version":"1.6.0"}
{"log.level":"info","@timestamp":"2022-12-01T15:41:44.898+0800","log.origin":{"file.name":"cmd/enroll_cmd.go","file.line":773},"message":"Fleet Server - Running on policy with Fleet Server integration: fleet-server-policy; missing config fleet.agent.id (expected during bootstrap process)","ecs.version":"1.6.0"}
{"log.level":"info","@timestamp":"2022-12-01T15:41:45.187+0800","log.origin":{"file.name":"cmd/enroll_cmd.go","file.line":471},"message":"Starting enrollment to URL: https://liuxgm.local:8220/","ecs.version":"1.6.0"}
{"log.level":"info","@timestamp":"2022-12-01T15:41:46.607+0800","log.origin":{"file.name":"cmd/enroll_cmd.go","file.line":273},"message":"Successfully triggered restart on running Elastic Agent.","ecs.version":"1.6.0"}
Successfully enrolled the Elastic Agent.
Elastic Agent has been successfully installed.

 

 

 

 

 

 

由于我们的 Fleet Server 及 Agents 是在同一个机器上运行的,我们选择 Existing hosts。点击上面的 Save and continue 按钮:

 

 

 

这样我们为 Fleet Server Policy 添加了一个 apm-1 的集成。 

我们接下在 terminal 中运行如下命令:

 

  java -javaagent:./elastic-apm-agent-1.34.1.jar\-Delastic.apm.service_name=javalin-app \-Delastic.apm.application_packages=de.spinscale.javalin \-Delastic.apm.server_urls=http://localhost:8200 \-Delastic.apm.secret_token=PqWTHGtHZS2i0ZuBol \-jar build/libs/javalin-app-all.jar

你现在可以继续打开 APM UI,你应该会看到流入的数据。

 

 

自动依附

如果你不想更改应用程序的启动选项,独立代理允许您附加到主机上运行的 JVM。

这需要你下载独立的 jar。 你可以在官方文档上找到链接。

要列出本地运行的 Java 应用程序,你可以运行:

java -jar /path/to/apm-agent-attach-1.34.1-standalone.jar --list

由于我通常在我的系统上运行多个 Java 应用程序,因此我指定要附加到的应用程序。 此外,请确保你已经停止了已附加代理的 Javalin 应用程序,并在没有配置附加代理的情况下启动常规 Javalin 应用程序。

java -jar /tmp/apm-agent-attach-1.33.1-standalone.jar --pid 30730 \--config service_name=javalin-app \--config application_packages=de.spinscale.javalin \--config server_urls=$APM_ENDPOINT_URL \--config secret_token=PqWTHGtHZS2i0ZuBol

上面的消息将返回如下内容:

2022-12-01 15:04:48.144  INFO Attaching the Elastic {apm-agent} to 30730
2022-12-01 15:04:49.649  INFO Done

因此,现在代理已附加到具有特殊配置的正在运行的应用程序。更多阅读请参阅 “https://elasticstack.blog.csdn.net/article/details/118481955”。

虽然前两种可能性都有效,但你也可以使用第三种方法:将 APM 代理用作直接依赖项。 这允许你在我们的应用程序中编写自定义 span 和 transaction。

程序化设置

编程设置允许你通过源代码中的一行 java 附加代理。

1)添加 java 代理依赖项。

dependencies {...implementation 'co.elastic.apm:apm-agent-attach:1.17.0'...
}

2)在我们的 main() 方法开始时检测应用程序。

我们还没有配置任何端点或 API 令牌。 虽然文档建议使用 src/main/resources/elasticapm.properties 文件,但我更喜欢使用环境变量,因为这可以防止将 API 令牌提交到你的源或合并另一个存储库。 保险库等机制允许您以这种方式管理你的秘密。

3)我们在本地项目的根目录中创建一个叫做 .env 的文件。其内容如下:

ELASTIC_APM_SERVICE_NAME=javalin-app
ELASTIC_APM_SERVER_URLS=https://APM_ENDPOINT_URL
ELASTIC_APM_SECRET_TOKEN=PqWTHGtHZS2i0ZuBol

根据我们的配置,.env 的内容如下:

$ pwd
/Users/liuxg/demos/apm/java_monitor
$ cat .env
ELASTIC_APM_SERVICE_NAME=javalin-app
ELASTIC_APM_SERVER_URLS=http://localhost:8220
ELASTIC_APM_SECRET_TOKEN=PqWTHGtHZS2i0ZuBol

4)你现在可以像以前一样运行 java 应用程序。

java -jar build/libs/javalin-app-all.jar

如果你想在你的 IDE 中运行它,你可以手动设置环境变量或搜索支持 .env 文件的插件。

稍等几分钟,让我们最后看一下 APM 应用程序。

 如你所见,这与前面显示的 Spring Boot 应用程序有很大的不同。 未列出不同的端点; 尽管包括错误,但我们可以看到每分钟的请求数。

唯一的 transaction 来自单个 servlet,这不是很有帮助。 让我们尝试通过引入自定义程序化 transaction 来解决这个问题。

定制 transactions 

1)添加另一个依赖项。

dependencies {...implementation 'co.elastic.apm:apm-agent-attach:1.17.0'implementation 'co.elastic.apm:apm-agent-api:1.17.0'...
}

2)修复 transaction 的名称以包括 HTTP 方法和请求路径:

import co.elastic.apm.api.ElasticApm;...app.before(ctx -> ElasticApm.currentTransaction().setName(ctx.method() + " " + ctx.path()));

重新启动你的应用程序并查看流入的数据。 测试几个不同的端点,尤其是抛出异常的端点和触发 404 的端点。

curl http://localhost:8000
curl http://localhost:8000/exception
curl http://localhost:8000/404

我们分别运行上面的命令几次。

 4)添加另一个端点以查看 transaction 的强大功能,该 transaction 轮询另一个 HTTP 服务。 你可能听说过 wttr.in,这是一种从中轮询天气信息的服务。 让我们实现一个将请求转发到该端点的 HTTP 代理方法。 让我们使用 Apache HTTP 客户端,这是最典型的 HTTP 客户端之一。

这是我们的新端点。

import org.apache.http.client.fluent.Request;...public static void main(String[] args) {
...app.get("/weather/:city", ctx -> {String city = ctx.pathParam("city");ctx.result(Request.Get("https://wttr.in/" + city + "?format=3").execute().returnContent().asBytes()).contentType("text/plain; charset=utf-8");});...

5)我们使用如下的命令来进行测试:

curl http://localhost:8000/weather/Beijing

$ curl http://localhost:8000/weather/Beijing
Beijing: ☀️   -2°C

让我们检查一下 APM UI。

/weather/Beijing 的事务现在包含一个 span,显示检索天气数据所花费的时间。 因为 HTTP 客户端是自动检测的,所以不需要做任何事情。 

如果该 URL 的 city 参数具有高基数,这将导致提及大量 URL 而不是通用端点。 如果你想防止这种情况发生,可以使用 ctx.matchedPath() 将每次对天气 API 的调用记录为 GET /weather/:city。 然而,这需要通过删除 app.before() 处理程序并将其替换为 app.after() 处理程序来进行一些重构。

app.after(ctx -> ElasticApm.currentTransaction().setName(ctx.method()+ " " + ctx.endpointHandlerPath()));

我们再次运行上面的请求,并再次回到 APM UI 界面。我们这次看到的是:

 

显然这次我们只看到一个 transaction:/weather/:city,而不以每个城市分别命令的 transaction。

设置 Uptime

到目前为止,我们的应用程序中有一些基本的监控功能。 我们索引日志(带跟踪),我们索引指标,我们甚至可以在我们的应用程序中查看以找出单个性能瓶颈,这要归功于 APM。 但是,仍然存在一个弱点。 到目前为止所做的一切都在应用程序中,但所有用户都是通过互联网访问应用程序的。

如何检查我们的用户是否具有我们的 APM 数据向我们建议的相同体验。 想象一下,在你的应用程序前面有一个滞后的负载均衡器,这会使你为每个请求额外花费 50 毫秒。 那将是毁灭性的。 或者 TLS 协商代价高昂。 即使这些外部事件都不是你的错,你仍然会受到影响,应该尝试减轻这些影响。 这意味着您需要先了解它们。

Uptime 不仅可以让你监控服务的可用性,还可以绘制延迟随时间变化的图表,并在 TLS 证书到期时收到通知。

设置

要将正常运行时间数据发送到 Elasticsearch,需要 Heartbeat(轮询组件)。 要下载并安装 Heartbeat,请使用适用于你系统的命令。我们可以到地址 Download Heartbeat • Uptime Monitoring & Elasticsearch | Elastic 下载适合你 Elasticsearch 的版本。针对我的 macOS,我使用如下的命令:

curl -L -O https://artifacts.elastic.co/downloads/beats/heartbeat/heartbeat-8.5.2-darwin-aarch64.tar.gz
tar xzvf heartbeat-8.5.2-darwin-aarch64.tar.gz

和之前的 Metricbeat 及 Filebeat 一样,我们可以使用同样的 API key 来进行配置。当我们解压缩 heartbeat 后,我们需要配置 heartbeat.yml 文件。

heartbeat.yml

ame: heartbeat-shipperoutput.elasticsearch:hosts: ["localhost:9200"]protocol: "https"# Authentication credentials - either API key or username/password.api_key: "xZ5uyIQBVVocAV-RwzpW:Szm88RvESbm88Bmk0SYFGQ"ssl.certificate_authorities: ["/Users/liuxg/elastic/elasticsearch-8.5.2/config/certs/http_ca.crt"]heartbeat.monitors:- type: httpid: javalin-http-appname: "Javalin Web Application"urls: ["http://localhost:8000"]check.response.status: [200]schedule: '@every 15s'- type: httpid: httpbin-getname: "httpbin GET"urls: ["https://httpbin.org/get"]check.response.status: [200]schedule: '@every 15s'- type: tcpid: javalin-tcpname: "TCP Port 8000"hosts: ["localhost:8000"]schedule: '@every 15s'processors:- add_observer_metadata:geo:name: asia-beijinglocation: "39.923423, 116.405654"

我们使用如下的命令来测试一下:

./heartbeat test config
$ ./heartbeat test config
Config OK
./heartbeat test output
$ ./heartbeat test output
elasticsearch: https://localhost:9200...parse url... OKconnection...parse host... OKdns lookup... OKaddresses: ::1, 127.0.0.1dial up... OKTLS...security: server's certificate chain verification is enabledhandshake... OKTLS version: TLSv1.3dial up... OKtalk to server... OKversion: 8.5.2

我们使用如下的命令来进行配置:

./heartbeat setup
$ ./heartbeat setup
Overwriting ILM policy is disabled. Set `setup.ilm.overwrite: true` for enabling.Index setup finished.

我们接下来使用如下的命令来启动 heartbeat:

./heartbeat -e

要查看 Uptime 应用程序,请选择 Observability → Uptime。 概述看起来像这样。

 

你可以看到监视器列表和全局概览。让我们看看其中一个警报的详细信息。单击 Javalin Web 应用程序。

您可以看到最后一次计划检查的执行情况,但每次检查的持续时间可能更有趣。你可以查看其中一项检查的延迟是否增加。

通过配置多个在全球范围内运行的 Heartbeats,你可以比较延迟并确定您需要哪个数据中心来运行你的应用程序以靠近你的用户。

监视器的持续时间在几毫秒内,因为它非常快。检查 httpbin.org 端点的监视器,你会看到更长的持续时间。在这种情况下,每个请求大约需要 1000 毫秒。这并不奇怪,因为端点不在附近,并且你需要为每个请求发起 TLS 连接,这是昂贵的。

不要低估这种监控的重要性。此外,考虑这只是一个开始,因为下一步是让合成器监视应用程序的正确行为,例如,以确保你的结帐过程始终有效。

接下我们停止运行 javalin web 应用。稍等一会儿,我们看到:

从图中,我们可以看到有两个服务的运行状态变为红色,也即它们是挂了。 

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

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

相关文章

uni-app 超详细教程(三)(从菜鸟到大佬)

本文中内容为&#xff1a; 1. 支付功能&#xff08;微信支付&#xff0c;支付宝支付&#xff09; 2. 项目打包&#xff1a;&#xff08;APP打包&#xff0c;H5打包&#xff0c;微信小程序打包&#xff09; 一&#xff0c;uni - app 的支付功能 一、微信支付 1、登录微信开…

华为云数据库GaussDB(for Cassandra)揭秘:高性能低成本是什么样的体验?

在我们的日常理念中&#xff0c;追求性价比是最为常见的&#xff0c;但是你知道购买低配置还能享受高性能、低延时、超低价的数据库有哪些吗&#xff1f;今天我们就用数据说话&#xff0c;带你深入了解GaussDB(for Cassandra)挑战高性价比&#xff01; 众所周知&#xff0c;有…

操作系统实验5:信号量的实现与应用

写在最前的总结 下面的实验内容是在完整做完实验时候补充的&#xff0c;这里先把踩过的坑记录一下。 调试总结 先在Ubuntu上模拟生产者—消费者问题。这个实验分为两大部分&#xff0c;一个是实现信号量&#xff0c;另一个是验证信号量。对于第二个&#xff0c;建议先在Ubun…

【MySQL基础】MySQL常用的图形化管理工具有那些?

目录 一、为什么要使用MySQL图形化管理工具 原因 / 目的 / 作用 二、什么是DOS窗口? 三、常见的MySQL图形化管理工具有那些&#xff1f; 四、 常见几个MySQL图形工具的介绍 Navicat SQLyog MySQL Workbench DataGrip 五、Navicat图形工具的安装与使用 第一步&#x…

学习响应式布局

针对性内容 页面设计在不同设备的显示情况布局只会使用float定位&#xff0c;而不会掌握flex不能很好的使用rem作为设计单位掌握响应式布局、弹性等常见布局 学习内容 css中媒体查询的作用和使用方法flex弹性盒子的用法rem的作用和使用方法目录 针对性内容 学习内容 Media…

[iOS]App Store Connect添加银行卡时的CNAPS代码查询

App Store Connect 协议、税务和银行业务中&#xff0c;给付费APP类型添加银行卡需要填写CNAPS代码CNAPS代码&#xff0c;其实就是联行号。 联行号又称大额行号、银联号、银行行号或CNAPS号。 银行联行号查询

Java+JSP+MySQL基于SSM的会议交接平台的设计与实现-计算机毕业设计

项目介绍 随着社会竞争压力的不断加强&#xff0c;企事业单位内部的会议都在不断的增加&#xff0c;有效的会议可以提高企事业内部的沟通&#xff0c;更好的做出符合战略目标的决策&#xff0c;但是传统的会议交接有一定的问题存在&#xff0c;首先就是必须面对面进行传达&…

matlab图像的增强

1.灰度变换增强 &#xff08;1&#xff09;图像直方图 &#xff08;2&#xff09;图像直方图的均衡化 2.频域滤波增强 &#xff08;1&#xff09;低通滤波器 &#xff08;2&#xff09;高通滤波器 &#xff08;3&#xff09;同态滤波器 3.彩色增强 &#xff08;1&#xff09;真…

.vcxproj.filters 误删后如何重建

背景&#xff1a; 今天碰到这样一种情况&#xff0c;我在删除这个VS文件夹下的.user文件时&#xff0c;不小心把.vcxproj.filters也删除了。当然为什么删.user呢&#xff0c;因为换电脑了。 删除之后&#xff0c;我发现&#xff1a;我的解决方案目录变成这样了&#xff1a; 对…

[附源码]Python计算机毕业设计SSM考试排考系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

深入理解ThreadLocal源码

1. 预备知识&#xff1a;强软弱虚引用 在Java中有四种引用的类型&#xff1a;强引用、软引用、弱引用、虚引用。 设计这四种引用的目的是可以用程序员通过代码的方式来决定对象的生命周期&#xff0c;方便GC。 强引用 强引用是程序代码中最广泛使用的引用&#xff0c;如下&a…

CSDNtop1全栈接口测试教程 jmeter接口测试,接口自动化测试【2】

延时等待&#xff08;全局性&#xff09; api 测试⽤例执⾏速度⾮常快&#xff0c;某些时候因为业务的特性想让它延迟⼏秒执⾏&#xff0c;那么这个时候就使⽤延时等待。 参数化 可以理解为&#xff1a;⼀个测试点需要多次操作&#xff0c;并且每次操作数据都是不⼀样但测试步…

最好的天线基础知识!超实用 随时查询

天线作为无线电的发射和接收设备是影响信号强度和质量的重要设备,其在移动通信领域的重要性非常关键。通过对天线选型,天线安装,天线调整从而保障基站覆盖区域的信号强度与质量。对其的 掌握程度是网规与网优工程师的技能基本要求之一。下文重点说明天线要掌握哪些方面及其原理…

【软件安装】Linux中RabbitMQ的安装

① 本篇是基于Linux操作系统中的安装&#xff0c;故先准备一个干净的Linux操作系统。本文中所有的操作基于CentOS8进行安装演示&#xff1b; ② 接下来的演示文本中&#xff0c;红色字体为操作步骤&#xff0c;黑色字体为解释说明&#xff1b; ③ 确保Linux系统中已经安装好必…

【python】 int、float、double与16进制字符串的互相转换

import structdef intToHex(num): # int转16进制return hex(num)[2:].upper()def hexToInt(hexString): # 16进制转intreturn int(hexString, 16)def floatToHex(floatValue): # float转16进制return struct.pack(>f, floatValue).hex().upper()def hexToFloat(hexString…

Lactoferrin-PEG-MTX/Paclitaxel 乳铁蛋白-聚乙二醇-甲氨蝶呤/紫杉醇

产品名称&#xff1a;乳铁蛋白-聚乙二醇-甲氨蝶呤 英文名称&#xff1a;Lactoferrin-PEG-MTX 纯度&#xff1a;95% 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 外观:固体或粘性液体&#xff0c;取决于分子量 PEG分子量可选&#xff1a;350、550、750、1k、2k、…

全球领先飞瞳引擎™云服务全球两千+企业用户,集装箱识别集装箱箱况残损检测,正常箱号识别率99.98%以上,箱信息识别及铅封识别免费

全球领先飞瞳引擎™AI集装箱识别检测云服务全球两千企业用户&#xff0c;集装箱识别集装箱箱况残损检测&#xff0c;正常箱号识别率99.98%以上&#xff0c;箱信息识别及铅封识别免费。CIMCAI中集飞瞳是全球应用落地最广&#xff0c;规模最大&#xff0c;最先进的的港航人工智能…

操作系统学习笔记(Ⅳ):文件

目录 1 文件管理 1.1 初识文件管理 1.文件属性 2.文件数据组织 3.向上功能 1.2 文件逻辑结构 1.无结构文件 2.有结构文件 3.顺序文件 4.索引文件 5.索引顺序文件 1.3 文件目录 1.文件控制块 2.目录结构 3.索引结点 1.4 文件物理结构 1.连续分配 2.链接分配 …

自定义表单、自定义流程、自定义页面、自定义报表应用开发平台

真正的大师,永远都怀着一颗学徒的心&#xff01; 一、项目简介 Java开发框架&#xff0c;自定义表单、自定义页面、自定义流程、自定义报表应用开发平台 二、实现功能 支持系统文件在线管理 支持代码在线编辑 支持URL 路由 支持黑白名单 支持定时任务 支持在线监控 支持…

Charles抓取接口报文并修改各种参数信息调试

1.首先介绍Charles面板 图上顶部工具栏常用介绍&#xff1a; 1是清除按钮&#xff1a;点击后将清空左侧抓取的接口列表&#xff0c;如果接口太多&#xff0c;可以点击该按钮清空列表&#xff0c;重新发起请求&#xff0c;一目了然&#xff1b; 2.是停止按钮&#xff1a;点击该按…