打造Java可观测性的5个关键步骤

本文涉及的产品
EMR Serverless StarRocks,5000CU*H 48000GB*H
应用实时监控服务ARMS - 应用监控,每月50GB免费额度
可观测链路 OpenTelemetry 版,每月50GB免费额度
简介: 伴随云原生和微服务的普及,可观测性设计基本上是作为一个线上业务服务必备的基础能力。这篇文章我将介绍天罡项目围绕可观测性的三大支柱:日志,指标以及链路追踪所做的可观测性设计和实践,以及项目中实施可观测性的5个关键步骤。

作者:砧木 阿里云智能-基础产品事业部-块存储-平台服务研发

伴随云原生和微服务的普及,可观测性设计基本上是作为一个线上业务服务必备的基础能力。这篇文章我将介绍天罡项目围绕可观测性的三大支柱:日志,指标以及链路追踪所做的可观测性设计和实践,以及项目中实施可观测性的5个关键步骤。


本文中提供的例子,适用于Spring Boot 2.x版本


步骤一: 健康检查,还活着吗?

首先我们需要知道我们的应用实例是否还活着, 关于活着这件事情。 又可以细分为进程还在不在,如果进程在那应用实例是否能对外提供服务。 所以关于健康检查这件事情就可以分为:存活态(liveness)和就绪态(readiness)。就绪态又包含,应用自身服务的就绪以及必要依赖的外部组件的就绪状态。actuator内置了常见的如datasource, redis等常见外部依赖的依赖检查,对于未内置支持的外部依赖。可以通过自定义Healthlndicators的方式接入。

curl -Li http://localhost:8080/actuator/health
HTTP/1.1 200 
Content-Type: application/vnd.spring-boot.actuator.v3+json
Transfer-Encoding: chunked
Date: Fri, 05 Nov 2021 03:37:54 GMT
{"status":"UP","components":{"db":{"status":"UP","details":{"database":"MySQL","validationQuery":"isValid()"}},"diskSpace":{"status":"UP","details":{"total":494384795648,"free":372947439616,"threshold":10485760,"exists":true}},"livenessState":{"status":"UP"},"ping":{"status":"UP"},"readinessState":{"status":"UP"}}}%

通过健康检查接口,无论是容器还是非容器环境,可以配合负载均衡或者kubernetes的探针,都可以实现对不可用实例流量的自动隔离。抛开spring boot框架来说,健康检查接口应该能够支持开发者或这外部系统快速判断存活与就绪状态。 没有涵盖到这两部分的健康检查都是耍流氓。此外这些数据还可以通过HTTP采集插件采集到SLS来设置告警。

步骤二: 监控指标,活得还好吗?

其次,当应用满足了活着这个基本条件以后,我们就需要知道我们的应用到底活着怎么样, 好不好,有没有潜在风险。对人来说如何评估你的活的好不好,就的看你所处的社会大环境好不好,家里还有没有余粮,以及你自己身体的机能状态。对应用也一样,以Java为例,首先是应用所在环境主机或者容器的物理资源情况。CPU,内存,磁盘,网络这几大基础件,其次是JVM相关的运行指标,最后再是应用自身的业务相关指标。


对于主机监控,天罡使用了Logtail内置的主机监控能力,并存储到SLS的时序存储中。除了主机监控以外,JVM以及应用业务指标监控则采用了prometheus规范。通过集成micrometer,默认即可输出JVM的相关监控指标。而对于spring-boot不支持的监控指标,如druid的数据库连接池状态,http client连接池的状态则通过自定义Metrics的方式进行统一采集。而为了让各个服务有统一的监控指标体系,这些常用组件的metrics则通过spring-starter二方库的形式进行管理,对于已有服务和新的服务可以无缝集成统一的监控指标体系。而对于业务类型的指标,自定义Metrics的方式同样适用。

curl -Li http://localhost:8080/actuator/prometheus
HTTP/1.1 200
Content-Type: text/plain; version=0.0.4;charset=utf-8
Content-Length: 13244
Date: Fri, 05 Nov 2021 06:32:31 GMT
# HELP jdbc_connections_active Current number of active connections that have been allocated from the data source.
# TYPE jdbc_connections_active gauge
jdbc_connections_active{app="aliyun-center",name="dataSource",source="30.1.1.1",} 0.0
# HELP jvm_gc_max_data_size_bytes Max size of long-lived heap memory pool
# TYPE jvm_gc_max_data_size_bytes gauge
jvm_gc_max_data_size_bytes{app="aliyun-center",source="30.1.1.1",} 2.863661056E9
# HELP jdbc_connections_max Maximum number of active connections that can be allocated at the same time.
# TYPE jdbc_connections_max gauge
jdbc_connections_max{app="aliyun-center",name="dataSource",source="30.1.1.1",} 8.0
# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process
# TYPE process_cpu_usage gauge
process_cpu_usage{app="aliyun-center",source="30.1.1.1",} 0.0012296864771536287
# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time
# TYPE system_load_average_1m gauge
system_load_average_1m{app="aliyun-center",source="30.1.1.1",} 3.7958984375

而对于应用监控指标的采集和存储,新版的Logtail组件内置了prometheus监控指标的采集能力,操作参考通过Logtail插件接入Prometheus监控数据

步骤三: 链路追踪,有迹可循

不过即使注意了日常健康保养,小灾小病也不可避免,假如你有点不舒服,表现出来可能是脑袋疼,但是实际上可能是一连串连锁反应后的结果。 链路追踪就是为了让我们能够在不舒服的时候能够以最快的速度排出杂音,迅速缩小问题范围。


在天罡中,我们采用skywalking agent采集上报链路数据,具体安装和配置可以参考:通过SkyWalking上报Java应用数据

skywalking会为每一个请求生成一个唯一的trace id. 通过trace id可以查看整个完整的调用链路,并且可以快速确定问题实际的产生位置。


通常来说云产品的所有调用都是通过POP API进行接入,用户反馈问题时通常会提供报错时反馈的RequestId信息。而如何通过RequestId快速查找调用链路,或者通过调用链路找到RequestId. 这就是接下来日志相关性所要解决的问题。

步骤四: 日志相关性,有理可循

最后我们的应用是一个时刻运行的系统,这个系统每时每秒都在以日志的形式记录着它的运行状态和运行时信息,当发现问题时,我们能够根据这些运行记录定位到根因,为了能够找到真正有用的信息。 这时就需要我们的日志具有相关性,能够关联到某个特定的事件或者流程,因此搜集日志是其一(通常是外部运维环境决定),能够找到相关性日志则是更重要的点。


首先是RequestId, 借用logback的MDC机制,我们只需要在适当的位置,在MDC中注入request id.即可确保当前请求所产生的日志具有固定的标识:

@OverridepublicbooleanpreHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler)
throwsException {
StringrequestId=request.getHeader(TBS_REQUEST_ID);
if (!Strings.isNullOrEmpty(requestId)) {
MDC.put("requestID", requestId);
    }
returntrue;
}


而skywalking本身内置了与logback的集成,可以自动往MDC中注入traceId信息。引入依赖即可:

<dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-logback-1.x</artifactId><version>8.5.0</version></dependency>


并在logback配置中,打印即可:

<propertyname="FILE_LOG_PATTERN"value="[%X{tid}] %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%X{requestID}] %logger{36}:%line [%thread] - %msg%n"/><!--省略的其--><encoderclass="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layoutclass="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"><pattern>${LOG_PATTERN}</pattern></layout></encoder>


通过日志相关性配置后,我们既可以通过主动发现慢请求链路,通过trace id找到相关的日志记录,进行主动的问题分析。 也可以在线上问题排查是根据RequestId找到调用链路,定界问题,并找到相关的日志进行分析。

链路关联日志

日志关联链路


步骤五: 可视化,看见变化

到目前为止,关于可观测性,我们在应用中内置了健康检查接口,prometheus的metrics接口以及skywalking agent。 同时通过日志相关性策略,将业务,链路进行关联,帮助我们快速定位和分析问题。 那可观测性最后的一步当然是构建我们的可视化Dashboard了。而SLS时序存储提供标准的Prometheus接口,因此我们可以直接将SLS时序存储作为Prometheus数据源加入到Grafana中,并通过 Grafana进行可视化。

Dashboard本身也应该是持续迭代和演进的,因此本着万物皆可as code的原则,我们使用git来管理我们的可视化大盘。

.
├── README.md
├── docker-compose.yaml
└── grafana
    ├── config.monitoring
    ├── dashboards
    │   ├── app
    │   │   └── jvm-micrometer.json # jvm监控打包
    │   └── server
    │       └── hosts.json # 主机监控大盘
    └── provisioning # 初始化
        ├── dashboards
        │   └── dashboard.yaml # dashboard配置
        └── datasources
            └── datasource.yaml # 数据源配置


小结

可观测性,有如一把钥匙,让我们打开了应用的黑盒子,让我们可以时刻了解我们应用自身的运行情况。同时通过外在表现(监控指标)与内部状态(链路和日志)帮助我们更快的定位和分析问题。

目录
相关文章
|
9月前
|
设计模式 算法 Java
JAVA设计模式13:模版方法模式,将一些步骤延迟到子类中实现
JAVA设计模式13:模版方法模式,将一些步骤延迟到子类中实现
|
10月前
|
安全 Java PHP
PHP/JAVA交易所系统开发(成熟案例)丨需求步骤丨指南详细丨方案逻辑丨逻辑教程丨源码功能
An exchange refers to an institution or platform that provides a centralized market for buying and selling transactions, where participants can trade various assets, such as securities, commodities, cryptocurrencies, etc. Exchanges provide market infrastructure and rules to facilitate compliant, saf
|
1月前
|
存储 Java API
Java——Stream流(1/2):Stream流入门、Stream流的创建(认识Stream、体验Stream流、Stream流的使用步骤、获取Stream流的方法)
Java——Stream流(1/2):Stream流入门、Stream流的创建(认识Stream、体验Stream流、Stream流的使用步骤、获取Stream流的方法)
27 0
|
2月前
|
Oracle 安全 Java
JAVA用Mail发送API的方法步骤教程
使用Java和Mail发送API实现自动化邮件发送,提高效率。步骤包括:1. 安装JDK并配置JAVA_HOME,2. 添加JavaMail库(可通过Maven或官网下载)。配置邮件发送涉及邮件服务器地址、端口和认证信息。创建邮件会话、邮件消息对象,然后使用Transport发送。示例代码展示完整流程。注意处理认证失败、连接问题和邮件发送失败等常见问题。
|
2月前
|
Java
在Java中,定义一个接口的步骤如下
【4月更文挑战第6天】在Java中,定义一个接口的步骤如下
17 1
|
2月前
|
Java API Maven
email api java编辑方法?一文教你学会配置步骤
在Java开发中,Email API是简化邮件功能的关键工具。本文指导如何配置和使用Email API Java:首先,在项目中添加javax.mail-api和javax.mail依赖;接着,配置SMTP服务器和端口;然后,创建邮件,设定收件人、发件人、主题和正文;最后,使用Transport.send()发送邮件。借助Email API Java,可为应用添加高效邮件功能。
|
9月前
|
算法 IDE Java
学习Java可以按照以下步骤进行
学习Java可以按照以下步骤进行
44 1
|
2月前
|
XML Java 数据格式
使用java解析XML文件的步骤
使用java解析XML文件的步骤
|
11月前
java202304java学习笔记第六十天-ssm-spring配置文件-数据源开发步骤
java202304java学习笔记第六十天-ssm-spring配置文件-数据源开发步骤
27 0
|
2月前
|
前端开发 Java jenkins
Java开发中的工作流程和步骤
Java开发中的工作流程和步骤