OpenTelemetry 實踐指南:歷史、架構與基本概念

crossoverJie發表於2024-06-14

背景

之前陸續寫過一些和 OpenTelemetry 相關的文章:

  • 實戰:如何優雅的從 Skywalking 切換到 OpenTelemetry
  • 實戰:如何編寫一個 OpenTelemetry Extensions
  • 從一個 JDK21+OpenTelemetry 不相容的問題講起

這些內容的前提是最好有一些 OpenTelemetry 的背景知識,看起來就不會那麼枯燥,為此這篇文章就來做一個入門科普,方便一些對 OpenTelemetry 不是那麼熟的朋友快速掌握一些 OpenTelemetry 的基本概念。


歷史發展

早在 OpenTelemetry 誕生之前可觀測性這個概念就一直存在了,我記得我最早接觸到這個概念是在 16 年當時的公司所使用的一個產品:pinpoint

現如今這個專案依然比較活躍。


依然還記得當時透過它可以直接看到專案呼叫的拓撲圖,在時間座標上框出高延遲的點就能列出這些請求,同時還能檢視此時的執行日誌。

這樣強大的功能對於一個剛工作一年的小白來說衝擊力實屬太大了一點。

後來才瞭解到 pinpoint 屬於 APM 這類產品,類似的產品還有:

  • Apache SkyWalking
  • 美團的 CAT 等

他們都是可以用於效能分析和鏈路追蹤的產品,到後來公司的運維層面也接入過 Zabbix、open-falcon 之類的產品:

17之後全面切換到 spring boot 時,也用過社群提供的 spring-boot-admin 專案:


這就是一個簡單的可以監控 spring boot 應用的產品,用於展示 JVM 指標,或者自己也可以定義一些健康指標。


再之後進入雲原生體系後可觀測性的技術棧稍有變化。

日誌使用 Sidecar 代理的方式透過 Agent 將資料寫入 ElasticSearch 中。
具體日誌採集方式可以參考之前的文章:

  • 在 kubernetes 環境下如何採集日誌

而鏈路追蹤則是使用的 skywalking,在 trace 這個領域 skywalking 還是非常受大家喜愛的。

不過最近也從 skywalking 切換到了我們本文所講到的 OpenTelemetry,具體可以看之前的文章:

  • 實戰:如何優雅的從 Skywalking 切換到 OpenTelemetry

指標採集使用的是自然也是 Prometheus 的那一套技術棧,只是 Prometheus 換為了與它完全相容的 VictoriaMetric 目前是為了更省資源。

客戶端使用則是直接使用 Prometheus 的庫進行指標暴露:

<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>prometheus-metrics-core</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>prometheus-metrics-exporter-httpserver</artifactId>
    <version>1.0.0</version>
</dependency>

最終透過配置抓取策略,由 VictoriaMetrics 的 scrape 程式來抓取指標最終寫入到它自己的儲存中:

apiVersion: operator.victoriametrics.com/v1beta1  
kind: VMPodScrape  
metadata:  
  name: kubernetes-pod-scrape  
  namespace: monitoring  
spec:  
  podMetricsEndpoints:  
    - scheme: http  
      scrape_interval: "30s"  
      path: /metrics  
      relabelConfigs:  
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]  
          separator: ;  
          regex: "true"  
          replacement: $1  
          action: keep  
        # 埠相同  
        - action: keep_if_equal  
          source_labels: [ __meta_kubernetes_pod_annotation_prometheus_io_port, __meta_kubernetes_pod_container_port_number ]  
        # 過濾INIT容器  
        - action: drop  
          source_labels: [ __meta_kubernetes_pod_container_init ]  
          regex: "true"  
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]  
          separator: ;  
          regex: (.+)  
          target_label: __metrics_path__  
          replacement: $1  
          action: replace  
        - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]  
          separator: ;  
          regex: ([^:]+)(?::\d+)?;(\d+)  
          target_label: __address__  
          replacement: $1:$2  
          action: replace  
        - separator: ;  
          regex: __meta_kubernetes_pod_label_(.+)  
          replacement: $1  
          action: labelmap  
        - source_labels: [__meta_kubernetes_namespace]  
          separator: ;  
          regex: (.*)  
          target_label: kubernetes_namespace  
          replacement: $1  
          action: replace  
        - source_labels: [__meta_kubernetes_pod_name]  
          separator: ;  
          regex: (.*)  
          target_label: kubernetes_pod_name  
          replacement: $1  
          action: replace  
      vm_scrape_params:  
        stream_parse: true  
  namespaceSelector:  
    any: true

以上是 VM 提供的 CRD

OpenTelemetry 誕生

到此鋪墊完成,不知道有沒有發現在可觀測性中關鍵的三個部分:日誌、指標、trace 都是使用不同的開源產品,從而會導致技術棧較多,維護起來自然也是比較麻煩的。

這麼一個軟體領域的核心能力自然需要提供一個完整方案的,將以上的不同技術棧都整合在一起,更加的方便開發者使用。

在這之前也有兩個社群想要做類似的事情:

  • OpenTracing
  • OpenCensus

不過他們並沒有統一整個可觀測領域,直到 2019 年 CNCF 社群宣佈成立 OpenTelemetry,並且將上述兩個社群進行合併共同開發 OpenTelemetry。

背靠 CNCF 雲原生社群加上許多知名廠商的支援(Google、Amazon、Redhat 等),現在已經正式成為 CNCF 的頂級專案了。

OpenTelemetry 架構介紹

但我們開啟 OpenTelemetry 社群的 GitHub 首頁時,會看到有許多專案;第一反應應該是比較蒙的,下面我會著重介紹一些比較重要的專案。

在開始之前還是先簡單介紹下 OpenTelemetry 的一些基礎元件和概念:

整個 OpenTelemetry 系統其實可以簡單分為三個部分:

  • 客戶端
  • OTel collector
  • 資料儲存

第一個客戶端很好理解,也就是我們的業務應用;如果是 Java 應用只需要掛載一個 agent 就可以自動採集系統的指標、鏈路資訊、日誌等上傳到 Collector 中。

也就是上圖的左邊部分。

之後就是非常關鍵的元件 collector,它可以透過 OTLP 協議接收剛才提到的客戶端上傳的資料,然後再內部進行處理,最終輸出到後續的儲存系統中。

Collector

上圖是 collector 的架構圖

由於 OpenTelemetry 設計之初就是要做到廠商無關,所以它就得做出更高層級的設計。

關鍵點就是這裡的 Receiver 和 Exporter 都是模組化的設計,第三方開發者可以基於它的標準開發不同元件從而相容不同的產品。

Receiver:用於接收客戶端上報的資料,不止是自己 agent 上報的資料,也可能會來自不同的廠商,比如 kubernetes、Kafka 等。

Exporter:同理,可以將 receiver 收到的資料進行處理之後輸出到不同的元件中;比如 Kafka/Pulsar/Promethus/Jaeger 等。

比如我們可以使用 Nginx Receiver接收來著 Nginx 上報的資料。

使用 MySQL Receiver接收來自 MySQL 的資料。

當然通常我們使用最多的還是 OTLP Receiver,這是官方的 OTLP 協議的接收器,可以接受官方的一些指標,比如我們只使用了 Java Agent 進行資料上報時。

https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver

在這裡是可以看到目前支援的所有第三方的 Receiver。


OpenTelemetry 所支援的 Exporter 也很多,比如一些常見的儲存:

  • clickhouse exporter
  • elasticsearch exporter
  • pulsar exporter
  • prometheus exporter
  • otlp http exporter

Exporter 的使用場景很多:如果是指標相關的資料可以直接寫入 Prometheus,如果是日誌資料也可以直接寫入 ElasticSearch。

如果還有其他的特殊需求(刪減屬性等)則可以寫入訊息佇列,自行處理完之後再發往 collector 進行後續的處理。

可能你已經發現了,由於 collector 非常的靈活,所以我們可以像搭積木一樣組裝我們的 receiver 和 exporter,它會以我們配置的流水線的方式進行呼叫,這樣我們就可以實現任意可定製的處理邏輯。

而這些流水線的組裝對於客戶端來說都是透明的,也就是說 collector 的更改完全不會影響到業務;業務只需要按照 OTLP 的格式上報資料即可。

在之前的從 Skywalking 切換到 OpenTelemetry 的文章中有人問為什麼要切換到 OpenTelemetry?

從這裡也能看得出來,OpenTelemetry 的靈活度非常高,藉助於 Exporter 可以任意的更換後端儲存,或者增加/刪減一些不需要的指標資料等。


當然我們也可以統一的在這裡進行搜尋,可以列出所有的第三方整合的元件:
https://opentelemetry.io/ecosystem/registry/

OpenTelemetry 專案介紹

opentelemetry-java

介紹完基本的概念後,我們可以看看 OTel 社群的一些主要開源專案。

這裡我們還是以剛才的那個架構圖從作往右講起,也就是主要分為客戶端和 collector 端。


目前官方支援的客戶端語言已經非常齊全了,大部分的版本都已經是 Stable 穩定版,意味著可以進入生產環境。

這裡我們以 Java 客戶端為例:

其中我們重點關注下 opentelemetry-java 和 opentelemetry-java-instrumentation 這兩個專案。

我們用的最多的會是 opentelemetry-java-instrumentation,它會給我們提供一個 java agent 的 JAR 包:

java -javaagent:path/to/opentelemetry-javaagent.jar \
     -jar myapp.jar

我們只需要在 Java 應用中加上該 agent 就可以實現日誌、指標、trace 的自動上報。

而且它還實現了不同框架、庫的指標採集與 trace。

在這裡可以查到支援的庫與框架列表:

https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md#libraries--frameworks

總之幾乎就是你能想到和不能想到的都支援了。

而 opentelemetry-java 我們直接使用的機率會小一些,opentelemetry-java-instrumentation 本身也是基於它建立的,可以理解為是 Java 版本的核心基礎庫,一些社群支援的元件就可以移動到 instrumentation 這個庫中。

比如我在上篇文章:從一個 JDK21+OpenTelemetry 不相容的問題講起中涉及到的 HostResourceProvider 資源載入就是從 opentelemetry-java 中移動到了 opentelemetry-java-instrumentation

具體可以參考:https://github.com/open-telemetry/opentelemetry-java/issues/4701

collector

之後就是 collector 的元件了,它同樣的也有兩個庫:
OpenTelemetry CollectorOpenTelemetry Collector Contrib

其實透過他們的名字也可以看得出來,他們的作用與剛才的 Java 庫類似:

  • opentelemetry-collector:由官方社群維護,提供了一些核心能力;比如只包含了最基本的 otlp 的 receiver 和 exporter。
  • opentelemetry-collector-contrib:包含了官方的 collector,同時更多的維護了社群提供的各種 receiver 和 exporter;就如上文提到的,一些社群元件(pulsar、MySQL、Kafka)等都維護在這個倉庫。

而我們生產使用時通常也是直接使用 opentelemetry-collector-contrib,畢竟它所支援的社群元件更多。

總結

因為 OpenTelemetry 想要解決的是整個可觀測領域的所有需求,所以倉庫非常多,社群也很開放,感興趣的朋友可以直接參與貢獻,這麼多 repo 總有一個適合你的。

後續會繼續講解如何安裝以及配置我們的 OpenTelemetry。

參考連結:

  • https://github.com/pinpoint-apm/pinpoint
  • https://github.com/codecentric/spring-boot-admin
  • https://github.com/open-telemetry/opentelemetry-java
  • https://github.com/open-telemetry/opentelemetry-java-instrumentation
  • https://github.com/open-telemetry/opentelemetry-java/issues/4701

相關文章