自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

開發(fā) | 一文讀懂微服務(wù)監(jiān)控之分布式追蹤

開發(fā) 前端 分布式
現(xiàn)在越來越多的應(yīng)用遷移到基于微服務(wù)的云原生的架構(gòu)之上,微服務(wù)架構(gòu)很強(qiáng)大,但是同時(shí)也帶來了很多的挑戰(zhàn),尤其是如何對(duì)應(yīng)用進(jìn)行調(diào)試,如何監(jiān)控多個(gè)服務(wù)間的調(diào)用關(guān)系和狀態(tài)。如何有效的對(duì)微服務(wù)架構(gòu)進(jìn)行有效的監(jiān)控成為微服務(wù)架構(gòu)運(yùn)維成功的關(guān)鍵。

[[272944]]

現(xiàn)在越來越多的應(yīng)用遷移到基于微服務(wù)的云原生的架構(gòu)之上,微服務(wù)架構(gòu)很強(qiáng)大,但是同時(shí)也帶來了很多的挑戰(zhàn),尤其是如何對(duì)應(yīng)用進(jìn)行調(diào)試,如何監(jiān)控多個(gè)服務(wù)間的調(diào)用關(guān)系和狀態(tài)。如何有效的對(duì)微服務(wù)架構(gòu)進(jìn)行有效的監(jiān)控成為微服務(wù)架構(gòu)運(yùn)維成功的關(guān)鍵。用軟件架構(gòu)的語言來說就是要增強(qiáng)微服務(wù)架構(gòu)的可觀測(cè)性(Observability)。

一文讀懂微服務(wù)監(jiān)控之分布式追蹤

微服務(wù)的監(jiān)控主要包含一下三個(gè)方面:

  • 通過收集日志,對(duì)系統(tǒng)和各個(gè)服務(wù)的運(yùn)行狀態(tài)進(jìn)行監(jiān)控
  • 通過收集量度(Metrics),對(duì)系統(tǒng)和各個(gè)服務(wù)的性能進(jìn)行監(jiān)控
  • 通過分布式追蹤,追蹤服務(wù)請(qǐng)求是如何在各個(gè)分布的組件中進(jìn)行處理的細(xì)節(jié)

對(duì)于是日志和量度的收集和監(jiān)控,大家會(huì)比較熟悉。常見的日志收集架構(gòu)包含利用Fluentd對(duì)系統(tǒng)日志進(jìn)行收集,然后利用ELK或者Splunk進(jìn)行日志分析。而對(duì)于性能監(jiān)控,Prometheus是常見的流行的選擇。

分布式追蹤正在被越來越多的應(yīng)用所采用。分布式追蹤可以通過對(duì)微服務(wù)調(diào)用鏈的跟蹤,構(gòu)建一個(gè)從服務(wù)請(qǐng)求開始到各個(gè)微服務(wù)交互的全部調(diào)用過程的視圖。用戶可以從中了解到諸如應(yīng)用調(diào)用的時(shí)延,網(wǎng)絡(luò)調(diào)用(HTTP,RPC)的生命周期,系統(tǒng)的性能瓶頸等等信息。那么分布式追蹤是如何實(shí)現(xiàn)的呢?

1.分布式追蹤的概念

谷歌在2010年4月發(fā)表了一篇論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》(http://1t.click/6EB),介紹了分布式追蹤的概念。

一文讀懂微服務(wù)監(jiān)控之分布式追蹤

對(duì)于分布式追蹤,主要有以下的幾個(gè)概念:

  • 追蹤 Trace:就是由分布的微服務(wù)協(xié)作所支撐的一個(gè)事務(wù)。一個(gè)追蹤,包含為該事務(wù)提供服務(wù)的各個(gè)服務(wù)請(qǐng)求。
  • 跨度 Span:Span是事務(wù)中的一個(gè)工作流,一個(gè)Span包含了時(shí)間戳,日志和標(biāo)簽信息。Span之間包含父子關(guān)系,或者主從(Followup)關(guān)系。
  • 跨度上下文 Span Context:跨度上下文是支撐分布式追蹤的關(guān)鍵,它可以在調(diào)用的服務(wù)之間傳遞,上下文的內(nèi)容包括諸如:從一個(gè)服務(wù)傳遞到另一個(gè)服務(wù)的時(shí)間,追蹤的ID,Span的ID還有其它需要從上游服務(wù)傳遞到下游服務(wù)的信息。

2.OpenTracing 標(biāo)準(zhǔn)概念

基于谷歌提出的概念OpenTracing(http://1t.click/6tC)定義了一個(gè)開放的分布式追蹤的標(biāo)準(zhǔn)。

Span是分布式追蹤的基本組成單元,表示一個(gè)分布式系統(tǒng)中的單獨(dú)的工作單元。每一個(gè)Span可以包含其它Span的引用。多個(gè)Span在一起構(gòu)成了Trace。

一文讀懂微服務(wù)監(jiān)控之分布式追蹤

OpenTracing的規(guī)范定義每一個(gè)Span都包含了以下內(nèi)容:

  • 操作名(Operation Name),標(biāo)志該操作是什么
  • 標(biāo)簽 (Tag),標(biāo)簽是一個(gè)名值對(duì),用戶可以加入任何對(duì)追蹤有意義的信息
  • 日志(Logs),日志也定義為名值對(duì)。用于捕獲調(diào)試信息,或者相關(guān)Span的相關(guān)信息
  • 跨度上下文呢 (SpanContext),SpanContext負(fù)責(zé)子微服務(wù)系統(tǒng)邊界傳遞數(shù)據(jù)。它主要包含兩部分:
  1. 和實(shí)現(xiàn)無關(guān)的狀態(tài)信息,例如Trace ID,Span ID
  2. 行李項(xiàng) (Baggage Item)。如果把微服務(wù)調(diào)用比做從一個(gè)城市到另一個(gè)城市的飛行, 那么SpanContext就可以看成是飛機(jī)運(yùn)載的內(nèi)容。Trace ID和Span ID就像是航班號(hào),而行李項(xiàng)就像是運(yùn)送的行李。每次服務(wù)調(diào)用,用戶都可以決定發(fā)送不同的行李。

這里是一個(gè)Span的例子:

  1. t=0 operation name: db_query t=x 
  2.  +-----------------------------------------------------+ 
  3.  | · · · · · · · · · · Span · · · · · · · · · · | 
  4.  +-----------------------------------------------------+ 
  5. Tags: 
  6. - db.instance:"jdbc:mysql://127.0.0.1:3306/customers 
  7. - db.statement: "SELECT * FROM mytable WHERE foo='bar';" ​ 
  8. Logs: 
  9. - message:"Can't connect to mysql server on '127.0.0.1'(10061)" ​ 
  10. SpanContext: 
  11. - trace_id:"abc123" 
  12. - span_id:"xyz789" 
  13. - Baggage Items: 
  14.  - special_id:"vsid1738" 

要實(shí)現(xiàn)分布式追蹤,如何傳遞SpanContext是關(guān)鍵。OpenTracing定義了兩個(gè)方法Inject和Extract用于SpanContext的注入和提取。

一文讀懂微服務(wù)監(jiān)控之分布式追蹤

Inject 偽代碼

  1. span_context = ... 
  2. outbound_request = ... ​ 
  3. # We'll use the (builtin) HTTP_HEADERS carrier format. We 
  4. # start by using an empty map as the carrier prior to the 
  5. # call to `tracer.inject`. 
  6. carrier = {} 
  7. tracer.inject(span_context, opentracing.Format.HTTP_HEADERS, carrier) ​ 
  8. # `carrier` now contains (opaque) key:value pairs which we pass 
  9. # along over whatever wire protocol we already use. 
  10. for key, value in carrier: 
  11.  outbound_request.headers[key] = escape(value) 

這里的注入的過程就是把context的所有信息寫入到一個(gè)叫Carrier的字典中,然后把字典中的所有名值對(duì)寫入 HTTP Header。

Extract 偽代碼

  1. inbound_request = ... ​ 
  2. # We'll again use the (builtin) HTTP_HEADERS carrier format. Per the 
  3. # HTTP_HEADERS documentation, we can use a map that has extraneous data 
  4. in it and let the OpenTracing implementation look for the subset 
  5. of key:value pairs it needs. 
  6. As such, we directly use the key:value `inbound_request.headers` 
  7. # map as the carrier. 
  8. carrier = inbound_request.headers 
  9. span_context = tracer.extract(opentracing.Format.HTTP_HEADERS, carrier) 
  10. Continue the trace given span_context. E.g., 
  11. span = tracer.start_span("...", child_of=span_context) ​ 
  12. # (If `carrier` held trace data, `span` will now be ready to use.) 

抽取過程是注入的逆過程,從carrier,也就是HTTP Headers,構(gòu)建SpanContext。

整個(gè)過程類似客戶端和服務(wù)器傳遞數(shù)據(jù)的序列化和反序列化的過程。這里的Carrier字典支持Key為string類型,value為string或者Binary格式(Bytes)。

3.怎么用能?

好了講了一大堆的概念,作為程序猿的你早已經(jīng)不耐煩了,不要講那些有的沒的,快上代碼。不急我們這就看看具體如何使用Tracing。

我們用一個(gè)程序猿喜聞樂見的打印‘hello world’的Python應(yīng)用來說明OpenTracing是如何工作的。

客戶端代碼

  1. import requests 
  2. import sys 
  3. import time 
  4. from lib.tracing import init_tracer 
  5. from opentracing.ext import tags 
  6. from opentracing.propagation import Format ​ 
  7. def say_hello(hello_to): 
  8.  with tracer.start_active_span('say-hello'as scope: 
  9.  scope.span.set_tag('hello-to', hello_to) 
  10.  hello_str = format_string(hello_to) 
  11.  print_hello(hello_str) 
  12. def format_string(hello_to): 
  13.  with tracer.start_active_span('format'as scope: 
  14.  hello_str = http_get(8081, 'format''helloTo', hello_to) 
  15.  scope.span.log_kv({'event''string-format''value': hello_str}) 
  16.  return hello_str ​ 
  17. def print_hello(hello_str): 
  18.  with tracer.start_active_span('println'as scope: 
  19.  http_get(8082, 'publish''helloStr', hello_str) 
  20.  scope.span.log_kv({'event''println'}) ​ 
  21. def http_get(port, path, param, value): 
  22.  url = 'http://localhost:%s/%s' % (port, path) ​ 
  23.  span = tracer.active_span 
  24.  span.set_tag(tags.HTTP_METHOD, 'GET'
  25.  span.set_tag(tags.HTTP_URL, url) 
  26.  span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT) 
  27.  headers = {} 
  28.  tracer.inject(span, Format.HTTP_HEADERS, headers) ​ 
  29.  r = requests.get(url, params={param: value}, headers=headers) 
  30.  assert r.status_code == 200 
  31.  return r.text 
  32. # main 
  33. assert len(sys.argv) == 2 ​ 
  34. tracer = init_tracer('hello-world'​ 
  35. hello_to = sys.argv[1] 
  36. say_hello(hello_to) 
  37. # yield to IOLoop to flush the spans 
  38. time.sleep(2) 
  39. tracer.close() 

客戶端完成了以下的工作:

  • 初始化Tracer,trace的名字是‘hello-world’
  • 創(chuàng)建以個(gè)客戶端操作say_hello,該操作關(guān)聯(lián)一個(gè)Span,取名‘say-hello’,并調(diào)用span.set_tag加入標(biāo)簽
  • 在操作say_hello中調(diào)用第一個(gè)HTTP 服務(wù)A,format_string, 該操作關(guān)聯(lián)另一個(gè)Span取名‘format’,并調(diào)用span.log_kv加入日志
  • 之后調(diào)用另一個(gè)HTTP 服務(wù)B,print_hello, 該操作關(guān)聯(lián)另一個(gè)Span取名‘println’,并調(diào)用span.log_kv加入日志
  • 對(duì)于每一個(gè)HTTP請(qǐng)求,在Span中都加入標(biāo)簽,標(biāo)志http method,http url和span kind。并調(diào)用tracer.inject把SpanContext注入到http header 中。

服務(wù)A代碼

  1. from flask import Flask 
  2. from flask import request 
  3. from lib.tracing import init_tracer 
  4. from opentracing.ext import tags 
  5. from opentracing.propagation import Format ​ 
  6. app = Flask(__name__) 
  7. tracer = init_tracer('formatter')    
  8. @app.route("/format"
  9. def format(): 
  10.  span_ctx = tracer.extract(Format.HTTP_HEADERS, request.headers) 
  11.  span_tags = {tags.SPAN_KIND: tags.SPAN_KIND_RPC_SERVER} 
  12.  with tracer.start_active_span('format', child_of=span_ctx, tags=span_tags): 
  13.  hello_to = request.args.get('helloTo'
  14.  return 'Hello, %s!' % hello_to 
  15. if __name__ == "__main__"
  16.  app.run(port=8081) 

服務(wù)A響應(yīng)format請(qǐng)求,調(diào)用tracer.extract從http headers中提取信息,構(gòu)建spanContext。

服務(wù)B代碼

  1. from flask import Flask 
  2. from flask import request 
  3. from lib.tracing import init_tracer 
  4. from opentracing.ext import tags 
  5. from opentracing.propagation import Format  
  6. app = Flask(__name__) 
  7. tracer = init_tracer('publisher'
  8. @app.route("/publish"
  9. def publish(): 
  10.  span_ctx = tracer.extract(Format.HTTP_HEADERS, request.headers) 
  11.  span_tags = {tags.SPAN_KIND: tags.SPAN_KIND_RPC_SERVER} 
  12.  with tracer.start_active_span('publish', child_of=span_ctx, tags=span_tags): 
  13.  hello_str = request.args.get('helloStr'
  14.  print(hello_str) 
  15.  return 'published' ​ 
  16. if __name__ == "__main__"
  17.  app.run(port=8082) 

服務(wù)B和A類似。

之后在支持分布式追蹤的軟件UI上(下圖是Jaeger UI),就可以看到類似下圖的追蹤信息。我們可以看到服務(wù)hello-word和三個(gè)操作say-hello/format/println的詳細(xì)追蹤信息。

一文讀懂微服務(wù)監(jiān)控之分布式追蹤

當(dāng)前有很多分布式追蹤軟件都提供了OpenTracing的支持,包括:Jaeger,LightStep,Instanna,Apache SkyWalking,inspectIT,stagemonitor,Datadog,Wavefront,Elastic APM等等。其中作為開源軟件的Zipkin(http://1t.click/6Ec)和Jaeger(http://1t.click/6DY)最為流行。

Zipkin

Zipkin(http://1t.click/6Ec)是Twitter基于Dapper開發(fā)的分布式追蹤系統(tǒng)。它的設(shè)計(jì)架構(gòu)如下圖:

一文讀懂微服務(wù)監(jiān)控之分布式追蹤
  • 藍(lán)色實(shí)體是Zipkin要追蹤的目標(biāo)組件,Non-Intrumented Server表示不直接調(diào)用Tracing API的微服務(wù)。通過Intrumented Client從Non-Intrumented Server中收集信息并發(fā)送給Zipkin的收集器Collector。Intrumented Server 直接調(diào)用Tracing API,發(fā)送數(shù)據(jù)到Zipkin的收集器。
  • Transport是傳輸通道,可以通過HTTP直接發(fā)送到Zipkin或者通過消息/事件隊(duì)列的方式。
  • Zipkin本身是一個(gè)Java應(yīng)用,包含了:收集器Collector負(fù)責(zé)數(shù)據(jù)采集,對(duì)外提供數(shù)據(jù)接口;存儲(chǔ);API和UI。

Zipkin的用戶界面像這個(gè)樣子:

一文讀懂微服務(wù)監(jiān)控之分布式追蹤
一文讀懂微服務(wù)監(jiān)控之分布式追蹤

Zipkin官方支持以下幾種語言的客戶端:C#,Go,Java,JavaScript,Ruby,Scala,PHP。開源社區(qū)也有其它語言的支持。

Zipkin發(fā)展到現(xiàn)在有快4年的時(shí)間,是一個(gè)相對(duì)成熟的項(xiàng)目。

Jaeger

Jaeger(http://1t.click/6DY)最早是由Uber開發(fā)的分布式追蹤系統(tǒng),同樣基于Dapper的設(shè)計(jì)理念。現(xiàn)在Jaeger是CNCF(Cloud Native Computing Foundation)的一個(gè)項(xiàng)目。如果你對(duì)CNCF這個(gè)組織有所了解,那么你可以推測(cè)出這個(gè)項(xiàng)目應(yīng)該和Kubernetes有非常緊密的集成。

Jaeger基于分布式的架構(gòu)設(shè)計(jì),主要包含以下幾個(gè)組件:

  1. Jaeger Client,負(fù)責(zé)在客戶端收集跟蹤信息。
  2. Jaeger Agent,負(fù)責(zé)和客戶端通信,把收集到的追蹤信息上報(bào)個(gè)收集器 Jaeger Collector
  3. Jaeger Colletor把收集到的數(shù)據(jù)存入數(shù)據(jù)庫或者其它存儲(chǔ)器
  4. Jaeger Query 負(fù)責(zé)對(duì)追蹤數(shù)據(jù)進(jìn)行查詢
  5. Jaeger UI負(fù)責(zé)用戶交互

這個(gè)架構(gòu)很像ELK,Collector之前類似Logstash負(fù)責(zé)采集數(shù)據(jù),Query類似Elastic負(fù)責(zé)搜索,而UI類似Kibana負(fù)責(zé)用戶界面和交互。這樣的分布式架構(gòu)使得Jaeger的擴(kuò)展性更好,可以根據(jù)需要,構(gòu)建不同的部署。

Jaeger作為分布式追蹤的后起之秀,隨著云原生和K8s的廣泛采用,正變得越來越流行。利用官方給出的K8s部署模版(http://1t.click/6DU),用戶可以快速的在自己的k8s集群上部署Jaeger。

4.分布式跟蹤系統(tǒng)——產(chǎn)品對(duì)比

當(dāng)然除了支持OpenTracing標(biāo)準(zhǔn)的產(chǎn)品之外,還有其它的一些分布式追蹤產(chǎn)品。這里引用一些其它博主的分析,給大家一些參考:

  • 調(diào)用鏈選型之Zipkin,Pinpoint,SkyWalking,CAT(http://1t.click/6tY)
  • 分布式調(diào)用鏈調(diào)研(pinpoint,skywalking,jaeger,zipkin等對(duì)比)(http://1t.click/6DK)
  • 分布式跟蹤系統(tǒng)——產(chǎn)品對(duì)比(http://1t.click/6ug)

5.總結(jié)

在微服務(wù)大行其道,云原生成為架構(gòu)設(shè)計(jì)的主流的情況下,微服務(wù)系統(tǒng)監(jiān)控,包含日志,指標(biāo)和追蹤成為了系統(tǒng)工程的重中之重。OpenTracing基于Dapper的分布式追蹤設(shè)計(jì)理念,定義了分布式追蹤的實(shí)現(xiàn)標(biāo)準(zhǔn)。在開源項(xiàng)目中,Zipkin和Jaeger是相對(duì)優(yōu)秀的選擇。尤其是Jaeger,由于對(duì)云原生框架的良好集成,是構(gòu)建微服務(wù)追蹤系統(tǒng)的必備良器。

責(zé)任編輯:華軒 來源: EAWorld
相關(guān)推薦

2023-09-20 22:56:45

分布式追蹤應(yīng)用程序

2023-09-21 16:10:44

2016-10-25 14:35:05

分布式系統(tǒng) 存儲(chǔ)

2024-07-09 08:11:56

2022-09-21 16:56:16

設(shè)計(jì)模式微服務(wù)架構(gòu)

2025-03-05 00:05:50

2016-09-01 13:48:18

2022-09-25 22:19:24

Dapr分布式追蹤

2022-07-13 09:53:58

分布式開發(fā)

2024-05-27 10:42:55

2021-01-25 15:00:44

微服務(wù)分布式日志

2020-09-11 09:44:04

微服務(wù)分布式鏈路

2020-06-10 10:20:24

微服務(wù)架構(gòu)WEB2.0

2021-08-27 10:14:16

Thanos監(jiān)控開源

2021-08-09 10:20:04

Thanos監(jiān)控架構(gòu)

2022-12-21 08:40:05

限流器分布式限流

2019-05-28 10:30:16

Java架構(gòu)微服務(wù)

2025-01-10 08:42:27

分布式服務(wù)發(fā)布Dubbo

2017-10-20 13:39:29

分布式系統(tǒng)數(shù)據(jù)存儲(chǔ)數(shù)據(jù)量

2017-11-08 09:57:00

分布式微服務(wù)集群
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)