[TOC]
Istio Trace鏈路追蹤方案
Istio Trace支援
envoy支援trace
envoy原生就支援分散式追蹤系統的接入,如支援jaeger和zipkin,如envoy的Tracing官方文件中表明envoy支援如下trace特性:
- 生成Request Id,填充HTTP的header欄位x-request-id
- 外部跟蹤服務整合,如支援LightStep, Zipkin或任何Zipkin相容後端(如Jaeger)
- 新增Client trace ID
相關資訊可以參考這裡 或者 envoy官方文件Jaeger Tracing,另外,在原始碼中有對應的trace相關的原始碼。
Istio支援trace
Istio的分散式追蹤相關介紹裡面相關說明可以知道,Istio的envoy代理攔截流量後會主動上報trace系統,通過proxy的引數zipkinAddress指定了trace系統的地址,這樣就不會再經過mixer了,直接envoy和trace系統互動,大體流程:
-
如果incoming的請求沒有trace相關的headers,則會再流量進入pods之前建立一個root span
-
如果incoming的請求包含有trace相關的headers,Sidecar的proxy將會extract這些span的上下文資訊,然後再在流量進入pods之前建立一個繼承上一個span的新的span
由於Istio的proxy代理是envoy,而envoy又原生支援jaeger,那因此Istio自然而然就支援jaeger了,在官方文件Distributed Tracing中有相關較為詳細的說明
當然,預設是通過envoy這個proxy直接上報的,如果要經過mixer上報,也是可行的,可以進行相關配置,額外處理一下,具體可以參考idou老師教你學Istio 08: 呼叫鏈埋點是否真的“零修改”?
不過目前envoy支援的trace方案相對比較簡單,採用策略無法應用於Jaeger的所有策略,然後也不支援不同業務有不同的取樣策略,因此Istio進行配置,也是全域性的。
~/goDev/Applications/src/Istio.io/Istio/pilot/pkg/networking/core/v1alpha3/listener.go中的原始碼如下:
if env.Mesh.EnableTracing {
tc := model.GetTraceConfig()
connectionManager.Tracing = &http_conn.HttpConnectionManager_Tracing{
OperationName: httpOpts.direction,
ClientSampling: &envoy_type.Percent{
Value: tc.ClientSampling,
},
RandomSampling: &envoy_type.Percent{
Value: tc.RandomSampling,
},
OverallSampling: &envoy_type.Percent{
Value: tc.OverallSampling,
},
}
connectionManager.GenerateRequestId = &google_protobuf.BoolValue{Value: true}
}
複製程式碼
Trace(jaeger)的持久化儲存
jaeger在Istio中的現狀
目前官方自帶的jaeger採用的是jaegertracing/all-in-one這個映象,這個會包含三個元件 jaeger-agent、jaeger-collector、jaeger-query,其中jaeger-collector會將資料儲存,而all-in-one這映象目前僅僅是儲存在記憶體裡面的,也就是臨時儲存,如果刪掉pod重啟,jaeger的資料是沒有了的。 jaegertracing/all-in-one映象記憶體儲存相關。
為此,我們要考慮,如何將jaeger-collector的資料儲存指定為自己的儲存服務如ES叢集,採用官方自帶的肯定不行了,只能是自己部署一套jaeger服務,或者讓jaeger服務的agent的收集地址指向我們自己的服務
doc.Istio.cn/en/help/faq… Istio.io/docs/refere…
這兩篇文章有說設定trace_zipkin_url, trace_jaeger_url,可以達到目的,檢視yaml配置發現mixer只有設定trace_zipkin_url:
containers:
- name: mixer
image: "docker.io/Istio/mixer:1.0.0"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9093
- containerPort: 42422
args:
- --address
- unix:///sock/mixer.socket
- --configStoreURL=k8s://
- --configDefaultNamespace=Istio-system
- --trace_zipkin_url=http://zipkin:9411/api/v1/spans
複製程式碼
這個只是針對Mixer元件而言的trace,如果是envoy本身的tarce,需要修改proxyv2的引數
jaeger持久化儲存的方案
Istio開源版本中,呼叫鏈對接jaeger是從envoy直接報上去的,沒有通過mixer來做。
因為呼叫鏈的資料量會很大,可靠性以及規模確是需要重點考慮的,因此必須要使用自己的服務 ,如果要配置為自己的jaeger服務,需要用kubectl修改Istio這個configmap中的zipkinAddress,配置為自己的服務地址,另外就是jaeger收資料是相容zipkin的。
kubectl get configmap Istio -n Istio-system -o yaml |grep zipkinAddress
有兩處zipkinAddress地址,如下:
zipkin.Istio-system:9411
複製程式碼
對於華為雲而言,呼叫鏈這裡他們會對接到華為雲的apm服務,在可靠性和效能上都會有保證。
對接外部的trace系統[Jaeger]
K8S獨立部署Jaeger元件
根據K8S安裝部署Jaeger官方文件部署基於k8s的Jaeger的生產環境下的容器,注意一定要採用文件中Production這個生成的部署方式。
注意建立Elasticserach的時候,需要等待特別久,而且一定要等到Elasticserach這個pod的狀態為Running的時候才能建立Jaeger的其他元件,因為其他元件要依賴Elasticserach
然後修改jaeger-query這個Service的type為NodePort,然後通過 kubectl get service jaeger-query
,可以看到Port,然後利用host ip可以訪問,如2.2叢集獨立部署的Jaeger Query UI
需要部署jaeger相對比較麻煩,有一些引數需要設定,這個需要一定的學習能力,需要對jaeger對外暴露的埠、協議有一定的理解;然後還需要對儲存引擎如ES有一定的瞭解
另外,如果是通過二進位制安裝部署的話,相對較為簡單,只需要注意啟動引數即可
修改Istio到已有Jaeger服務
通過kubectl get configmap istio -n istio-system -o yaml |grep zipkinAddress
先直接修改zipkinAddress的地址,指定為jaeger-collector這個Service的地址,埠是9411,只有這個9411地址才相容zipkin協議。因為envoy這個proxy會預設使用環境變數來設定zipkinAddress地址,預設地址是zipkin.istio-system:9411
。修改過configmap之後,如果後面通過helm upgrade更新,則現在通過這個方式來修改的資料會失效,因此要完全修改,則必須通過修改過install/kubernetes/helm/istio//templates/configmap.yaml
,同時還要修改install/kubernetes/helm/istio//charts/mixer/templates
下面的zipkin相關的地址。
如果是istio.yaml這個模板檔案部署,則還需:
-
修改istio.yaml檔案中的 zipkinAddress: zipkin.Istio-system:9411
- 修改為:zipkinAddress: 10.233.61.200:9411【ClusterIP只針對K8S叢集內】
-
修改istio.yaml檔案中的mixer相關的trace_zipkin_url地址
- 修改為:--trace_zipkin_url=http://10.233.61.200:9411/api/v1/spans【ClusterIP只針對K8S叢集內】
-
修改istio.yaml檔案中的proxyv2相關的zipkinAddress這個args
- 修改為:10.233.61.200:9411【ClusterIP只針對K8S叢集內】
其他說明:
-
修改所有zipkinAddress相關的地址為jaeger-collector這個Service的地址,這個如果都是K8S叢集,可以直接配置為ClusterIP,但是實際中需要配置一個全域性域名
- istio這個configmap中的zipkinAddress地址,proxy會採用這個環境變數,但是已經部署的pod不會生效了,因為是手動注入的,istioctl kube-inject的時候才會用到proxy的環境變數,因此需要刪除Deployment然後重新部署生效。如果是自動注入的應該就只需要重啟pod。
-
jaeger-agent這個服務,如果Istio直接配置為外部jaeger地址的話,是不會經過jaeger-agent的,因此可以關閉
-
由於通過ES進行資料儲存,因此現在殺掉jaeger相關的Pod,重啟後資料依然存在
-
對接到外部jaeger服務的話,Istio自帶的jaeger相關的就可以直接關閉了
取樣策略修改和配置
Jaeger本身支援在client端調整和通過collector調整取樣策略,但是在Istio中並沒有Jaeger的client,只是envoy裡面支援了trace,直接修改envoy的trace相關原始碼不太友好。不過Istio中提供了一個全域性的設定,通過設定pilot的引數可以用來控制採用策略。
Istio的取樣流程大致是:在pilot的v1alpha3的流量管理介面中,在提供Listener的Http filters的時候會判斷:是否使能了mesh的trace,如果使能,則建立trace並讀取 採用配置,取樣通過環境變數PILOT_TRACE_SAMPLING
來配置,其範圍是0.0 - 100.0,預設為100,全取樣。
修改的方式有兩種:
-
helm安裝時候的選項引數:pilot.traceSampling
-
通過
kubectl -n Istio-system edit deploy Istio-pilot
修改PILOT_TRACE_SAMPLING
變數
當PILOT_TRACE_SAMPLING
的值是100的時候,表示全取樣,每一次請求都會取樣,可以驗證得到,通過訪問測試頁面,記錄發起的請求次數,然後檢視Jaeger Trace UI,檢視Services為productpage的Trace,發現發起請求的次數和Trace的次數保持一致。
當PILOT_TRACE_SAMPLING
的值是50的時候,表示取樣1/2,每兩次請求都會取樣一次,修改完後,等待一小會兒,然後驗證。驗證結果表示現在並非1:2,但是也不完全是1/2的概率,具體還有待分析Jaeger的原理,但是至少證明了策略的修改是有效的
對接Mtrace系統
現有Mtrace系統,在原有Jaeger基礎上做了一些調整,使用了protobuf協議,同時增加了kafka。因此要想對接MTrace系統,還需要對proxy(envoy)做一些調整,並不是僅僅修改一些配置引數和地址等就可以解決的
業務接入Trace鏈路注意點
a,業務處理HTTP Header
雖然Istio能夠攔截流量並自動傳送Span資訊,但是要把整個過程統一追蹤並連結起來,還需要業務在程式碼中處理和追蹤相關的HTTP Header,這樣代理在傳送 Span 資訊的時候,才能正確的把同一個跟蹤過程統一起來。具體詳見
在Mtrace等系統或者原生的jaeger中,會有有個client的角色存在,這個client會建立並初始化一個trace,並處理好TraceID的事情,但是Istio後,服務中沒有Mtrace 發client端的 SDK,因此才需要再業務程式碼中處理好http header,但是對於非HTTP如TCP需要自行擴充套件支援,這個暫時不考慮;對應gRPC的話,因為也是基於http,因此可以通過一些方式新增。
所以,對於trace這塊,並非完全沒有任何侵入,業務程式碼有一點點小的改動,就是需要額外處理下http 的指定的header並依次傳遞
b,Istio設定取樣百分比
百分比預設值為100,全部取樣,可以修改為0-100;修改的方式有兩種:
-
helm安裝時候的選項引數:pilot.traceSampling
-
通過
kubectl -n Istio-system edit deploy Istio-pilot
修改PILOT_TRACE_SAMPLING變數
這個設定是全域性的,沒有辦法針對特定業務有特定的取樣策略。如果需要對特定業務取樣,就需要給collector配置靜態的json策略檔案,然後也需要client支援,具體可以參考Jaeger官方文件。
問題 & TODO
-
需要業務程式碼中處理好http header,但是對於非HTTP而言,怎麼弄 ?
- http 和 gRPC都需要業務自己處理好header
- TCP需要自定義擴充套件欄位
-
不通過envoy上報,通過mixer上報
-
支援不同業務不同的採用策略