开发者社区> 元乙> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

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

简介: 伴随云原生和微服务的普及,可观测性设计基本上是作为一个线上业务服务必备的基础能力。这篇文章我将介绍天罡项目围绕可观测性的三大支柱:日志,指标以及链路追踪所做的可观测性设计和实践,以及项目中实施可观测性的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应用数据
image
skywalking会为每一个请求生成一个唯一的trace id. 通过trace id可以查看整个完整的调用链路,并且可以快速确定问题实际的产生位置。


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

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

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


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

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
    String requestId = request.getHeader(TBS_REQUEST_ID);
    if (!Strings.isNullOrEmpty(requestId)) {
        MDC.put("requestID", requestId);
    }
    return true;
}


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

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


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

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


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

链路关联日志

image

日志关联链路


image

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

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

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 # 数据源配置


小结

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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
一次性把Java的四种引用说清楚!
前几天在CodeReview的时候,看到了一个用WeakHashMap的代码,进而聊到了WeakReference,再聊到Java四种引用类型。
28 0
Java——JDBC连接数据库(步骤详解!!!)
Java——JDBC连接数据库(步骤详解!!!)
125 0
IWa
浅谈活动规则与现状——《我的Java打怪日记》
针对这个举办这个活动后,目前开发者社区的现状,自己简单的分析一下哈。 仅表达下自己的见解,如有不对欢迎评论。
134 0
突破Java面试(27)-如何保证缓存与数据库的数据一致性
1 面试题 如何保证缓存与数据库的双写一致性? 2 考点分析 你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 3 详解 一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况,最好不要做这个方案 读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况 串行化之后,就会导致系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的一个请求。
8513 0
给女友讲讲设计模式——工厂模式(JAVA实例)1
前言 接触Java已经有很长的一段时间了,但是总是一味的去探索新的技术,学着不断的去堆砌代码,最后终于发现自己写的代码是没有灵魂的,有些时候只是单纯的实现了功能,但是代码的可读性和可维护性并不是那么好,所以开始慢慢的学习和接触设计模式。
865 0
+关注
元乙
阿里云日志服务数据采集客户端负责人,目前采集客户端logtail在集团百万规模部署,每天采集上万应用数PB数据,经历多次双11双12考验。
64
文章
1
问答
来源圈子
更多
阿里云存储基于飞天盘古2.0分布式存储系统,产品包括对象存储OSS、块存储Block Storage、共享文件存储NAS、表格存储、日志存储与分析、归档存储及混合云存储等,充分满足用户数据存储和迁移上云需求,连续三年跻身全球云存储魔力象限四强。
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载