Dapr 可觀測性之分散式追蹤
在構建應用程式時,瞭解系統的行為方式是運維它的重要部分——這包括能夠觀察應用程式的內部呼叫、衡量其效能並在問題發生時能夠立即找到問題。這對任何系統來說都是具有挑戰性的,對於由多個微服務組成的分散式系統更是如此,其中由多個呼叫組成的流可能在一個微服務中開始,但在另一個微服務中繼續呼叫。可觀測性在生產環境中至關重要,在開發過程中對於瞭解瓶頸、提高效能和跨微服務執行基本除錯也很有用。
雖然可以從底層基礎架構中收集有關應用程式的一些資料(例如記憶體消耗、CPU 使用情況),但必須從 應用程式感知 層收集其他有意義的資訊——該層可以顯示如何執行一系列重要的呼叫跨微服務。這通常意味著開發人員必須為此新增一些程式碼來檢測應用程式。通常,檢測程式碼只是將收集到的資料(例如追蹤和指標)傳送到外部監控工具或服務,以幫助儲存、視覺化和分析這些資訊。
由於這部分程式碼並不是應用程式的核心邏輯,所以這自然成為了開發人員的另一個負擔,有時需要了解監控工具的 API,使用額外的 SDK 等。這種工具也可能會增加應用程式的可移植性挑戰。應用程式可能需要不同的工具,具體取決於應用程式的部署環境。例如,不同的雲提供商提供不同的監控解決方案,本地部署可能需要本地解決方案。
用於獲得可觀測性的系統資訊被稱為 telemetry(遙測) ,它可以分為四大類。
-
Distributed tracing(分散式追蹤)提供了對參與分散式業務通訊的服務之間流量的洞察力。
-
Metrics(指標)提供了對服務效能及其資源消耗的洞察力。
-
Logging(日誌)提供了對程式碼如何執行以及是否發生錯誤的洞察力。
-
Health(健康)端點提供了對服務可用性的洞察力。
Dapr 可觀測性構件將可觀測性與應用解耦,它自動捕捉由構成 Dapr 控制平面的 Dapr sidecar 和 Dapr 系統服務產生的流量。該模組將跨越多個服務的單個操作的流量進行關聯。它還暴露了效能指標、資源利用率和系統的健康狀況。遙測資料以開放標準的格式釋出,使資訊能夠被輸入你選擇的監控後端。在那裡,這些資訊可以被視覺化、查詢和分析。
由於 Dapr 進行了抽象,所以應用程式不知道可觀測性是如何實現的。不需要開發者關心如何去實現這部分與核心業務邏輯無關的程式碼,Dapr 允許開發者專注於構建業務邏輯,而不是觀察能力的建設。觀察力是在 Dapr 系統層面上配置的,並且在不同的服務中是一致的,即使是由不同的團隊建立,並使用不同的技術棧構建。
如何工作
Dapr 的 sidecar 架構實現了內建的可觀測性功能,當服務進行通訊時,Dapr sidecars 攔截流量並提取追蹤、指標和日誌資訊,遙測資料以開放標準格式進行釋出,預設 Dapr 支援 OpenTelemetry 和 Zipkin。
Dapr 提供 collectors 收集器,可以將遙測資料釋出到不同的後端監控工具,這些工具將 Dapr 遙測資料呈現出來,用於分析和查詢。圖 10-1 顯示了 Dapr 的可觀察性架構。
![](http://mdimg.wxwenku.com/getimg/ccdf080c7af7e8a10e9b88444af98393c61e40ee6669b3478bdb690a96ee4f09ae78bd5f7775888e0e039242df52355e.jpg)
-
服務 A 呼叫服務 B 的一個操作,該呼叫從服務 A 的 Dapr sidecar 被路由到服務 B 的 sidecar。
-
當服務 B 完成操作時,響應會通過 Dapr sidecar 被送回服務 A。它們收集併發布每個請求和響應的所有可用遙測資料。
-
配置的收集器攝取遙測資料並將其傳送到監控後端。
不過需要注意的是新增可觀測性的支援不同於配置其他 Dapr 構建塊,比如前面我們介紹的釋出訂閱或者狀態管理這些元件,我們不需要引用構建塊了,而是新增收集器和監控後端,上圖顯示我們可以配置多個與不同監控後端整合的收集器。
下面我們來分別對可觀測性的幾個遙測型別進行說明。
分散式追蹤
分散式追蹤提供了對分散式應用中跨服務流動流量的洞察力。交換的請求和響應資訊的日誌是排除問題的重要資訊來源,比較困難的是把屬於同一業務事務的訊息整合起來。
Dapr 使用 W3C Trace Context 這個統一的標準來關聯相關資訊,它將相同的上下文資訊注入到一次完整的請求和響應中。
![](http://mdimg.wxwenku.com/getimg/356ed03bdc643f9448b3f6485edc229bd46f412c70e29c76fa7a299b111fe772060ea9b07d272482ff9801057c9e3045.jpg)
上圖顯示了一個 W3C Trace Context
標準的示例:
-
服務 A 呼叫服務 B 上的操作。當服務 A 開始呼叫時,Dapr 建立一個唯一的
trace context
並將其注入到請求中。 -
服務 B 接收請求並呼叫服務 C 上的操作。Dapr 檢測到傳入請求包含
trace context
並通過將其注入到服務 C 的傳出請求中來傳播它。 -
服務 C 接收請求並處理它。Dapr 檢測到傳入的請求包含
trace context
,並通過將其注入到傳出響應中返回給服務 B 來傳播它。 -
服務 B 接收響應並處理它。然後它建立一個新的響應並通過將其注入到傳出響應中來傳播
trace context
並返回到服務 A。
一組屬於一起的請求和響應就稱為 trace(追蹤)
,如下圖所示:
![](http://mdimg.wxwenku.com/getimg/ccdf080c7af7e8a10e9b88444af98393e28fa7992252af346a47c35f9b51f6f2de9f484c25b5982236ce7a415b33b0fb.jpg)
注意檢視上圖 trace
是如何代表一個發生在許多服務中的獨特應用事務的。一個 trace
是一系列 spans
集合組成的,每個 span
代表一個單一的操作或在 trace
中完成的工作單位。 Spans
是在實現單一事務的服務之間傳送的請求和響應。
接下來我們來討論如何通過將遙測資料釋出到對應的監控後端。
使用 Zipkin
Zipkin 是一個開源的分散式追蹤系統,它可以攝取和視覺化遙測資料。Dapr 為 Zipkin 提供了預設支援。
當 Dapr 在自託管模式下初始化 (dapr init) 時,多個容器會部署到本地 Docker,可以執行 docker ps
命令檢視本地執行的所有容器,確保 Zipkin 容器已啟動並正在執行,並記下它正在執行的埠(預設為 9411)。
![](http://mdimg.wxwenku.com/getimg/ccdf080c7af7e8a10e9b88444af983936cfdaf7127799de824c6fbd86145d5353279ef060c22f1fa4c828c9afa0b5e73.jpg)
如果沒有 Zipkin 容器服務執行,可以使用下面的命令來進行啟動:
➜ docker run --name dapr_zipkin -d -p 9411:9411 openzipkin/zipkin
此時其實我們即可在瀏覽器中通過 http://localhost:9411
訪問到 Zipkin 的 Web 頁面,在 Dashboard 中我們可以搜尋檢視已通過 Dapr 可觀測性構建塊記錄的遙測資料。
![](http://mdimg.wxwenku.com/getimg/ccdf080c7af7e8a10e9b88444af98393dfcdb8f075de4b42ef8af4da294ea0f2ff8bd58c7cb3a20c6bbb5c1f1bc17d21.jpg)
在搜尋結果中點選 SHOW
按鈕即可檢視詳細的遙測資料。
![](http://mdimg.wxwenku.com/getimg/ccdf080c7af7e8a10e9b88444af98393be57eb0638fa02e74e2ae5738bcd15eb73fdcaaca3fd747fcc1e15add8ac4a05.jpg)
我們可以發現在本地自拓管模式下面並沒有做任何的關於 Zipkin 的配置,當有服務請求經過了 Dapr sidecar 過後,Zipkin 中就有了對應的遙測資料了,這是因為自拓管模式下面預設就啟用了 Zipkin 來收集遙測資料。相關的配置位於 $HOME/.dapr/config.yaml
,內容如下所示:
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprConfig
spec:
tracing:
samplingRate: "1"
zipkin:
endpointAddress: http://localhost:9411/api/v2/spans
所以如果是在 Kubernetes 模式下面要啟用 Zipkin 作為 tracing 後端,則需要單獨建立 Configuration
物件才行。
首先,必須使用 Dapr 配置檔案為 Dapr 執行時啟用 tracing。下面是一個名為 dapr-config.yaml
的配置檔案示例,它啟用了 tracing:
# dapr-config.yaml
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: appconfig
spec:
tracing:
samplingRate: "1"
zipkin:
endpointAddress: "http://zipkin.default.svc.cluster.local:9411/api/v2/spans"
可以看到該配置檔案和本地的配置幾乎一致,唯一不同的就是 zipkin.endpointAddress
的地址不同。其中的 samplingRate
屬性指定了用於釋出追蹤的間隔時間,這個值必須在 0(禁止追蹤)和 1(每條追蹤都被髮布)之間。例如,值為 0.5 時,則表示每隔一段時間就釋出一次 trace,這樣就大大減少了釋出流量。我們這裡的 zipkin.endpointAddress
指向 Kubernetes 叢集中執行的 Zipkin 伺服器,Zipkin 的預設埠是 9411。直接應用該資源物件即可:
➜ kubectl apply -f dapr-config.yaml
當然還需要手動部署 Zipkin 服務,對應的資源清單檔案如下所示:
# zipkin.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: zipkin
namespace: default
labels:
service: zipkin
spec:
selector:
matchLabels:
service: zipkin
template:
metadata:
labels:
service: zipkin
spec:
containers:
- name: zipkin
image: openzipkin/zipkin-slim
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9411
protocol: TCP
---
kind: Service
apiVersion: v1
metadata:
name: zipkin
namespace: default
labels:
service: zipkin
spec:
type: NodePort
ports:
- port: 9411
targetPort: 9411
nodePort: 32411
protocol: TCP
name: zipkin
selector:
service: zipkin
這裡我們使用的 openzipkin/zipkin-slim
容器映象,Zipkin Service 暴露了 Zipkin Web 前端,可以通過 32411 埠來進行訪問。同樣直接應用上面的資源清單:
➜ kubectl apply -f zipkin.yaml
部署完成後可以檢視 Pod 狀態瞭解應用是否部署成功:
➜ kubectl get pods -l service=zipkin
NAME READY STATUS RESTARTS AGE
zipkin-f5c696fb7-94mqz 1/1 Running 0 3m9s
➜ kubectl get svc -l service=zipkin
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
zipkin NodePort 10.102.75.84 <none> 9411:32411/TCP 30s
部署成功後可以通過 http:<node-ip>:32411
來訪問 Zipkin Web 頁面。
![](http://mdimg.wxwenku.com/getimg/356ed03bdc643f9448b3f6485edc229b8b3350dface613a9ca353f1aedaeed18f9feb1206c9d4d89f5679c121bd293ee.jpg)
接下來我們就可以釋出遙測資料了,需要注意的是我們需要在每個 Dapr sidecar 在啟動時發出遙測資料,為此需要為應用新增一個 dapr.io/config
註解。
同樣這裡我們還是以 quickstarts
示例進行說明,定位到 tutorials/distributed-calculator
目錄下面:
➜ git clone [-b <dapr_version_tag>] http://github.com/dapr/quickstarts.git
➜ cd tutorials/distributed-calculator
該示例是一個分散式計算器,展示了 Dapr 的方法呼叫和狀態持久化功能,其中每個操作都由用不同語言/框架編寫的服務提供支援:
-
Addition: Go mux application
-
Multiplication: Python flask application
-
Division: Node Express application
-
Subtraction: .NET Core application
前端應用由一個服務端和一個用 React 編寫的客戶端組成,原始碼地址:React calculator 。
![](http://mdimg.wxwenku.com/getimg/6b990ce30fa9193e296dd37902816f4b76e4ddfdf9250f4a46fdda191b95c942396127c3b4324cea4a3e9ad6feec5789.jpg)
上圖為該示例應用各個元件的組成和服務架構。
我們可以隨便檢視一個微服務的部署清單,位於 deploy/
目錄下面,比如 go-adder.yaml
:
# go-adder.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: addapp
labels:
app: add
spec:
replicas: 1
selector:
matchLabels:
app: add
template:
metadata:
labels:
app: add
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "addapp"
dapr.io/app-port: "6000"
dapr.io/config: "appconfig"
spec:
containers:
- name: add
image: ghcr.io/dapr/samples/distributed-calculator-go:latest
env:
- name: APP_PORT
value: "6000"
ports:
- containerPort: 6000
imagePullPolicy: Always
上面的資源清單中我們通過 dapr.io/config
註解指定了使用 appconfig
這個配置檔案,該配置檔案中使用了 Zipkin 服務來獲取遙測資料,其他微服務中也使用了該註解,所以當應用部署完成後,Zipkin 就能獲取到相應的遙測資料。
需要注意 dapr.io/config
後面指定的 Configuration
物件需要和當前應用位於同一個名稱空間之下。
直接部署該示例應用:
➜ kubectl apply -f deploy/
部署完成後我們可以通過 dapr configurations
命令檢視當前叢集中的所有配置資訊:
➜ dapr configurations -k -A
NAMESPACE NAME TRACING-ENABLED METRICS-ENABLED AGE CREATED
default appconfig true true 1m 2022-09-20 17:01.21
同樣在 Dashboard 中也可以看到該配置資訊:
![](http://mdimg.wxwenku.com/getimg/6b990ce30fa9193e296dd37902816f4ba8f708168568094f4e99c80996e9af1b8cd6d7fe0e0bdaf3004a8be09f79cd0c.jpg)
應用部署完成後檢視 Pod 的狀態:
➜ kubectl get pods
NAME READY STATUS RESTARTS AGE
addapp-84c9764fdb-72mxf 2/2 Running 0 74m
calculator-front-end-59cbb6658c-rbctf 2/2 Running 0 74m
divideapp-8476b7fbb6-kr8dr 2/2 Running 0 74m
multiplyapp-7c45fbbf99-hrmff 2/2 Running 0 74m
subtractapp-58645db87-25tg9 2/2 Running 0 62m
➜ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
addapp-dapr ClusterIP None <none> 80/TCP,50001/TCP,50002/TCP,9090/TCP 8m29s
calculator-front-end LoadBalancer 10.110.177.32 192.168.0.54 80:31701/TCP 8m29s
calculator-front-end-dapr ClusterIP None <none> 80/TCP,50001/TCP,50002/TCP,9090/TCP 8m29s
divideapp-dapr ClusterIP None <none> 80/TCP,50001/TCP,50002/TCP,9090/TCP 8m29s
multiplyapp-dapr ClusterIP None <none> 80/TCP,50001/TCP,50002/TCP,9090/TCP 8m29s
subtractapp-dapr ClusterIP None <none> 80/TCP,50001/TCP,50002/TCP,9090/TCP 8m29s
zipkin NodePort 10.108.46.223 <none> 9411:32411/TCP 16m
部署完成後我們可以通過 calculator-front-end
這個 LoadBalancer 型別的 Service 去訪問計算器的前端應用,我們這裡分配的 EXTERNAL-IP
地址為 192.168.0.54
。
![](http://mdimg.wxwenku.com/getimg/356ed03bdc643f9448b3f6485edc229bd597529172cdb72c8f57591f8a108fe6eb73ef676c075a0151fe307126bc1018.jpg)
開啟瀏覽器的控制檯視窗(使用 F12 鍵) ,檢視在使用計算器時生成的日誌。請注意,每次單擊按鈕時,都會看到表示狀態永續性的日誌:
Rehydrating State:
{total: "21", next: "2", operation: "x"}
還要注意,每次輸入一個完整的方程式(例如 126 ÷ 3 =
) ,日誌都會指示對服務的呼叫:
Calling divide service
客戶端程式碼呼叫 Express 伺服器,後者將呼叫通過 Dapr 路由到後端服務。在這種情況下,在 nodejs 應用程式上呼叫 divide
端點。
當我們操作應用的時候,後面就有網路請求產生,也就有了微服務之間的呼叫,所以此時就會引數對應的 trace 遙測資料,我們可以前往 Zipkin 查詢下資料。
![](http://mdimg.wxwenku.com/getimg/6b990ce30fa9193e296dd37902816f4b4f0972b27c56a55cfd47966d6d5a5ee7ccf9259bdcd024db3a4deae0e5335b5b.jpg)
點選 SHOW
就可以看到詳細的遙測資料。
![](http://mdimg.wxwenku.com/getimg/6b990ce30fa9193e296dd37902816f4b4c12d23a27784ac3495cf45adb6f005809700097b73512cfefd56bf635d5a416.jpg)
同樣的除了 Zipkin,其他監視後端軟體也可引入 Zipkin 格式的遙測,比如 Jaeger,Jaeger 是由 Uber 建立的開源追蹤系統。它用於跟蹤分散式服務之間的事務,並對複雜的微服務環境進行故障排除,又比如 New Relic 是一個全堆疊可觀測性平臺,它可以連結來自分散應用程式的相關資料,以提供系統的完整圖片 要試用它們,只需要在 Dapr 配置檔案中指定一個指向 Jaeger 或 New Relic 伺服器的 endpointAddress
即可。下面是配置 Dapr 以將遙測傳送到 Jaeger 伺服器的配置檔案示例。Jaeger 的 URL 與 Zipkin 的 URL 相同。唯一的區別是伺服器執行的埠號:
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: dapr-config
namespace: default
spec:
tracing:
samplingRate: "1"
zipkin:
endpointAddress: "http://localhost:9415/api/v2/spans"
同樣如果要使用 New Relic,則需要將 endpointAddress
指定為 New Relic API 的地址。
- Dapr 可觀測性之分散式追蹤
- DeepFlow AutoTagging 之 Prometheus 標籤標準化
- 在 Linkerd 中獲取應用的黃金指標
- Linkerd Service Mesh 快速上手
- 使用 Cluster API 和 ArgoCD 建立管理 Kubernetes 叢集
- 使用 Crossplane 和 VCluster 在 Kubernetes 上快速構建新叢集
- 有意思,這個工具可以讓你像 GitLab 一樣管理資料庫
- 雲原生宣告式資料庫結構遷移工具 - SchemaHero
- Containerd 對接私有映象倉庫 Harbor
- 使用 Prometheus Pushgateway 推送監控指標
- 使用 Traefik Hub 輕鬆暴露本地 Kubernetes 叢集服務
- DevOps 工具鏈管理器 DevStream 還真是神器!
- 實現基於 Grafana Loki 的日誌報警
- 日誌收集工具 Fluentd 使用教程
- Sentry OpenTelemetry前後端全鏈路打通
- 從零開始的 Kubernetes 攻防指南
- 如何修改 K8S Master節點 IP?可沒想象中那麼簡單~
- 這款基於 Kubernetes 的通用開源 PaaS 管理平臺非常值得一試
- 一個由 Kubernetes 驅動的 PaaS 系統 - Porter
- Thanos Ruler 元件的使用