天天看點

opentracing & jeager

簡介

opentracing是一個分布式追蹤系統的client接口标準。jeager是uber的tracing系統。

收集的資料

specification: https://opentracing.io/specification/
[1] https://developer.aliyun.com/article/514488
[2] http://peter.bourgon.org/blog/2017/02/21/metrics-tracing-and-logging.html?spm=a2c6h.12873639.0.0.61b453f6kQ1TwU
[3] https://github.com/opentracing/specification/blob/master/specification.md
[4] https://github.com/opentracing-contrib/opentracing-specification-zh/blob/master/semantic_conventions.md
[5] https://github.com/opentracing/opentracing-go
[6] https://github.com/yurishkuro/opentracing-tutorial/tree/master/go
[7] https://godoc.org/github.com/opentracing/opentracing-go
           

建議多看幾遍spec,比什麼部落格翻譯好多了。不得不說很多部落格和翻譯都很aji(include me)。

tracing的概述

https://github.com/opentracing/specification/blob/master/specification.md
https://blog.csdn.net/u013970991/article/details/77822060
           

What

從概念上而言,tracing是分布式追蹤工具,對分布式系統中的某request的流向進行追蹤。如上面的文章所言。

入侵式:

也因為tracing是追蹤具體的request的執行流,是以須有侵入式的方式植入代碼。

因為入侵式需要深入客戶代碼,顯然是不能依賴于其他公司的三方庫,是以大家隻有規範接口,而不同的公司的接口規範可能是不同的(大家想法不一樣嘛),是以需要标準化,接口的具體内容格式化顯然是不現實的(大家的需求不同),是以需要一個抽象層次比較高,且開源的标準。如是opentracing。

自定義實作:

在opentracing中隻是規範了互動标準,并沒有内容實作,是以我們需要去自定義實作Tracer,同時依賴開源的Tracer也是可以的。

OpenTracing的實作中,比較流行的為 Jaeger 和 Zipkin。

jeager

https://zhuanlan.zhihu.com/p/44824994
https://www.jaegertracing.io/docs/1.18/
           

jeager是對Tracing系統的實作。

Tracer

關于文檔,可以搜尋go doc,然後索引jeager-client
// TraceID represents unique 128bit identifier of a trace
type TraceID struct {
	High, Low uint64
}
// Tracer implements opentracing.Tracer.
type Tracer struct {
	serviceName string
	hostIPv4    uint32 // this is for zipkin endpoint conversion

	sampler  SamplerV2
	reporter Reporter
	metrics  Metrics
	logger   log.DebugLogger

	timeNow      func() time.Time
	randomNumber func() uint64

	options struct {
		gen128Bit                   bool // whether to generate 128bit trace IDs
		zipkinSharedRPCSpan         bool
		highTraceIDGenerator        func() uint64 // custom high trace ID generator
		maxTagValueLength           int
		noDebugFlagOnForcedSampling bool
		maxLogsPerSpan              int
		// more options to come
	}
	// allocator of Span objects
	spanAllocator SpanAllocator

	injectors  map[interface{}]Injector
	extractors map[interface{}]Extractor

	observer compositeObserver

	tags    []Tag
	process Process

	baggageRestrictionManager baggage.RestrictionManager
	baggageSetter             *baggageSetter

	debugThrottler throttler.Throttler
}
           

SpanContext

// TraceID represents unique 128bit identifier of a trace
type TraceID struct {
	High, Low uint64
}

// SpanID represents unique 64bit identifier of a span
type SpanID uint64

// SpanContext represents propagated span identity and state
type SpanContext struct {
	// traceID represents globally unique ID of the trace.
	// Usually generated as a random number.
	traceID TraceID

	// spanID represents span ID that must be unique within its trace,
	// but does not have to be globally unique.
	spanID SpanID

	// parentID refers to the ID of the parent span.
	// Should be 0 if the current span is a root span.
	parentID SpanID

	// Distributed Context baggage. The is a snapshot in time.
	baggage map[string]string

	// debugID can be set to some correlation ID when the context is being
	// extracted from a TextMap carrier.
	//
	// See JaegerDebugHeader in constants.go
	debugID string

	// samplingState is shared across all spans
	samplingState *samplingState

	// remote indicates that span context represents a remote parent
	remote bool
}
           

Span

// Span implements opentracing.Span
type Span struct {
	// referenceCounter used to increase the lifetime of
	// the object before return it into the pool.
	referenceCounter int32

	sync.RWMutex

	tracer *Tracer

	// TODO: (breaking change) change to use a pointer
	context SpanContext

	// The name of the "operation" this span is an instance of.
	// Known as a "span name" in some implementations.
	operationName string

	// firstInProcess, if true, indicates that this span is the root of the (sub)tree
	// of spans in the current process. In other words it's true for the root spans,
	// and the ingress spans when the process joins another trace.
	firstInProcess bool

	// startTime is the timestamp indicating when the span began, with microseconds precision.
	startTime time.Time

	// duration returns duration of the span with microseconds precision.
	// Zero value means duration is unknown.
	duration time.Duration

	// tags attached to this span
	tags []Tag

	// The span's "micro-log"
	logs []opentracing.LogRecord

	// The number of logs dropped because of MaxLogsPerSpan.
	numDroppedLogs int

	// references for this span
	references []Reference

	observer ContribSpanObserver
}
           

span的樣式

  1. https://opentracing.io/docs/overview/spans/

Example

Example Span:
    t=0            operation name: db_query               t=x

     +-----------------------------------------------------+
     | · · · · · · · · · ·    Span     · · · · · · · · · · |
     +-----------------------------------------------------+

Tags:
- db.instance:"customers"
- db.statement:"SELECT * FROM mytable WHERE foo='bar'"
- peer.address:"mysql://127.0.0.1:3306/customers"

Logs:
- message:"Can't connect to mysql server on '127.0.0.1'(10061)"

SpanContext:
- trace_id:"abc123"
- span_id:"xyz789"
- Baggage Items:
  - special_id:"vsid1738"
           

Observer

// Observer can be registered with the Tracer to receive notifications about
// new Spans.
//
// Deprecated: use jaeger.ContribObserver instead.
type Observer interface {
	OnStartSpan(operationName string, options opentracing.StartSpanOptions) SpanObserver
}

// SpanObserver is created by the Observer and receives notifications about
// other Span events.
//
// Deprecated: use jaeger.ContribSpanObserver instead.
type SpanObserver interface {
	OnSetOperationName(operationName string)
	OnSetTag(key string, value interface{})
	OnFinish(options opentracing.FinishOptions)
}
           

Observer作為觀察者,在觸發Span相關的事件的時候回調。

Metrics

https://godoc.org/github.com/uber/jaeger-lib/metrics#Factory
func Metrics(factory metrics.Factory) Option
// Metrics creates an Option that initializes Metrics in the tracer,
// which is used to emit statistics about spans.
func Metrics(factory metrics.Factory) Option {
	return func(c *Options) {
		c.metrics = factory
	}
}

type Factory interface {
    Counter(metric Options) Counter
    Timer(metric TimerOptions) Timer
    Gauge(metric Options) Gauge
    Histogram(metric HistogramOptions) Histogram

    // Namespace returns a nested metrics factory.
    Namespace(scope NSOptions) Factory
}
           

metrics用來上報統計資訊。

Log

type Logger
type Logger interface {
    // Error logs a message at error priority
    Error(msg string)

    // Infof logs a message at info priority
    Infof(msg string, args ...interface{})
}
//Logger provides an abstract interface for logging from Reporters. Applications can provide their own implementation of this interface to adapt reporters logging to whatever logging library they prefer (stdlib log, logrus, go-logging, etc).
           

關于Inject和Extract

>https://opentracing.io/specification/
>https://wu-sheng.gitbooks.io/opentracing-io/content/spec
           
The Tracer interface creates Spans and understands how to Inject (serialize) and Extract (deserialize) them across process boundaries. Formally, it has the following capabilities.

其實Inject和Extract就是序列化和反序列化的過程,序列化之後的SpanContext可以在rpc的metadata中傳遞,以期望達到SpanContext可以跨越程序的目的。詳細參考文章開頭的specification。