本文分享自華為雲社群《基於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資訊,不僅可以看到服務級別的呼叫,還能看到方法級別的呼叫,以及方法級別的耗時。
點選關注,第一時間瞭解華為雲新鮮技術~