微服务的可观测性大抵分为三大类:Metrics,Tracing 和 Logging。
Metrics 监控侧重于技术指标的收集与观测,如服务调用 QPS、响应工夫、错误率和资源使用率
Logging 侧重于运行日志的采集、存储与检索, 通常应用 ELK
Tracing 则偏差于调用链的串联、追踪与 APM 剖析, 服务与服务之间的调用耗时等等, 链路追踪。
一、对 grpc 服务进行监控
服务端
const (
serviceName = "simple_zipkin_server"
zipkinAddr = "http://127.0.0.1:9411/api/v1/spans"
zipkinRecorderAddr = "127.0.0.1:9000"
)
/*
获取 zipkin 的 tracer 对象,并把 tracer 封装成 ServerInterceptor 注入到 grpc.ServerOption 中
*/
func NewZipkinTracer(opts []grpc.ServerOption) (opentracing.Tracer, []grpc.ServerOption, error) {collector, err := zipkin.NewHTTPCollector(zipkinAddr)
if err != nil {log.Fatal(err.Error())
return nil, opts, err
}
recorder := zipkin.NewRecorder(collector, true, zipkinRecorderAddr, serviceName)
tracer, err := zipkin.NewTracer(recorder, zipkin.ClientServerSameSpan(true), zipkin.TraceID128Bit(true))
if err != nil {log.Fatal(err.Error())
return nil, opts, err
}
opts = append(opts, grpc_middleware.WithUnaryServerChain(otgrpc.OpenTracingServerInterceptor(tracer, otgrpc.LogPayloads()),
))
return tracer, opts, nil
}
func main() {
//...
go func() {
//...
var opts = []grpc.ServerOption{grpc.Creds(cred)}
_, opts, err = NewZipkinTracer(opts)
if err != nil {log.Fatal(err.Error())
return
}
rpcserver := grpc.NewServer(opts...)
//...
}
//...
}
客户端
const (
serviceName = "simple_zipkin_server"
zipkinAddr = "http://127.0.0.1:9411/api/v1/spans"
zipkinRecorderAddr = "127.0.0.1:9000"
)
/*
获取 zipkin 的 tracer 对象,并把 tracer 封装成 ClientInterceptor 注入到 grpc.DialOption 中
*/
func NewZipkinTracer(opts []grpc.DialOption) (opentracing.Tracer, []grpc.DialOption, error) {collector, err := zipkin.NewHTTPCollector(zipkinAddr)
if err != nil {log.Fatal(err.Error())
return nil, opts, err
}
recorder := zipkin.NewRecorder(collector, true, zipkinRecorderAddr, serviceName)
tracer, err := zipkin.NewTracer(recorder, zipkin.ClientServerSameSpan(true), zipkin.TraceID128Bit(true))
if err != nil {log.Fatal(err.Error())
return nil, opts, err
}
opts = append(opts, grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(tracer, otgrpc.LogPayloads()),
))
return tracer, opts, nil
}
func main() {
//...
var opts = []grpc.DialOption{grpc.WithTransportCredentials(creds)}
_, opts, err = NewZipkinTracer(opts)
if err != nil {log.Fatal(err.Error())
return
}
conn, err := grpc.Dial(fmt.Sprintf("%v:%d", addr.Service.Address, addr.Service.Port), opts...)
if err != nil {log.Fatal(err)
}
defer conn.Close()
//...
}
先后运行 server.go 和 client.go,进行一次 grpc 的调用;
拜访 http://localhost:9411/zipkin,抉择 ”serviceName” 为 ”simple_zipkin_server”
二、对 Gin 框架的 Web 服务进行监控
var (
zkReporter reporter.Reporter
zkTracer opentracing.Tracer
)
const (
serviceName = "zipkin_gin_server"
serviceEndpoint = "localhost:8080"
zipkinAddr = "http://127.0.0.1:9411/api/v2/spans"
)
func initZipkinTracer(engine *gin.Engine) error {zkReporter = zkHttp.NewReporter(zipkinAddr)
endpoint, err := zipkin.NewEndpoint(serviceName, serviceEndpoint)
if err != nil {log.Fatalf("unable to create local endpoint: %+v\n", err)
return err
}
nativeTracer, err := zipkin.NewTracer(zkReporter, zipkin.WithTraceID128Bit(true), zipkin.WithLocalEndpoint(endpoint))
if err != nil {log.Fatalf("unable to create tracer: %+v\n", err)
return err
}
zkTracer = zkOt.Wrap(nativeTracer)
opentracing.SetGlobalTracer(zkTracer)
// 将 tracer 注入到 gin 的中间件中
engine.Use(func(c *gin.Context) {span := zkTracer.StartSpan(c.FullPath())
defer span.Finish()
c.Next()})
return nil
}
func main() {engine := gin.Default()
err := initZipkinTracer(engine)
if err != nil {panic(err)
}
defer zkReporter.Close()
engine.GET("/ping", func(c *gin.Context) {c.JSON(http.StatusOK, "pong")
})
//...
engine.Run(":8080")
}
参考文章:
https://blog.csdn.net/feizaoS…