基於OpenTelemetry實現Java微服務調用鏈跟蹤

本文分享自華爲雲社區《基於OpenTelemetry實現Java微服務調用鏈跟蹤》,作者: 可以交個朋友。

一 背景

隨着業務的發展,所有的系統都會走向微服務化體系,微服務進行拆分後,服務的依賴關係變得複雜,如果出現了錯誤和異常,定位的過程將會變得複雜,一個請求可能需要調用很多個服務,所以微服務架構中,分佈式鏈路跟蹤的實現至關重要,去跟進一個請求到底有哪些服務參與,參與的順序又是怎樣的,從而達到每個請求的步驟清晰可見。如何快速查詢整個請求鏈路上的信息並呈現出來是解決排查問題複雜度的根本方法。

image.png

二 簡介

Java 是世界上最流行的編程語言之一,很多大小項目都是通過Java進行微服務的開發來實現。
本篇博客將以springboot微服務爲例,通過使用opentelemetry-java SDK 進行自動埋點以代碼無侵入的方式實現微服務的分佈式跟蹤能力。

三 實踐演示

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

訪問效果如下:

image.png

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項目

image.png

其中loadgenerator服務是個客戶端工具用於訪問demo項目。訪問信息如下:

image.png

相比之前沒有集成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: 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已經以配置的規則進行工作。

image.png

3.4 Jaeger查看調用鏈跟蹤數據

訪問jaeger UI,UI端口爲16686。可以看到jaeger已經接收到trace信息,目前已有4條trace,每條trace均有8個span信息。

image.png

查看詳細span信息,不僅可以看到服務級別的調用,還能看到方法級別的調用,以及方法級別的耗時。

image.png

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章