Tracing 中间件使用 OpenTelemetry 实现了链路追踪。
OpenTelemetry & jaeger
我们需要了解open telemetry Jaeger 什么及他们的关系
两个产品合并,首先要考虑的是什么?有过经验的同学都知道:如何让两边的用户能够继续使用。因此新项目首要核心目标就是兼容OpenTracing和OpenCensus。
OpenTelemetry的核心工作目前主要集中在3个部分:
- 规范的制定和协议的统一,规范包含数据传输、API的规范,协议的统一包含:HTTP W3C的标准支持及GRPC等框架的协议标准
- 多语言SDK的实现和集成,用户可以使用SDK进行代码自动注入和手动埋点,同时对其他三方库(Log4j、LogBack等)进行集成支持;
- 数据收集系统的实现,当前是基于OpenCensus Service的收集系统,包括Agent和Collector。
由此可见,OpenTelemetry的自身定位很明确:数据采集和标准规范的统一,对于数据如何去使用、存储、展示、告警,官方是不涉及的,我们目前推荐使用Prometheus + Grafana做Metrics存储、展示,使用Jaeger做分布式跟踪的存储和展示。
jeager 安装
# pull images
docker pull jaegertracing/all-in-one:1.38
# run images
docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 14268:14268 -p 14250:14250 -p 9411:9411 jaegertracing/all-in-one:1.38
jaeger UI 访问http://localhost:16686/search
添加trace 链路
grpc 服务app/user/internal/server/grpc.go 添加链路
package server
import (
"github.com/go-kratos/kratos/v2/middleware/tracing"
v1 "kratos-tiway/api/user/v1"
"kratos-tiway/app/user/internal/conf"
"kratos-tiway/app/user/internal/service"
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware/recovery"
"github.com/go-kratos/kratos/v2/transport/grpc"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/sdk/resource"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
// 设置全局trace
func initTracer(url string) error {
// 创建 Jaeger exporter
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
if err != nil {
return err
}
tp := tracesdk.NewTracerProvider(
// 将基于父span的采样率设置为100%
tracesdk.WithSampler(tracesdk.ParentBased(tracesdk.TraceIDRatioBased(1.0))),
// 始终确保再生成中批量处理
tracesdk.WithBatcher(exp),
// 在资源中记录有关此应用程序的信息
tracesdk.WithResource(resource.NewSchemaless(
semconv.ServiceNameKey.String("kratos-tiway.user"),
attribute.String("exporter", "jaeger"),
attribute.Float64("float", 312.23),
)),
)
otel.SetTracerProvider(tp)
return nil
}
// NewGRPCServer new a gRPC server.
func NewGRPCServer(c *conf.Server, user *service.UserService, logger log.Logger) *grpc.Server {
err := initTracer("http://localhost:14268/api/traces")
if err != nil {
panic(err)
}
var opts = []grpc.ServerOption{
grpc.Middleware(
recovery.Recovery(),
tracing.Server(),
),
}
if c.Grpc.Network != "" {
opts = append(opts, grpc.Network(c.Grpc.Network))
}
if c.Grpc.Addr != "" {
opts = append(opts, grpc.Address(c.Grpc.Addr))
}
if c.Grpc.Timeout != nil {
opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration()))
}
srv := grpc.NewServer(opts...)
v1.RegisterUserServer(srv, user)
return srv
}