写点什么

基于 OpenTelemetry 实现 Java 微服务调用链跟踪

  • 2024-02-19
    广东
  • 本文字数:3341 字

    阅读完需:约 11 分钟

基于OpenTelemetry实现Java微服务调用链跟踪

本文分享自华为云社区《基于OpenTelemetry实现Java微服务调用链跟踪》,作者: 可以交个朋友。

一 背景


随着业务的发展,所有的系统都会走向微服务化体系,微服务进行拆分后,服务的依赖关系变得复杂,如果出现了错误和异常,定位的过程将会变得复杂,一个请求可能需要调用很多个服务,所以微服务架构中,分布式链路跟踪的实现至关重要,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每个请求的步骤清晰可见。如何快速查询整个请求链路上的信息并呈现出来是解决排查问题复杂度的根本方法。


二 简介


Java 是世界上最流行的编程语言之一,很多大小项目都是通过 Java 进行微服务的开发来实现。本篇博客将以 springboot 微服务为例,通过使用 opentelemetry-java SDK 进行自动埋点以代码无侵入的方式实现微服务的分布式跟踪能力。

三 实践演示


demo 项目一共 3 个 service:foo-svc、bar-svc 、loo-svc 。项目源码可前往:https://github.com/HFfleming/springboot-trace-demo/tree/autoconfigure


访问效果如下:


3.1 前提条件


已创建 k8s 集群,可使用 CCE 集群平台作为基础环境。


k8s 集群中已安装 opentelemetry-collector 组件


k8s 集群中已安装 jaeger 作为分布式跟踪数据展示的平台

3.2 集成 opentelemetry-java-instrumentation


OpenTelemetry 提供了 Java agent(opentelemetry-java-instrumentation)。当附加到应用程序中时,它会修改各种流行库和框架的字节码以捕获遥测数据。可以以多种格式导出遥测数据。还可以通过命令行参数或环境变量配置代理和导出器。最终结果是无需更改代码即可从 Java 应用程序收集遥测数据。


下载 otel-java jar 包并添加到容器镜像中


前往官方仓库 https://github.com/open-telemetry/opentelemetry-java-instrumentation 下载 opentelemetry-javaagent.jar


通过环境变量配置 java agent 和 otlp 导出器


  • 通过环境变量的形式配置 java agent:ENV JAVA_TOOL_OPTIONS="-javaagent:/usr/app/opentelemetry-javaagent.jar"

  • 服务名称: ENV OTEL_SERVICE_NAME="foo-svc"

  • 使用 otlp 协议的导出器:ENV OTEL_TRACES_EXPORTER="otlp"

  • 关闭 java agent 的指标 otlp 导出器: ENV OTEL_METRICS_EXPORTER="none"

  • 关闭 java agent 的日志 otlp 导出器: ENV OTEL_LOGS_EXPORTER="none"

  • 指定 OTLP 导出器的端点,跨 ns 的场景下建议写上 otel 的 ns:ENV OTEL_EXPORTER_OTLP_ENDPOINT="http://opentelemetry-collector.tracing.svc.cluster.local:4317"

    除了环境变量的形式,也可通过 jvm 参数形式进行 agent 和导出器的配置。详细配置或者欲开启更多导出信息可参考: https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure


容器镜像制作


建议重新制作镜像,将 opentelemetry-javaagent 等 otlp 基础配置打包在镜像中。后续如果有变动,也可通过 deployment 中 env 字段进行修改覆盖。


镜像 Dockerfile 文件可参照如下:


#基于官方的Maven镜像FROM maven:3.8.7-openjdk-18-slim AS build
#将本地代码复制到Docker容器中的 /usr/src/app 目录下COPY src /usr/src/foo-app/srcCOPY pom.xml /usr/src/foo-appCOPY opentelemetry-javaagent.jar /usr/src/foo-app
# 在容器的 /usr/src//foo-app 目录下,运行mvn clean package 命令,构建项目RUN mvn -f /usr/src/foo-app/pom.xml clean package
# 使用官方的openjdk 镜像作为基础镜像FROM openjdk:19-jdk-slim
# 将打包生成的jar文件复制到容器中COPY --from=build /usr/src/foo-app/target/*.jar /usr/app/foo-app.jarCOPY --from=build /usr/src/foo-app/opentelemetry-javaagent.jar /usr/app/opentelemetry-javaagent.jar
# 声明服务运行在8080端口EXPOSE 8080
# 通过环境变量的形式配置java agent并且通过环境变量传递配置属性ENV JAVA_TOOL_OPTIONS="-javaagent:/usr/app/opentelemetry-javaagent.jar"# 服务的k8s servicenameENV OTEL_SERVICE_NAME="foo-svc"# 使用的是otlp协议的导出器ENV OTEL_TRACES_EXPORTER="otlp"# 关闭java agent的指标 otlp导出器ENV OTEL_METRICS_EXPORTER="none"## 关闭java agent的日志 otlp导出器ENV OTEL_LOGS_EXPORTER="none"# 指定OTLP导出器的端点,跨ns的场景下建议写上otel的nsENV OTEL_EXPORTER_OTLP_ENDPOINT="http://opentelemetry-collector.tracing.svc.cluster.local:4317"
#指定docker容器的启动命令ENTRYPOINT ["java", "-jar","/usr/app/foo-app.jar"]
复制代码


镜像推送至镜像仓库,可使用 SWR 容器镜像仓库


docker build 构建完镜像后,然后 docker push 至镜像仓库。


本人 demo 项目镜像如下,可供读者调试使用:


foo-svc: swr.cn-north-4.myhuaweicloud.com/k8s-solution/foo-svc:v2

bar-svc: swr.cn-north-4.myhuaweicloud.com/k8s-solution/bar-svc:v2

loo-svc: swr.cn-north-4.myhuaweicloud.com/k8s-solution/loo-svc:v2


在 k8s 集群中部署 demo 项目



其中 loadgenerator 服务是个客户端工具用于访问 demo 项目。访问信息如下:



相比之前没有集成 opentelemetry-javaagent.jar ,访问信息请求头多了 traceparent 信息,很明显该信息就是分布式跟踪所需要使用到的

3.3 OpenTelemetry 配置遥测数据的接受和导出


在上述环境变量中,通过 otlp-grpc 协议进行 java 微服务遥测数据导出的。所以在 opentelemetry-collector 中的 receivers 接收器配置中需要配置 otlp grpc 规则进行数据的接受:


receivers:  otlp:    protocols:      grpc:        endpoint: ${env:MY_POD_IP}:4317
复制代码


otel 接受到数据后,需要将数据处理后进行导出。导出后端可以是 jaeger,通过 jaeger 进行分布式跟踪数据的展示,需要需要在 opentelemery-collector 中配置 exporter 导出器


exporters:  debug: {}  #导出器配置log,可记录导出行为  otlp:    endpoint: jaeger-collector.hu.svc.cluster.local:4317 #jaeger的otlp-grpc端口    tls:      insecure: true
复制代码


需要注意此处导出器后端 jaeger 使用的协议为 otlp,如果 jaeger-collector service 未配置该端口,则会导出失败,建议检查 jaeger 相关 service 的配置。


- name: otlp-grpc  port: 4317  protocol: TCP  targetPort: 4317
复制代码


通过 pipeline 启用 otel 采集器中配置的各种组件。上面配置了接收器和导出器,如果不在 pipeline 中声明,则不会启用该组件。启用方式参考:


service: # 用于根据接收器、处理器、导出器和扩展部分中的配置来配置收集器中启用的组件  extensions:  - health_check  pipelines:    traces:      exporters:      - debug      - otlp      processors:      - memory_limiter      - batch      receivers:      - otlp
复制代码


完整配置参考如下,这些配置以 configmap 形式挂载到 otel-collector 容器中使用。


apiVersion: v1kind: ConfigMapmetadata:  name: opentelemetry-collector  namespace: tracingdata:  relay: |    exporters:      debug: {}      otlp:        endpoint: jaeger-collector.hu.svc.cluster.local:4317        tls:          insecure: true    extensions:      health_check:        endpoint: ${env:MY_POD_IP}:13133
processors: batch: {} memory_limiter: check_interval: 5s limit_percentage: 80 spike_limit_percentage: 25
receivers: otlp: protocols: grpc: endpoint: ${env:MY_POD_IP}:4317
service: extensions: - health_check pipelines: traces: exporters: - debug - otlp processors: - memory_limiter - batch receivers: - otlp
telemetry: metrics: address: ${env:MY_POD_IP}:8888
复制代码


配置更新后,重启 otel-collector 容器。查看 otel 容器日志可以看到 otel 已经以配置的规则进行工作。


3.4 Jaeger 查看调用链跟踪数据


访问 jaeger UI,UI 端口为 16686。可以看到 jaeger 已经接收到 trace 信息,目前已有 4 条 trace,每条 trace 均有 8 个 span 信息。



查看详细 span 信息,不仅可以看到服务级别的调用,还能看到方法级别的调用,以及方法级别的耗时。



点击关注,第一时间了解华为云新鲜技术~

发布于: 刚刚阅读数: 4
用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

生于云,长于云,让开发者成为决定性力量

评论

发布
暂无评论
基于OpenTelemetry实现Java微服务调用链跟踪_Java_华为云开发者联盟_InfoQ写作社区