go-kit微服務:服務鏈路追蹤

鏈路追蹤

現代互聯網服務一般是使用複雜的、大規模的分佈式系統來實現的。這些應用程序每每是由大量的軟件模塊構建的,並且這些軟件模塊可能由不一樣的團隊開發,可能使用不一樣的編程語言,而且能夠跨多個物理設施跨越數千臺機器。在這種環境中,幫助理解系統行爲和性能問題推理的工具是很是寶貴的。git

微服務架構是一個分佈式架構,實際開發中,咱們按照業務要求劃分服務單元,一套系統每每會由多個業務單元構成。在這個場景中,一個請求可能須要經歷多個業務單元的處理才能完成響應,若是出現了錯誤或異常,很難定位。github

爲了解決這個問題,谷歌開源了分佈式鏈路追蹤組件Drapper,並發表論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》介紹了Drapper的設計思想。在該論文的影響下,Twitter設計、研發並開源了分佈式鏈路追蹤系統Zipkin。golang

Zipkin

Zipkin是一個分佈式跟蹤系統,它能夠幫助收集時間數據,以此解決在微服務架構下的延遲問題。它同時提供了分佈式系統時間數據的收集和查詢功能。Zipkin的架構以下圖所示:docker

Zipkin官方架構圖

經過架構圖可知,Zipkin由Collector、Storage、API、UI共4個組件構成,Reporter由應用系統提供並收集數據,其工做原理大概以下:數據庫

  • 在應用程序中嵌入追蹤器(Tracer),它使用Span記錄應用程序動做的時間和元數據信息;
  • Reporter把Span發送至Zipkin的數據收集器Collector;
  • Collector經過Storage組件把數據存儲至數據庫;
  • UI組件經過API接口查詢追蹤數據並顯示;

Zipkin經過Trace結構表示對一次請求的跟蹤,一次請求由若干服務處理,每一個服務生成一個Span,同一請求的Span之間存在關聯關係,在UI組件中以樹形式展現。Span的主要數據模型以下所示:編程

字段 類型 說明
traceId string 隨機生成,用於惟一標識一個追蹤信息,全部的span都包含此信息。
name string span的名稱,可以使用method命名,在UI組件中顯示
parentId string 父級span的編號,若爲空,則表示爲根span
id string span的編號
timestamp integer span建立的時間
duration integer span持續時間
annotations Annotation 關聯一個事件,用時間戳解釋延遲信息
tags Tags span的標籤,用於搜索、顯示和分析

Zipkin官方已經推出各類常見語言的支持,如C#、go、Java、JavaScript、Ruby、Scala、PHP,另外社區也貢獻了Python、C/C++、Lua等語言的支持。bootstrap

實戰演練

Step-0:準備工做

本文將延續「go-kit微服務系列」,使用go-kit集成Zipkin實現算術運算服務的鏈路追蹤,這裏將包含兩個部分:segmentfault

  • 在網關gateway中增長鏈路追蹤採集邏輯,同時在反向代理中增長追蹤設置。
  • 在算術運算服務的傳輸層和Endpoint層增長鏈路追蹤採集邏輯。

go-kit在tracing包中默認添加了zipkin的支持,因此集成工做將會比較輕鬆。在開始以前,須要下載如下依賴:api

# zipkin官方庫
go get github.com/openzipkin/zipkin-go

# 下面三個包都是依賴,按需下載
git clone https://github.com/googleapis/googleapis.git [your GOPATH]/src/google.golang.org/genproto

git clone https://github.com/grpc/grpc-go.git [your GOPATH]/src/google.golang.org/grpc

git clone https://github.com/golang/text.git [your GOPATH]/src/golang.org/text
複製代碼

本次演練使用arithmetic_consul_demo中的gatewayregister兩個服務,複製該目錄並重命名爲arithmetic_trace_demo,刪除discover瀏覽器

Step-1:Docker啓動Zipkin

  1. 打開文件docker/docker-compose.yml,在consul的基礎上增長zipkin配置信息(使用官方推薦的openzipkin/zipkin),最終內容以下所示:
version: '2'

services:
  consul:
    image: progrium/consul:latest
    ports:
      - 8400:8400
      - 8500:8500
      - 8600:53/udp
    hostname: consulserver
    command: -server -bootstrap -ui-dir /ui

  zipkin:
    image: openzipkin/zipkin
    ports:
      - 9411:9411
複製代碼
  1. 打開終端切換至docker目錄,執行如下命令,啓動consul和zipkin。
sudo docker-compose up
複製代碼
  1. 啓動成功後,打開瀏覽器輸入http://localhost:9411檢查是否啓動成功。

Step-2:修改gateway

gateway將做爲鏈路追蹤的第一站和最後一站,咱們須要截獲到達gateway的全部請求,記錄追蹤信息。gateway做爲外部請求的服務端,同時做爲算術運算服務的客戶端(反向代理內部實現)。

建立追蹤器

結合Zipkin的架構圖,須要在應用程序中集成Reporter組件,咱們使用官方提供的go包。代碼以下(默認設置了zipkin的url):

// 建立環境變量
var (
	// consul環境變量省略
	zipkinURL  = flag.String("zipkin.url", "http://192.168.192.146:9411/api/v2/spans", "Zipkin server url")
	)
flag.Parse()

var zipkinTracer *zipkin.Tracer
{
	var (
		err           error
		hostPort      = "localhost:9090"
		serviceName   = "gateway-service"
		useNoopTracer = (*zipkinURL == "")
		reporter      = zipkinhttp.NewReporter(*zipkinURL)
	)
	defer reporter.Close()
	zEP, _ := zipkin.NewEndpoint(serviceName, hostPort)
	zipkinTracer, err = zipkin.NewTracer(
		reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer),
	)
	if err != nil {
		logger.Log("err", err)
		os.Exit(1)
	}
	if !useNoopTracer {
		logger.Log("tracer", "Zipkin", "type", "Native", "URL", *zipkinURL)
	}
}
複製代碼

爲全部請求增長鏈路追蹤

咱們使用的傳輸方式爲http,可使用zipkin-go提供的middleware/http包,它採用裝飾者模式把咱們的http.Handler進行封裝,而後啓動監聽便可,代碼以下所示:

//建立反向代理
proxy := NewReverseProxy(consulClient, zipkinTracer, logger)

tags := map[string]string{
	"component": "gateway_server",
}

handler := zipkinhttpsvr.NewServerMiddleware(
	zipkinTracer,
	zipkinhttpsvr.SpanName("gateway"),
	zipkinhttpsvr.TagResponseSize(true),
	zipkinhttpsvr.ServerTags(tags),
)(proxy)
複製代碼

反向代理設置

gateway接收請求後,會建立一個span,其中的traceId將做爲本次請求的惟一編號,gateway必須把這個traceId「告訴」算術運算服務,算術運算服務才能爲該請求持續記錄追蹤信息。

ReverseProxy中可以完成這一任務的就是Transport,咱們可使用zipkin-gomiddleware/http包提供的NewTransport替換系統默認的http.DefaultTransport。代碼以下所示:

// NewReverseProxy 建立反向代理處理方法
func NewReverseProxy(client *api.Client, zikkinTracer *zipkin.Tracer, logger log.Logger) *httputil.ReverseProxy {

	//建立Director
	director := func(req *http.Request) {
        //省略
	}

	// 爲反向代理增長追蹤邏輯,使用以下RoundTrip代替默認Transport
	roundTrip, _ := zipkinhttpsvr.NewTransport(zikkinTracer, zipkinhttpsvr.TransportTrace(true))

	return &httputil.ReverseProxy{
		Director:  director,
		Transport: roundTrip,
	}
}
複製代碼

這一步很關鍵!若不設置,會致使整個鏈路追蹤不完整。爲了解決這個問題,花費了很多時間,最後仍是經過zipkin-goREADME解開了疑惑。

完成以上過程,就能夠編譯運行了。

Step-3:修改算術服務

建立追蹤器

這一步與gateway的處理方式同樣,再也不描述。

追蹤Endpoint

go-kit提供了對zipkin-go的封裝,可直接調用中間件TraceEndpoint對算術運算服務的兩個Endpoint進行設置。代碼以下:

endpoint := MakeArithmeticEndpoint(svc)
endpoint = NewTokenBucketLimitterWithBuildIn(ratebucket)(endpoint)
//添加追蹤,設置span的名稱爲calculate-endpoint
endpoint = kitzipkin.TraceEndpoint(zipkinTracer, "calculate-endpoint")(endpoint)

//建立健康檢查的Endpoint
healthEndpoint := MakeHealthCheckEndpoint(svc)
healthEndpoint = NewTokenBucketLimitterWithBuildIn(ratebucket)(healthEndpoint)
//添加追蹤,設置span的名稱爲health-endpoint
healthEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "health-endpoint")(healthEndpoint)
複製代碼

追蹤Transport

  1. 修改transports.goMakeHttpHandler方法。增長參數zipkinTracer,而後在ServerOption中設置追蹤參數。代碼以下:
// MakeHttpHandler make http handler use mux
func MakeHttpHandler(ctx context.Context, endpoints ArithmeticEndpoints, zipkinTracer *gozipkin.Tracer, logger log.Logger) http.Handler {
	r := mux.NewRouter()

	zipkinServer := zipkin.HTTPServerTrace(zipkinTracer, zipkin.Name("http-transport"))

	options := []kithttp.ServerOption{
		kithttp.ServerErrorLogger(logger),
		kithttp.ServerErrorEncoder(kithttp.DefaultErrorEncoder),
		zipkinServer,
	}

	//省略代碼

	return r
}
複製代碼
  1. main.go中調用MakeHttpHandler
//建立http.Handler
r := MakeHttpHandler(ctx, endpts, zipkinTracer, logger)
複製代碼

至此,全部的代碼修改工做已經完成,下一步就是啓動測試了。

Step-4:運行&測試

確保ConsulZipkingatewayregister四個服務已經正常運行,而後使用Postman進行請求測試(與以前相似,爲了方便查看數據,可多點幾回)。

在瀏覽器中打開http://localhost:9411,點擊「Find Traces」按鈕,便可看到以下界面。詳細顯示了每一個請求執行的時間、span的數量、途徑的服務名稱等信息。

打開第一個請求,進入該請求的鏈路追蹤界面,以下圖所示。

鏈路追蹤

  • 上半部分顯示:,該請求的執行時間爲10.970毫秒、途徑的服務爲2個、鏈路深度爲三、span數量爲3。
  • 下半部分顯示:以樹形方式顯示span,直觀展現每一個span的途徑服務、執行時間、span名稱等信息。

經過該界面,咱們能夠知道請求鏈路中比較耗時的環節爲gateway-service。緣由是:每次請求過來,程序都要到Consul中查詢服務實例,動態建立服務地址。

另外,點擊樹形結構的每一個span,能夠查看span的描述信息,這裏再也不展開描述。

總結

本文使用go-kit的tracing組件和zipkin-go包,爲網關服務和算術運算服務增長了鏈路追蹤功能,以實例方式演示了在go-kit中集成Zipkin的方式。示例比較簡單,但願對你有用!

本文參考

本文首發於本人微信公衆號【兮一昂吧】,歡迎掃碼關注!

相關文章
相關標籤/搜索