Go gRPC 系列十:gRPC+Zipkin 分佈式鏈路追蹤

你們好,我是煎魚,在實際應用中,你作了那麼多 Server 端,寫了 N 個 RPC 方法。想看看方法的指標,卻無處下手?html

本文將經過 gRPC + Opentracing + Zipkin 搭建一個分佈式鏈路追蹤系統來實現查看整個系統的鏈路、性能等指標。git

Opentracing

是什麼

OpenTracing 經過提供平臺無關、廠商無關的API,使得開發人員可以方便的添加(或更換)追蹤系統的實現github

不過 OpenTracing 並非標準。由於 CNCF 不是官方標準機構,可是它的目標是致力爲分佈式追蹤建立更標準的 API 和工具golang

名詞解釋

Trace

一個 trace 表明了一個事務或者流程在(分佈式)系統中的執行過程docker

Span

一個 span 表明在分佈式系統中完成的單個工做單元。也包含其餘 span 的 「引用」,這容許將多個 spans 組合成一個完整的 Trace後端

每一個 span 根據 OpenTracing 規範封裝如下內容:api

  • 操做名稱
  • 開始時間和結束時間
  • key:value span Tags
  • key:value span Logs
  • SpanContext

Tags

Span tags(跨度標籤)能夠理解爲用戶自定義的 Span 註釋。便於查詢、過濾和理解跟蹤數據bash

Logs

Span logs(跨度日誌)能夠記錄 Span 內特定時間或事件的日誌信息。主要用於捕獲特定 Span 的日誌信息以及應用程序自己的其餘調試或信息輸出架構

SpanContext

SpanContext 表明跨越進程邊界,傳遞到子級 Span 的狀態。常在追蹤示意圖中建立上下文時使用app

Baggage Items

Baggage Items 能夠理解爲 trace 全局運行中額外傳輸的數據集合

一個案例

image

圖中能夠看到如下內容:

  • 執行時間的上下文
  • 服務間的層次關係
  • 服務間串行或並行調用鏈

結合以上信息,在實際場景中咱們能夠經過整個系統的調用鏈的上下文、性能等指標信息,一會兒就可以發現系統的痛點在哪兒

Zipkin

image

是什麼

Zipkin 是分佈式追蹤系統。它的做用是收集解決微服務架構中的延遲問題所需的時序數據。它管理這些數據的收集和查找

Zipkin 的設計基於 Google Dapper 論文。

運行

docker run -d -p 9411:9411 openzipkin/zipkin
複製代碼

其餘方法安裝參見:github.com/openzipkin/…

驗證

訪問 http://127.0.0.1:9411/zipkin/ 檢查 Zipkin 是否運行正常

image

gRPC + Opentracing + Zipkin

在前面的小節中,咱們作了如下準備工做:

  • 瞭解 Opentracing 是什麼
  • 搭建 Zipkin 提供分佈式追蹤系統的功能

接下來實現 gRPC 經過 Opentracing 標準 API 對接 Zipkin,再經過 Zipkin 去查看數據

目錄結構

新建 simple_zipkin_client、simple_zipkin_server 目錄,目錄結構以下:

go-grpc-example
├── LICENSE
├── README.md
├── client
│   ├── ...
│   ├── simple_zipkin_client
├── conf
├── pkg
├── proto
├── server
│   ├── ...
│   ├── simple_zipkin_server
└── vendor
複製代碼

安裝

$ go get -u github.com/openzipkin/zipkin-go-opentracing
$ go get -u github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc
複製代碼

gRPC

Server

package main

import (
	"context"
	"log"
	"net"

	"github.com/grpc-ecosystem/go-grpc-middleware"
	"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
	zipkin "github.com/openzipkin/zipkin-go-opentracing"
	"google.golang.org/grpc"

	"github.com/EDDYCJY/go-grpc-example/pkg/gtls"
	pb "github.com/EDDYCJY/go-grpc-example/proto"
)

type SearchService struct{}

func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
	return &pb.SearchResponse{Response: r.GetRequest() + " Server"}, nil
}

const (
	PORT = "9005"

	SERVICE_NAME              = "simple_zipkin_server"
	ZIPKIN_HTTP_ENDPOINT      = "http://127.0.0.1:9411/api/v1/spans"
	ZIPKIN_RECORDER_HOST_PORT = "127.0.0.1:9000"
)

func main() {
	collector, err := zipkin.NewHTTPCollector(ZIPKIN_HTTP_ENDPOINT)
	if err != nil {
		log.Fatalf("zipkin.NewHTTPCollector err: %v", err)
	}

	recorder := zipkin.NewRecorder(collector, true, ZIPKIN_RECORDER_HOST_PORT, SERVICE_NAME)

	tracer, err := zipkin.NewTracer(
		recorder, zipkin.ClientServerSameSpan(false),
	)
	if err != nil {
		log.Fatalf("zipkin.NewTracer err: %v", err)
	}

	tlsServer := gtls.Server{
		CaFile:   "../../conf/ca.pem",
		CertFile: "../../conf/server/server.pem",
		KeyFile:  "../../conf/server/server.key",
	}
	c, err := tlsServer.GetCredentialsByCA()
	if err != nil {
		log.Fatalf("GetTLSCredentialsByCA err: %v", err)
	}

	opts := []grpc.ServerOption{
		grpc.Creds(c),
		grpc_middleware.WithUnaryServerChain(
			otgrpc.OpenTracingServerInterceptor(tracer, otgrpc.LogPayloads()),
		),
	}
    ...
}
複製代碼
  • zipkin.NewHTTPCollector:建立一個 Zipkin HTTP 後端收集器
  • zipkin.NewRecorder:建立一個基於 Zipkin 收集器的記錄器
  • zipkin.NewTracer:建立一個 OpenTracing 跟蹤器(兼容 Zipkin Tracer)
  • otgrpc.OpenTracingClientInterceptor:返回 grpc.UnaryServerInterceptor,不一樣點在於該攔截器會在 gRPC Metadata 中查找 OpenTracing SpanContext。若是找到則爲該服務的 Span Context 的子節點
  • otgrpc.LogPayloads:設置並返回 Option。做用是讓 OpenTracing 在雙向方向上記錄應用程序的有效載荷(payload)

總的來說,就是初始化 Zipkin,其又包含收集器、記錄器、跟蹤器。再利用攔截器在 Server 端實現 SpanContext、Payload 的雙向讀取和管理

Client

func main() {
	// the same as zipkin server
	// ...
	conn, err := grpc.Dial(":"+PORT, grpc.WithTransportCredentials(c),
		grpc.WithUnaryInterceptor(
			otgrpc.OpenTracingClientInterceptor(tracer, otgrpc.LogPayloads()),
		))
	...
}
複製代碼
  • otgrpc.OpenTracingClientInterceptor:返回 grpc.UnaryClientInterceptor。該攔截器的核心功能在於:

(1)OpenTracing SpanContext 注入 gRPC Metadata

(2)查看 context.Context 中的上下文關係,若存在父級 Span 則建立一個 ChildOf 引用,獲得一個子 Span

其餘方面,與 Server 端是一致的,先初始化 Zipkin,再增長 Client 端特需的攔截器。就能夠完成基礎工做啦

驗證

啓動 Server.go,執行 Client.go。查看 http://127.0.0.1:9411/zipkin/ 的示意圖:

image

image

複雜點

image

image

來,本身實踐一下。

總結

在多服務下的架構下,串行、並行、服務套服務是一個很是常見的狀況,用常規的方案每每很難發現問題在哪裏(成本太大)。而這種狀況就是分佈式追蹤系統大展拳腳的機會了

但願你經過本章節的介紹和學習,可以瞭解其概念和搭建且應用一個追蹤系統。

若是有任何疑問或錯誤,歡迎在 issues 進行提問或給予修正意見,若是喜歡或對你有所幫助,歡迎 Star,對做者是一種鼓勵和推動。

個人博客

跟煎魚學 Go:github.com/eddycjy/blo…

個人公衆號

image

參考

本系列示例代碼

相關文章
相關標籤/搜索