链路追踪
什么是链路追踪
链路追踪,全称分布式链路追踪。在微服务架构下,系统由大量服务组成,每个服务可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心…例如一次请求往往会涉及到多个服务,在系统发生故障的时候,快速定位和解决问题,就需要追踪服务请求序列。因此,分析性能问题的工具以及理解系统的行为变得很重要。链路追踪正是用于解决这个问题。
Vine 中通过 wrapper 实现链路追踪。
实例
我们提供一个简单的代码实例,来说明链路追踪的工作方式:
package main
import (
"context"
"fmt"
"time"
pb "github.com/vine-io/examples/wrapper/pb"
"github.com/vine-io/vine"
"github.com/vine-io/vine/core/client"
"github.com/vine-io/vine/core/client/grpc"
"github.com/vine-io/vine/core/registry"
"github.com/vine-io/vine/core/server"
log "github.com/vine-io/vine/lib/logger"
"github.com/vine-io/vine/lib/trace"
"github.com/vine-io/vine/lib/trace/memory"
"github.com/vine-io/vine/util/wrapper"
)
type hello struct {
}
func (h hello) Echo(ctx context.Context, request *pb.Request, response *pb.Response) error {
ctx, span := trace.DefaultTracer.Start(ctx, "echo")
defer trace.DefaultTracer.Finish(span)
response.Result = request.Name
return nil
}
func main() {
s := vine.NewService(
vine.WrapHandler(HandlerWrapper()),
)
s.Init()
pb.RegisterHelloHandler(s.Server(), &hello{})
go func() {
time.Sleep(time.Second)
// grpc 加载 trace wrapper
cli := grpc.NewClient(client.WrapCall(CallWrapper()))
cli = wrapper.TraceCall(s.Name(), memory.NewTracer(), cli)
cc := pb.NewHelloService(s.Name(), cli)
cc.Echo(context.TODO(), &pb.Request{"Client"})
}()
if err := s.Run(); err != nil {
log.Fatal(err)
}
}
func CallWrapper() client.CallWrapper {
return func(fn client.CallFunc) client.CallFunc {
return func(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
traceID, parentID, ok := trace.FromContext(ctx)
if ok {
fmt.Printf("call: tarceID=%s parentID=%s\n", traceID, parentID)
}
return fn(ctx, node, req, rsp, opts)
}
}
}
func HandlerWrapper() server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
traceID, parentID, ok := trace.FromContext(ctx)
if ok {
fmt.Printf("handle: tarceID=%s parentID=%s\n", traceID, parentID)
}
return fn(ctx, req, rsp)
}
}
}
新建链路
ctx = trace.ToContext(ctx, uuid.NewString(), uuid.NewString())
链路调用
// 新建链路
ctx, span := trace.Start(ctx, "echo")
// 停止 span
defer trace.Finish(span)
捕获链路
traceID, parentID, ok := trace.FromContext(ctx)
if ok {
fmt.Printf("call: tarceID=%s parentID=%s\n", traceID, parentID)
}
最后修改 September 7, 2021: trace (8771eb0)