目前不少的大中小公司都在探索和實踐着微服務這種軟件開發架構,將複雜龐大的重量型項目經過明肯定義的 API 拆分紅多個小型可複用的獨立服務單元或者說是服務組件,這樣讓應用程序更易於擴展和更快地開發,從而加速創新並縮短新功能的上市時間。可是複用和拆分依舊簡化不了系統的複雜度,雖然微服務架構拆分了業務單元,可是各類組件之間的調用也是錯中複雜,所以帶來一系列的問題:node
對於服務的維護者來講,觀察某一個請求(事件)的整個生命週期也是很困難;nginx
難以進行用戶體驗優化web
後臺真實錯誤緣由分析後端
分佈式系統內各組件的調用狀況等爲了解決這個問題,曾在90年代末出現的Tracing技術流行了起來,在早期,出現了一大批優秀的 Tracing 軟件:
api
Dapper(Google) : 各 tracer 的基礎緩存
Zipkin微信
鷹眼(taobao)網絡
諦聽(盤古,阿里云云產品使用的Trace系統)架構
...併發
儘管分佈式追蹤系統發展很快,種類繁多,但核心步驟通常有三個:代碼埋點
, 數據存儲
、 查詢展現
。但在數據採集過程當中,因爲須要侵入用戶代碼,而且不一樣系統的 API 並不兼容,這就致使了若是您但願切換追蹤系統,每每會帶來較大改動,出現了痛點,就會有人解決,爲了解決不一樣的分佈式追蹤系統 API 不兼容的問題,誕生了 OpenTracing 規範,Opentracing也正是爲了解決這樣的痛點。
OpenTracing 進入 CNCF,正在爲全球的分佈式追蹤,提供統一的概念和數據標準。
OpenTracing 經過提供平臺無關、廠商無關的 API,使得開發人員可以方便的添加(或更換)追蹤系統的實現。
也就是說,聽從Opentracing的規範,就至關於在應用程序/類庫和追蹤或日誌分析程序之間定義了一個輕量級的標準化層,解耦了代碼和Tracing API。
那麼tracing到底是什麼?
在廣義上,一個trace表明了一個事務或者流程在(分佈式)系統中的執行過程。在OpenTracing標準中,trace是多個span組成的一個有向無環圖(DAG),每個span表明trace中被命名並計時的連續性的執行片斷。
分佈式追蹤中的每一個組件都包含本身的一個或者多個span。例如,在一個常規的RPC調用過程當中,OpenTracing推薦在RPC的客戶端和服務端,至少各有一個span,用於記錄RPC調用的客戶端和服務端信息
一個父級的span會顯示的並行或者串行啓動多個子span。在OpenTracing標準中,甚至容許一個子span有個多父span(例如:並行寫入的緩存,可能經過一次刷新操做寫入動做)。
在一個分佈式系統中,追蹤一個事務或者調用流通常如上圖所示。雖然這種圖對於看清各組件的組合關係是頗有用的,可是,它不能很好顯示組件的調用時間,是串行調用仍是並行調用,若是展示更復雜的調用關係,會更加複雜,甚至沒法畫出這樣的圖。另外,這種圖也沒法顯示調用間的時間間隔以及是否經過定時調用來啓動調用。一種更有效的展示一個典型的trace過程,以下圖所示:
這種展示方式增長顯示了執行時間的上下文,相關服務間的層次關係,進程或者任務的串行或並行調用關係。這樣的視圖有助於發現系統調用的關鍵路徑。經過關注關鍵路徑的執行過程,項目團隊可能專一於優化路徑中的關鍵位置,最大幅度的提高系統性能。例如:能夠經過追蹤一個資源定位的調用狀況,明確底層的調用狀況,發現哪些操做有阻塞的狀況。
tracing,monitoring和logging
但是提及tracing,腦子就會有一些疑問,tracing,monitoring和logging之間究竟有什麼區別呢?先來看一張圖
對於監控來講,好比咱們經常使用的Prometheus是經過pull的方式有頻率的定量的向目標收集指標,而後將數據進行聚合計算,造成報告,對有問題的異常數據進行報警,因此Monitoring的需求並無包含很是高的併發量和通信量。反過來講:高併發、大數據量的需求並不適用於Monitoring這個點。
在瞭解Opentracing以後,你會發現Optracing規範是有標準固定的格式的,這也是和logging最大的不一樣,tracing蒐集一個事件過程當中全部指定蒐集的項,好比某個接口的請求時間,當收到某個SQL後,這個SQL的實行時間等,會將這些時間彙總到一個報告中,造成一個tracing,由於Tracing是針對某一個事件(通常來講就是一個API),而這個API可能會和不少組件進行溝通,後續的全部的組件溝通不管是內部仍是外部的IO,都算做這個API調用的Tracing的一部分。能夠想見在一個業務繁忙的系統中,API調用的數量已是天文數字,而其衍生出來的Tracing記錄更是不得了的量。其特色就是高頻、巨量,一個API會衍生出大量的子調用。
通常來講咱們在大型系統中提到Logging說的都不是簡單的日誌,而是日誌聚合系統。從本質上來講,Monitoring和Tracing都是Logging,Logging是這三者中覆蓋面最大的超集,而前二者則是其一部分的子集。Logging最麻煩的是,開發者也不會徹底知道最後記錄進入到日誌系統裏的一共會有哪些東西,只有在使用(檢索)的時候纔可能須要彙總查詢總量中的一部分。
每一個組件都有它本身存在的必要性:
Monitoring系統(Prometheus)從根本的需求和基本設計上就不可能支持Tracing和Logging:低頻 vs 高頻、低量 vs 高量,其從設計到實現就只爲了監控服務
Tracing系統(Jaeger)對提供的數據有格式要求,且處理方式和通常的Logging也不一樣,有更限定的應用範圍
Logging系統(ELK)能夠處理前二者的需求,但前二者的領域有更專業的工具就不推薦直接使用普通的日誌聚合系統了;Logging系統通常用來處理大型系統的日誌聚合以及檢索查詢
OpenTracing 實現之Jaeger 和 Zipkin
Jaeger目前是CNCF中的一個孵化項目,是 Uber 推出的一款開源分佈式追蹤系統,兼容 OpenTracing API,因此咱們這裏主要說一說Opentracing的後起之秀jaeger。先來看看Jaeger的架構圖:
Jaeger Client - 爲不一樣語言實現了符合 OpenTracing 標準的 SDK。應用程序經過 API 寫入數據,client library 把 trace 信息按照應用程序指定的採樣策略傳遞給 jaeger-agent。
Agent - 它是一個監聽在 UDP 端口上接收 span 數據的網絡守護進程,它會將數據批量發送給 collector。它被設計成一個基礎組件,部署到全部的宿主機上。Agent 將 client library 和 collector 解耦,爲 client library 屏蔽了路由和發現 collector 的細節。
Collector - 接收 jaeger-agent 發送來的數據,而後將數據寫入後端存儲。Collector 被設計成無狀態的組件,所以您能夠同時運行任意數量的 jaeger-collector。
Data Store - 後端存儲被設計成一個可插拔的組件,支持將數據寫入 cassandra、elastic search。
Query - 接收查詢請求,而後從後端存儲系統中檢索 trace 並經過 UI 進行展現。Query 是無狀態的,您能夠啓動多個實例,把它們部署在 nginx 這樣的負載均衡器後面。
當處理的數據量很大的時候,jaeger-collector就會面臨着一些性能的瓶頸,沒法及時存儲 jaeger-agent 發送來的數據,所以官方也支持使用kafka作爲緩衝區,下面是架構圖:
在熟悉了jaeger以後,爲了更快的熟悉並掌握jaeger的使用,咱們在kubernetes上安裝一下jaeger,而且在Edge Router Traefik2.0中使用jaeger配置一下tracing. jaeger的官方支持四種後端存儲:
Cassandra 3.4+
Elasticsearch 5.x, 6.x, 7.x
Kafka
memory storage
由於咱們k8s集羣裏面已經運行着日誌集羣了,因此咱們直接時候用Elasticsearch做爲jaeger的後端存儲.
☸️ devcluster🔥 logging ~ 🐳 👉 k get podsNAME READY STATUS RESTARTS AGEes-cluster-0 1/1 Running 0 10des-cluster-1 1/1 Running 0 10des-cluster-2 1/1 Running 0 10dfluentd-es-7pk8j 1/1 Running 0 10dfluentd-es-glnpb 1/1 Running 0 10dfluentd-es-jpvlw 1/1 Running 0 10dfluentd-es-l4mqv 1/1 Running 0 10dfluentd-es-rff5d 1/1 Running 0 10dkibana-6c448bd4d8-ghl7l 1/1 Running 0 10d[ root@curl-69c656fd45-xqtqp:/ ]$ curl -XGET http://elasticsearch.logging.svc.cluster.local:9200/_cat/nodes10.244.2.147 57 99 26 6.15 6.24 6.04 mdi - es-cluster-010.244.2.148 77 99 26 6.15 6.24 6.04 mdi * es-cluster-110.244.2.149 66 99 26 6.15 6.24 6.04 mdi - es-cluster-2
首先咱們建立一個Namespace
kubectl create namespace tracing
接下來第一步是在同一個Namespace下配置一個ConfigMap,用於定義jaeger-agent,jaeger-query,jaeger-collector服務的配置。名稱爲
jaeger-configmap.yml
apiVersion: v1kind: ConfigMapmetadata: name: jaeger-configuration labels: app: jaeger app.kubernetes.io/name: jaeger namespace: tracingdata: span-storage-type: elasticsearch collector: | es: server-urls: http://elasticsearch.logging.svc.cluster.local:9200 #這裏是咱們的es集羣的訪問地址 collector: zipkin: http-port: 9411 query: | es: server-urls: http://elasticsearch.logging.svc.cluster.local:9200 agent: | collector: host-port: "jaeger-collector:14267"
而後咱們經過list對象在tracing空間下定義jaeger-agent,jaeger-collector,jaeger-query以及它們的服務資源:
jaeger-production.yml
,配置文件內容比較多,能夠在微信公衆號內回覆·jaeger·
獲取最後,咱們在集羣中安裝一下便可:
kubectl apply -f jaeger-configmap.ymlkubectl apply -f jaeger-production.yml
查看服務是否正常運行了
☸️ devcluster🔥 tracing ~ 🐳 👉 kubectl get pods,svc,cmNAME READY STATUS RESTARTS AGEpod/jaeger-agent-4d5hz 1/1 Running 0 111mpod/jaeger-agent-574mg 1/1 Running 0 111mpod/jaeger-agent-5ztvr 1/1 Running 0 111mpod/jaeger-agent-sgn8s 1/1 Running 0 111mpod/jaeger-agent-xtlvv 1/1 Running 0 112mpod/jaeger-collector-77498bb8c-5xxf2 1/1 Running 0 130mpod/jaeger-query-b595fc78b-7qbxg 1/1 Running 0 130mNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEservice/jaeger-collector ClusterIP 10.110.33.231 <none> 14267/TCP,14268/TCP,9411/TCP 130mservice/jaeger-query ClusterIP 10.110.13.229 <none> 80/TCP 130mservice/zipkin ClusterIP 10.107.120.100 <none> 9411/TCP 130mNAME DATA AGEconfigmap/jaeger-configuration 4 146m
如何在外部訪問k8s集羣的jaeger-ui呢?咱們定義一個
jaeger-ingress.yml
apiVersion: traefik.containo.us/v1alpha1kind: IngressRoutemetadata: name: jaeger-query namespace: tracingspec: selector: app.kubernetes.io/name: jaeger app.kubernetes.io/component: query entryPoints: - web routes: - match: Host(`jaeger-query.xslimg.com`) kind: Rule services: - name: jaeger-query port: 80
咱們使用 kubectl apply-f jaeger-ingress.yml
就能夠生成一個訪問jaeger的路由了。
配置Traefik的靜態配置文件,開啓tracing,咱們修改一下k8s環境中的traefik的configmap,增長已下配置
... tracing: jaeger: samplingServerURL: http://192.168.10.231:5778/sampling samplingType: const samplingParam: 1.0 localAgentHostPort: 192.168.10.231:6831 # 這裏是運行爲daemonset的agent的主機地址 gen128Bit: true propagation: jaeger traceContextHeaderName: uber-trace-id collector: endpoint: http://jaeger-collector.tracing.svc.cluster.local:14268/api/traces?format=jaeger.thrift...
而後咱們重建一下traefik便可
kubectl apply -f traefik-configmap.ymlkubectl apply -f traefik-deployment.yaml
從新更新完配置文件和deployment.在重建成功後就能夠訪問:
這樣咱們就能夠在jaeger中查看traefik了
你也能夠運行一個基於微服務框架的案例,經過案例進行深刻了解jaeger,分析併發訪問服務後,觀察jaeger收取到數據的具體表現。好了,opentracing入門和jaeger的實現就暫時說到這了。
目前100000+人已關注加入咱們
![](http://static.javashuo.com/static/loading.gif)
本文分享自微信公衆號 - 雲原生生態圈(CloudNativeEcoSystem)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。