Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: rfc for tracing in pixiu #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

maxingg
Copy link

@maxingg maxingg commented Mar 16, 2022

The main ideas about this proposal are as follows:

  1. choose jeager to adapt various sampling strategies.
  2. build an abstract layer for trace to accept different protocols.

@maxingg
Copy link
Author

maxingg commented Mar 17, 2022

@ztelur


The tracerManager structure is as follows:
```go
type TracerManager struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是不是有一个抽象的 TracerManager,然后其中一个实现是 JaegerManager,这样后续更容易扩展其他的分布式追踪后端?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TracerManager是管理所有的driver,目前只有默认的JaegerDriver,后续可以根据需要扩展成map。

defer rootSpan.Finish()
s.ls.FilterChain.ServeHTTP(w, r.WithContext(ctx))

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以分别添加一下,在 Networkfilter 和 HttpFilter 中使用 Tracer 进行上报的案例。比如说在 https://github.com/apache/dubbo-go-pixiu/blob/develop/pkg/filter/http/remote/call.go 中或者 https://github.com/apache/dubbo-go-pixiu/blob/develop/pkg/common/grpc/manager.go 也想要进行记录

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对tracer.go进行修改,及时删改追踪完成的trace。

type Tracer struct {
	Id String
	T opentracing.Tracer
	closer io.Closer
}

func (t *Tracer) Close() {
	delete(holder.tracers, t.Id)
	t.Close()
}

当http_listener监听到HTTP请求:

tracer, _, _ := NewTracer("HTTP") 
defer tracer.Close()
rootSpan := tracer.StartSpan("http-listener")
ctx := tracer.T.ContextWithSpan(r.Context(), rootSpan)
defer rootSpan.Finish()

s.ls.FilterChain.ServeHTTP(w, r.WithContext(ctx))

HTTPConnectionManager 中追踪:
我们抽离出获取Tracer的公共方法:

// TODO 增强代码健壮性
func GetTracer(protocolName, tracerId string)  api.Tracer {
  driver := GetTraceDriverManager().getDriver()
  return driver.getTracer(prtocolName, traceId);
}
func (hcm *HttpConnectionManager) ServeHTTP(w stdHttp.ResponseWriter, r *stdHttp.Request) {
  ...
  hc.Reset()
  
  traceId := r.Header.Get("trace-id")
	tracer := trace.GetTracer("HTTP", traceId)

	hcmSpan, spanContext := opentracing.StartSpanFromContextWithTracer(r.Context(), tracer, "Filter---HttpConnectionManager封装HttpContext")
	hc.Ctx = spanContext
	defer hcmSpan.Finish()
  
  err := hcm.Handle(hc)
	...
}


func (hcm *HttpConnectionManager) Handle(hc *pch.HttpContext) error {
	// hc.Ctx = context.Background()
  traceId := hc.Request.Header.Get("trace-id")
  tracer := trace.GetTracer("HTTP", traceId)
  hcmSpan, spanContext := opentracing.StartSpanFromContextWithTracer(r.Context(), tracer, "Filter---HttpConnectionManager查找路由,确定集群")
	hc.Ctx = spanContext
	defer hcmSpan.Finish()
  
	err := hcm.findRoute(hc)
	if err != nil {
		return err
	}
	hcm.handleHTTPRequest(hc)
	return nil
}

Note:hcm这里是一个空Context,这里直接注释了源代码。另外,在NetWorkFilter和HttpFilter中的处理过程与上述过程基本一致,不再演示。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个看起来不错,将一些细节隐藏到共有的抽象方法中,真正要使用 tracer 进行记录的位置只感知项目提供的接口,不需要了解底层的具体实现

Disabled bool
//默认是HTTP
ServiceName string
Driver string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是否需要不同 driver 所特有的 config 字段?比如 skywalking 的配置和 jaeger 的配置数据可能有些差异

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前只考虑了jaeger,可以考虑扩充:

type TracerConfigs struct {
	jaegerConfig JaegerConfig
	skywalking SkyWalkingConfig
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

一阶段可以只支持 jaeger,但是需要考虑并给出扩展机制,可以按照后续要支持 skywalking为例进行说明。比如说 :

  1. 不同的driver类型如何进行识别和读取不同的config设置到对应的变量中;
  2. 初始化建立 TracerProvider 时可能的差异怎么处理;
  3. 不同 lib 如果有 api 方面差异,如何统一使用,比如说 StartSpan。

可以和下面的 DriverManager 一起进行扩展性描述。

@mark4z
Copy link
Contributor

mark4z commented Mar 27, 2022

rename file name to ur [$feature-$version]

@maxingg
Copy link
Author

maxingg commented Mar 29, 2022

model包下的TraceConfig如下:

type TracerConfig struct {
	Name    string
	Sampler Sampler
	Config  interface{}
}
type Sampler struct {
	Type  string
	Param float64
}

系统的trace采用otel,driver结构如下:

type Holder struct {
	Tracers map[string]protocol.Trace
	Id      uint64
}
type TraceDriver struct {
	holders map[protocolName]*Holder
	tp      *sdktrace.TracerProvider
	context context.Context
}

holder中Tracers的键会使用Id进行拼接之后原子递增,保证唯一性。在TraceDriverManager的初始化中,主要是对driver的初始化,包括设置exprter(支持jaeger,otlp等)和TraceProvider。

func (driver *TraceDriver) Init(bs *model.Bootstrap) *TraceDriver {
	config := bs.Trace
	ctx := context.Background()
	exp, err := newExporter(ctx, config)
	if err != nil {
		//TODO 错误处理
		return nil
	}
	provider := newTraceProvider(exp, config)

	otel.SetTracerProvider(provider)

	return &TraceDriver{
		tp: provider,
	}
} 

其中可根据config的name属性选择不同的exporter设置,并在TraceProvider的生成中设置采样率。

为支持不同协议请求的Tracer,提供Trace接口,并提供默认实现Tracer。如果其他协议请求(比如HTTP)支持自己协议的span方法,重写部分方法即可。

type Trace interface {
	GetId() string
	StartSpan(name string, request interface{}) (context.Context, trace.Span)
	StartSpanFromContext(name string, tx context.Context) (context.Context, trace.Span)
	Close()
}

type Tracer struct {
	Id string
	T  trace.Tracer
	H  *trace2.Holder
}

type HTTPTracer struct {
	*Tracer
}

func (t *Tracer) GetId() string {
	return t.Id
}

func (t *Tracer) Close() {
	delete(t.H.Tracers, t.Id)
}

func (t *Tracer) StartSpan(name string, request interface{}) (context.Context, trace.Span) {
	return t.T.Start(request.(*http.Request).Context(), name)
}

func (t *Tracer) StartSpanFromContext(name string, ctx context.Context) (context.Context, trace.Span) {
	return t.T.Start(ctx, name)
}

func (t *HTTPTracer) StartSpan(name string, request interface{}) (context.Context, trace.Span) {
	...
}

func (t *HTTPTracer) StartSpanFromContext(name string, ctx context.Context) (context.Context, trace.Span) {
	...
}

最终在程序中调用流程如下:

//http_listener.go
func (s *DefaultHttpWorker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	tracer := trace.NewTracer(trace.HTTP)
	defer tracer.Close()
	ctx, span := tracer.StartSpan("http", r)
	defer span.End()
	r.Header.Set("trace-id", tracer.GetId())
	
	s.ls.FilterChain.ServeHTTP(w, r.WithContext(ctx))
}

//manager.go

func (hcm *HttpConnectionManager) ServeHTTP(w stdHttp.ResponseWriter, r *stdHttp.Request) {
	...
	traceId := r.Header.Get("trace-id")
	tracer, _ := trace.GetTracer(trace.HTTP, traceId)
	ctx, span := tracer.StartSpanFromContext("HttpConnectionManager", hc.Ctx)
	defer span.End()
	hc.Ctx = ctx
	...
}

@ztelur

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants