基于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/src
COPY pom.xml /usr/src/foo-app
COPY 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.jar
COPY --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 servicename
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" #指定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项目。访问信息如下:

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: v1
kind: ConfigMap
metadata:
name: opentelemetry-collector
namespace: tracing
data:
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信息,不仅可以看到服务级别的调用,还能看到方法级别的调用,以及方法级别的耗时。

基于OpenTelemetry实现Java微服务调用链跟踪的更多相关文章
- 第四模块 :微服务调用链监控CAT架构和实践
采样率:每一个请求为都进行记录,或者100次请求为记录50次 各个开源框架都满足opentracing的标准,只要使用opentracing标准埋点的客户端,可以使用不同的客户端去展示,opentra ...
- 微服务架构 | 10.1 使用 Sleuth 追踪服务调用链
目录 前言 1. Sleuth 基础知识 1.1 Sleuth 原理 2. 在服务中使用 Sleuth 追踪 2.1 引入 pom.xml 依赖文件 2.2 查看日志信息 最后 前言 参考资料: &l ...
- 多云架构下,JAVA微服务技术选型实例解析
[摘要] 本文介绍了基于开源自建和适配云厂商开发框架两种构建多云架构的思路,以及这些思路的优缺点. 微服务生态 微服务生态本质上是一种微服务架构模式的实现,包括微服务开发SDK,以及微服务基础设施. ...
- 基于Spring Cloud的微服务入门教程
(本教程的原地址发布在本人的简书上:http://www.jianshu.com/p/947d57d042e7,若各位看官有什么问题或不同看法请在这里或简书留言,谢谢!) 本人也是前段时间才开始接触S ...
- 干货|基于 Spring Cloud 的微服务落地
转自 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的 ...
- 基于Spring Cloud的微服务落地
微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的微服务 ...
- Java微服务框架一览
引言:本文首先简单介绍了微服务的概念以及使用微服务所能带来的优势,然后结合实例介绍了几个常见的Java微服务框架. 微服务在开发领域的应用越来越广泛,因为开发人员致力于创建更大.更复杂的应用程序,而这 ...
- Java微服务(二):服务消费者与提供者搭建
本文接着上一篇写的<Java微服务(一):dubbo-admin控制台的使用>,上篇文章介绍了docker,zookeeper环境的安装,并参考dubbo官网演示了dubbo-admin控 ...
- Java微服务(二):负载均衡、序列化、熔断
本文接着上一篇写的<Java微服务(二):服务消费者与提供者搭建>,上一篇文章主要讲述了消费者与服务者的搭建与简单的实现.其中重点需要注意配置文件中的几个坑. 本章节介绍一些零散的内容:服 ...
- 智能家居巨头 Aqara 基于 KubeSphere 打造物联网微服务平台
背景 从传统运维到容器化的 Docker Swarm 编排,从 Docker Swarm 转向 Kubernetes,然后在 Kubernetes 运行 SpringCloud 微服务全家桶,到最终拥 ...
随机推荐
- Java 使用二分查找快速定位元素位置
转载请注明出处: 快速定位 一个有序数列中 某一个元素的位置: 共有三种思路: 第一种:使用 for 循环,匹配元素值 与循环变量的值是否相等,相等则循环变量时的 i 则为元素位置 第二种:使用 二分 ...
- C++中不支持strdup(),使用_strdup()
1.问题 C4996 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conf ...
- 为什么 sort() 中的 return a-b 可以决定升序
arr.sort( function(a,b){ return a-b; } ) 千万不要理解成 a 减 b 其实它代表的是26个字母中的 a 和 b b 比 a 大,所以 a - b 就是升序,写成 ...
- java - ArrayList的使用
package list; import java.util.ArrayList; import demo.Hero; public class ListTs { public static void ...
- [转帖]信创从芯开始,CPU实现国产有多难?
https://www.eet-china.com/mp/a213516.html 数字底座的"底座"--CPU,决定信创底层逻辑的关键.CPU 是信息产业中最基础的核心部件,指令 ...
- [转帖]【Python】计算程序运行时间的方法总结
一.第一种方法 利用time包: import time def test(): start_time = time.time() # 记录程序开始运行时间 s = 0 for i in range( ...
- [转帖]Linux磁盘I/O(二):使用vm.dirty_ratio和vm.dirty_background_ratio优化磁盘性能
文件缓存是一项重要的性能改进,在大多数情况下,读缓存在绝大多数情况下是有益无害的(程序可以直接从RAM中读取数据).写缓存比较复杂,Linux内核将磁盘写入缓存,过段时间再异步将它们刷新到磁盘.这对加 ...
- [转帖]MIPS和ARM授权差异引起的龙芯路线变迁
https://zhuanlan.zhihu.com/p/99807721 一.MIPS和ARM授权的异同 MIPS授权和ARM授权都分为处理器核授权(Core License)和架构授权(Archi ...
- redis 设置密码之后,通过命令行一键刷新的办法
之前以为很麻烦 发现还是自己太low了. redis-cli -a Test1127 flushall
- STM32CubeMX教程25 PWR 电源管理 - 睡眠、停止和待机模式
1.准备材料 开发板(正点原子stm32f407探索者开发板V2.4) STM32CubeMX软件(Version 6.10.0) 野火DAP仿真器 keil µVision5 IDE(MDK-Arm ...