100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 35 jaeger链路追踪

35 jaeger链路追踪

时间:2024-04-30 20:47:41

相关推荐

35 jaeger链路追踪

目录

一、链路追踪1 - 链路追踪简介2 - 链路追踪技术选型3 - jaeger安装4 - jaeger组成5 - opentracing解析二、go使用jaeger1 - 发送单span2 - 发送嵌套span3 - grpc发送span三、goods_web集成jaeger1 - 添加nacos配置2 - 添加中间件3 - 初始化连接注入Tracer4 - api中调用grpc带上ctx5 - 优化otgrpc的源码四、order_web集成jaeger1 - 复制tracing和otgrpc到order_web中2 - router修改3 - grpc调用接口修改4 - 初始化连接注入Tracer5 - 添加nacos配置五、同步srv层和web层的jaeger1 - otgrpc原理分析2 - 初始化jaeger3 - 增加追踪的span4 - 过滤掉健康检查的jaeger六、完整源码

一、链路追踪

1 - 链路追踪简介

什么是链路追踪:分布式链路追踪就是将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等链路追踪主要功能: 故障快速定位:可以通过调用链结合业务日志快速定位错误信息链路性能可视化:各个阶段链路耗时、服务依赖关系可以通过可视化界面展现出来链路分析:通过分析链路耗时、服务依赖关系可以得到用户的行为路径,汇总分析应用在很多业务场景

2 - 链路追踪技术选型

3 - jaeger安装

jaeger官方地址:/jaegertracing/jaegerjaeger安装参考:/qq23001186/article/details/126339387

4 - jaeger组成

分布式追踪系统发展很快,种类繁多,但核心步骤一般有三个:代码埋点(我们来实现)、数据存储、查询展示

Jaeger组成Jaeger Client:为不同语言实现了符合OpenTracing标准的SDK.应用程序通过API写入数据,client library把trace信息按照应用程序指定的采样策略传递给jaeger-agentAgent:它是一个监听再UDP端口上接收span数据的网络守护进程,它会将数据批量发送给collector.它被设计成一个基础组件,部署到所有的宿主机上.Agent将client library和collector解耦,为client library屏蔽了路由和发现collector的细节collector:接收jaeger-agent发送来的数据.然后将数据写入到后端存储.collector被设计成无状态的组件,因此可以同事运行任意数量的jaeger-collectorData Store:后端存储被设计成一个可插拔的组件,支持将数据写入cassandra,elasticsearchQuery:接收查询请求,然后从后端存储系统中检索trace并通过UI进行展示.Query是无状态的,可以启动多个实例,把他们部署再nginx这样的负载均衡器后面

5 - opentracing解析

以下内容摘自:/developer/article/1846107

综述:这是正式的OpenTracing语义标准。OpenTracing是一个跨编程语言的标准,此文档会避免具有语言特性的概念。比如,我们在文档中使用"interface",因为所有的语言都包含"interface"这种概念

版本命名策略:OpenTracing标准使用Major.Minor版本命名策略(即:大版本.小版本),但不包含.Patch版本(即:补丁版本)。如果标准做出不向前兼容的改变,则使用“主版本”号提升。如果是向前兼容的改进,则进行小版本号提升,例如加入新的标准tag, log和SpanContext引用类型

OpenTracing数据模型

OpenTracing中的Trace(调用链)通过归属于此调用链的Span来隐性的定义。 特别说明,一条Trace(调用链)可以被认为是一个由多个Span组成的有向无环图(DAG图), Span与Span的关系被命名为References译者注: Span,可以被翻译为跨度,可以被理解为一次方法调用, 一个程序块的调用, 或者一次RPC/数据库访问.只要是一个具有完整时间周期的程序访问,都可以被认为是一个span

OpenTracing API:OpenTracing标准中有三个重要的相互关联的类型,分别是Tracer, Span 和 SpanContext。下面,我们分别描述每种类型的行为,一般来说,每个行为都会在各语言实现层面上,会演变成一个方法,而实际上由于方法重载,很可能演变成一系列相似的方法

Tracer:Tracer接口用来创建Span,以及处理如何处理Inject(serialize) 和 Extract (deserialize),用于跨进程边界传递

Span:每个Span包含以下的状态

An operation name,操作名称A start timestamp,起始时间A finish timestamp,结束时间Span Tag,一组键值对构成的Span标签集合。键值对中,键必须为string,值可以是字符串,布尔,或者数字类型Span Log,一组span的日志集合。 每次log操作包含一个键值对,以及一个时间戳。 键值对中,键必须为string,值可以是任意类型。 但是需要注意,不是所有的支持OpenTracing的Tracer,都需要支持所有的值类型SpanContext,Span上下文对象References(Span间关系),相关的零个或者多个Span(Span间通过SpanContext建立这种关系)

SpanContext:每一个SpanContext包含以下状态

任何一个OpenTracing的实现,都需要将当前调用链的状态(例如:trace和span的id),依赖一个独特的Span去跨进程边界传输Baggage Items,Trace的随行数据,是一个键值对集合,它存在于trace中,也需要跨进程边界传输

Span间关系:一个Span可以与一个或者多个SpanContexts存在因果关系。OpenTracing目前定义了两种关系:ChildOf(父子) 和 FollowsFrom(跟随)

二、go使用jaeger

jaeger go官方地址:/jaegertracing/jaeger-client-go

1 - 发送单span

package mainimport ("time""/opentracing/opentracing-go""/uber/jaeger-client-go"jaegercfg "/uber/jaeger-client-go/config")func main() {cfg := jaegercfg.Configuration{Sampler: &jaegercfg.SamplerConfig{Type: jaeger.SamplerTypeConst,Param: 1,},Reporter: &jaegercfg.ReporterConfig{LogSpans: true,LocalAgentHostPort: "192.168.78.131:6831",},ServiceName: "mxshop",}tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))if err != nil {panic(err)}opentracing.SetGlobalTracer(tracer)defer closer.Close()span := opentracing.StartSpan("go-grpc-web")time.Sleep(time.Second)defer span.Finish()}

执行完成在jaeger查看

2 - 发送嵌套span

直接新建2个span

opentracing.SetGlobalTracer(tracer)defer closer.Close()spanA := opentracing.StartSpan("funcA")time.Sleep(time.Millisecond * 500)defer spanA.Finish()spanB := opentracing.StartSpan("funcB")time.Sleep(time.Millisecond * 1000)defer spanB.Finish()

删除defer

opentracing.SetGlobalTracer(tracer)defer closer.Close()spanA := opentracing.StartSpan("funcA")time.Sleep(time.Millisecond * 500)spanA.Finish()spanB := opentracing.StartSpan("funcB")time.Sleep(time.Millisecond * 1000)spanB.Finish()

同tracer的span

opentracing.SetGlobalTracer(tracer)defer closer.Close()parentSpan := tracer.StartSpan("main")spanA := opentracing.StartSpan("funcAAA", opentracing.ChildOf(parentSpan.Context()))time.Sleep(time.Millisecond * 500)spanA.Finish()spanB := opentracing.StartSpan("funcBBB", opentracing.ChildOf(parentSpan.Context()))time.Sleep(time.Millisecond * 1000)spanB.Finish()parentSpan.Finish()

在两个span中间添加业务逻辑

parentSpan := tracer.StartSpan("main")spanA := opentracing.StartSpan("funcAAA", opentracing.ChildOf(parentSpan.Context()))time.Sleep(time.Millisecond * 500)spanA.Finish()time.Sleep(time.Millisecond * 1000)spanB := opentracing.StartSpan("funcBBB", opentracing.ChildOf(parentSpan.Context()))time.Sleep(time.Millisecond * 1000)spanB.Finish()parentSpan.Finish()

多级嵌套:main -> spanA -> spanB

parentSpan := tracer.StartSpan("main")spanA := opentracing.StartSpan("funcAAA", opentracing.ChildOf(parentSpan.Context()))time.Sleep(time.Millisecond * 500)spanA.Finish()time.Sleep(time.Millisecond * 1000)spanB := opentracing.StartSpan("funcBBB", opentracing.ChildOf(spanA.Context()))time.Sleep(time.Millisecond * 1000)spanB.Finish()parentSpan.Finish()

3 - grpc发送span

第三方grpc-opentracing:/grpc-ecosystem/grpc-opentracing;直接clone下来使用server/server.go

package mainimport ("context""net""/grpc""my_test/proto")type Server struct{}func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,error) {return &proto.HelloReply{Message: "hello " + request.Name,}, nil}func main() {g := grpc.NewServer()proto.RegisterGreeterServer(g, &Server{})lis, err := net.Listen("tcp", "0.0.0.0:50051")if err != nil {panic("failed to listen:" + err.Error())}err = g.Serve(lis)if err != nil {panic("failed to start grpc:" + err.Error())}}

client/client.go

package mainimport ("context""fmt""/grpc/credentials/insecure""my_test/otgrpc""/opentracing/opentracing-go""/uber/jaeger-client-go"jaegercfg "/uber/jaeger-client-go/config""/grpc""my_test/proto")func main() {cfg := jaegercfg.Configuration{Sampler: &jaegercfg.SamplerConfig{Type: jaeger.SamplerTypeConst,Param: 1,},Reporter: &jaegercfg.ReporterConfig{LogSpans: true,LocalAgentHostPort: "192.168.78.131:6831",},ServiceName: "mxshop",}tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))if err != nil {panic(err)}opentracing.SetGlobalTracer(tracer)defer closer.Close()conn, err := grpc.Dial("127.0.0.1:50051",grpc.WithTransportCredentials(insecure.NewCredentials()),grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer())))if err != nil {panic(err)}defer conn.Close()c := proto.NewGreeterClient(conn)r, err := c.SayHello(context.Background(), &proto.HelloRequest{Name: "bobby"})if err != nil {panic(err)}fmt.Println(r.Message)}

三、goods_web集成jaeger

1 - 添加nacos配置

goods_web/config/config.go

type JaegerConfig struct {Host string `mapstructure:"host" json:"host"`Port int `mapstructure:"port" json:"port"`Name string `mapstructure:"name" json:"name"`}type ServerConfig struct {Name string `mapstructure:"name" json:"name"`Host string `mapstructure:"host" json:"host"`Tags []string `mapstructure:"tags" json:"tags"`Port int `mapstructure:"port" json:"port"`GoodsSrvInfo GoodsSrvConfig `mapstructure:"goods_srv" json:"goods_srv"`JWTInfoJWTConfig`mapstructure:"jwt" json:"jwt"`ConsulInfo ConsulConfig `mapstructure:"consul" json:"consul"`JaegerInfo JaegerConfig `mapstructure:"jaeger" json:"jaeger"`}

nacos配置

{"host": "192.168.124.9","name": "goods_web","port": 8082,"tags": ["mxshop","imooc","bobby","goods","web"],"goods_srv": {"name": "goods_srv"},"jwt": {"key": "VYLDYq3&hGWjWqF$K1ih"},"consul": {"host": "192.168.124.51","port": 8500},"jaeger": {"host": "192.168.124.51","port": 6381,"name": "ja_web_api"}}

2 - 添加中间件

goods_web/middlewares/tracing.go

package middlewaresimport ("fmt""/opentracing/opentracing-go""/uber/jaeger-client-go""web_api/goods_web/global""/gin-gonic/gin"jaegercfg "/uber/jaeger-client-go/config")func Trace() gin.HandlerFunc {return func(ctx *gin.Context) {cfg := jaegercfg.Configuration{Sampler: &jaegercfg.SamplerConfig{Type: jaeger.SamplerTypeConst,Param: 1,},Reporter: &jaegercfg.ReporterConfig{LogSpans: true,LocalAgentHostPort: fmt.Sprintf("%s:%d", global.ServerConfig.JaegerInfo.Host, global.ServerConfig.JaegerInfo.Port),},ServiceName: global.ServerConfig.JaegerInfo.Name,}tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))if err != nil {panic(err)}opentracing.SetGlobalTracer(tracer)defer closer.Close()startSpan := tracer.StartSpan(ctx.Request.URL.Path)defer startSpan.Finish()ctx.Set("tracer", tracer)ctx.Set("parentSpan", startSpan)ctx.Next()}}

goods_web/router/router_goods.go:router调用中间件

package routerimport ("/gin-gonic/gin""web_api/goods_web/api/goods""web_api/goods_web/middlewares")func InitGoodsRouter(Router *gin.RouterGroup) {GoodsRouter := Router.Group("goods").Use(middlewares.Trace()){GoodsRouter.GET("", goods.List) //商品列表//GoodsRouter.POST("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.New) //该接口需要管理员权限GoodsRouter.POST("", goods.New) // 我们测试先将这2个接口权限关闭掉GoodsRouter.GET("/:id", goods.Detail) //获取商品的详情//GoodsRouter.DELETE("/:id",middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Delete) //删除商品GoodsRouter.DELETE("/:id", goods.Delete)// 我们测试先将这2个接口权限关闭掉GoodsRouter.GET("/:id/stocks", goods.Stocks) //获取商品的库存//GoodsRouter.PUT("/:id",middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Update)GoodsRouter.PUT("/:id", goods.Update)//GoodsRouter.PATCH("/:id",middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.UpdateStatus)GoodsRouter.PATCH("/:id", goods.UpdateStatus)}}

3 - 初始化连接注入Tracer

goods_web/initialize/init_srv_conn.go

package initializeimport ("fmt"_ "/mbobakov/grpc-consul-resolver" // It's important"/opentracing/opentracing-go""/zap""/grpc""/grpc/credentials/insecure""web_api/goods_web/global""web_api/goods_web/proto""web_api/goods_web/utils/otgrpc")func InitSrvConn() {consulInfo := global.ServerConfig.ConsulInfouserConn, err := grpc.Dial(fmt.Sprintf("consul://%s:%d/%s?wait=14s", consulInfo.Host, consulInfo.Port, global.ServerConfig.GoodsSrvInfo.Name),grpc.WithTransportCredentials(insecure.NewCredentials()),grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer())),)if err != nil {zap.S().Fatal("[InitSrvConn] 连接 【商品服务失败】")}global.GoodsSrvClient = proto.NewGoodsClient(userConn)}

4 - api中调用grpc带上ctx

goods_web/api/goods/api_goods.go

func List(ctx *gin.Context) {//省略。。。request.Brand = int32(brandIdInt)请求商品的service服务r, err := global.GoodsSrvClient.GoodsList(context.WithValue(context.Background(), "ginContext", ctx), request)if err != nil {zap.S().Errorw("[List] 查询 【商品列表】失败")api.HandleGrpcErrorToHttp(err, ctx)return}//省略。。。}

5 - 优化otgrpc的源码

goods_web/utils/otgrpc/client.go:源码优化 -> 从ginContext中拿到tracer和parentSpan

func OpenTracingClientInterceptor(tracer opentracing.Tracer, optFuncs ...Option) grpc.UnaryClientInterceptor {otgrpcOpts := newOptions()otgrpcOpts.apply(optFuncs...)return func(ctx context.Context,method string,req, resp interface{},cc *grpc.ClientConn,invoker grpc.UnaryInvoker,opts ...grpc.CallOption,) error {var err errorvar parentCtx opentracing.SpanContextif parent := opentracing.SpanFromContext(ctx); parent != nil {parentCtx = parent.Context()}ginContext := ctx.Value("ginContext")switch ginContext.(type) {case *gin.Context:if itracer, ok := ginContext.(*gin.Context).Get("tracer"); ok {tracer = itracer.(opentracing.Tracer)}if parentSpan, ok := ginContext.(*gin.Context).Get("parentSpan"); ok {parentCtx = parentSpan.(*jaegerClient.Span).Context()}}//省略。。。

四、order_web集成jaeger

1 - 复制tracing和otgrpc到order_web中

2 - router修改

order_web/router/router_order.go

package routerimport ("/gin-gonic/gin""web_api/order_web/api/order""web_api/order_web/api/pay""web_api/order_web/middlewares")func InitOrderRouter(Router *gin.RouterGroup) {OrderRouter := Router.Group("orders").Use(middlewares.SetUserId()).Use(middlewares.Trace()){OrderRouter.GET("", order.List) // 订单列表//BannerRouter.GET("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), order.List) // 订单列表OrderRouter.POST("", order.New) // 新建订单OrderRouter.GET("/:id/", order.Detail) // 订单详情}PayRouter := Router.Group("pay"){PayRouter.POST("alipay/notify", pay.Notify)}}

3 - grpc调用接口修改

order_web/api/order/api_order.go

func New(ctx *gin.Context) {orderForm := forms.CreateOrderForm{}if err := ctx.ShouldBindJSON(&orderForm); err != nil {api.HandleValidatorError(ctx, err)}userId, _ := ctx.Get("userId")rsp, err := global.OrderSrvClient.CreateOrder(context.WithValue(context.Background(), "ginContext", ctx), &proto.OrderRequest{UserId: int32(userId.(uint)),Name: orderForm.Name,Mobile: orderForm.Mobile,Address: orderForm.Address,Post: orderForm.Post,})//省略

4 - 初始化连接注入Tracer

order_web/initialize/init_srv_conn.go

package initializeimport ("fmt"_ "/mbobakov/grpc-consul-resolver" // It's important"/opentracing/opentracing-go""/zap""/grpc""/grpc/credentials/insecure""web_api/order_web/global""web_api/order_web/proto""web_api/order_web/utils/otgrpc")func InitSrvConn() {consulInfo := global.ServerConfig.ConsulInfogoodsConn, err := grpc.Dial(fmt.Sprintf("consul://%s:%d/%s?wait=14s", consulInfo.Host, consulInfo.Port, global.ServerConfig.GoodsSrvInfo.Name),grpc.WithTransportCredentials(insecure.NewCredentials()),grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer())),)if err != nil {zap.S().Fatal("[InitSrvConn] 连接 【商品服务失败】")}global.GoodsSrvClient = proto.NewGoodsClient(goodsConn)orderConn, err := grpc.Dial(fmt.Sprintf("consul://%s:%d/%s?wait=14s", consulInfo.Host, consulInfo.Port, global.ServerConfig.OrderSrvInfo.Name),grpc.WithTransportCredentials(insecure.NewCredentials()),grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer())),)if err != nil {zap.S().Fatal("[InitSrvConn] 连接 【订单服务失败】")}global.OrderSrvClient = proto.NewOrderClient(orderConn)inventoryConn, err := grpc.Dial(fmt.Sprintf("consul://%s:%d/%s?wait=14s", consulInfo.Host, consulInfo.Port, global.ServerConfig.InventorySrvInfo.Name),grpc.WithTransportCredentials(insecure.NewCredentials()),grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer())),)if err != nil {zap.S().Fatal("[InitSrvConn] 连接 【库存服务失败】")}global.InventorySrvClient = proto.NewInventoryClient(inventoryConn)}

5 - 添加nacos配置

order_web/config/config.go

type JaegerConfig struct {Host string `mapstructure:"host" json:"host"`Port int `mapstructure:"port" json:"port"`Name string `mapstructure:"name" json:"name"`}type ServerConfig struct {Name string `mapstructure:"name" json:"name"`Host string `mapstructure:"host" json:"host"`Tags []string`mapstructure:"tags" json:"tags"`Port int`mapstructure:"port" json:"port"`GoodsSrvInfoSrvConfig `mapstructure:"goods_srv" json:"goods_srv"`OrderSrvInfoSrvConfig `mapstructure:"order_srv" json:"order_srv"`InventorySrvInfo SrvConfig `mapstructure:"inventory_srv" json:"inventory_srv"`JWTInfoJWTConfig `mapstructure:"jwt" json:"jwt"`ConsulInfo ConsulConfig `mapstructure:"consul" json:"consul"`AliPayInfo AlipayConfig `mapstructure:"alipay" json:"alipay"`JaegerInfo JaegerConfig `mapstructure:"consul" json:"jaeger"`}

nacos配置

{"host": "192.168.124.9","name": "order_web","port": 8083,"tags": ["mxshop","imooc","bobby","order","web"],"goods_srv": {"name": "goods_srv"},"order_srv": {"name": "order_srv"},"inventory_srv": {"name": "inventory_srv"},"jwt": {"key": "VYLDYq3&hGWjWqF$K1ih"},"consul": {"host": "192.168.124.51","port": 8500},"jaeger": {"host": "192.168.124.51","port": 6381,"name": "ja_order_api"},"alipay":{"app_id":"000121645456","private_key":"MIIEowIBAAKCA","ali_public_key":"MIIBIjANBgkq","notify_url":"http://xxx","return_url":"http://127.0.0.1:8089"}}

五、同步srv层和web层的jaeger

1 - otgrpc原理分析

order_web/utils/otgrpc/client.go

2 - 初始化jaeger

order_srv/main.go:主要修改grpc.NewServer

package mainimport ("flag""fmt""/apache/rocketmq-client-go/v2""/apache/rocketmq-client-go/v2/consumer""/opentracing/opentracing-go""nd/order_srv/handler""nd/order_srv/utils/otgrpc""net""os""os/signal""syscall""/satori/go.uuid""/zap""/grpc""/grpc/health""/grpc/health/grpc_health_v1""/uber/jaeger-client-go"jaegercfg "/uber/jaeger-client-go/config""nd/order_srv/global""nd/order_srv/initialize""nd/order_srv/proto""nd/order_srv/utils""nd/order_srv/utils/register/consul")func main() {IP := flag.String("ip", "0.0.0.0", "ip地址")Port := flag.Int("port", 50060, "端口号") // 这个修改为0,如果我们从命令行带参数启动的话就不会为0//初始化initialize.InitLogger()initialize.InitConfig()initialize.InitDB()initialize.InitSrvConn()zap.S().Info(global.ServerConfig)flag.Parse()zap.S().Info("ip: ", *IP)if *Port == 0 {*Port, _ = utils.GetFreePort()}zap.S().Info("port: ", *Port)//初始化jaegercfg := jaegercfg.Configuration{Sampler: &jaegercfg.SamplerConfig{Type: jaeger.SamplerTypeConst,Param: 1,},Reporter: &jaegercfg.ReporterConfig{LogSpans: true,LocalAgentHostPort: "192.168.124.51:6831",},ServiceName: "mxshop",}tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))if err != nil {panic(err)}opentracing.SetGlobalTracer(tracer)server := grpc.NewServer(grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer)))proto.RegisterOrderServer(server, &handler.OrderServer{})lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", *IP, *Port))if err != nil {panic("failed to listen:" + err.Error())}//注册服务健康检查grpc_health_v1.RegisterHealthServer(server, health.NewServer())//服务注册register_client := consul.NewRegistryClient(global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port)serviceId := fmt.Sprintf("%s", uuid.NewV4())err = register_client.Register(global.ServerConfig.Host, *Port, global.ServerConfig.Name, global.ServerConfig.Tags, serviceId)if err != nil {zap.S().Panic("服务注册失败:", err.Error())}zap.S().Debugf("启动服务器, 端口: %d", *Port)go func() {err = server.Serve(lis)if err != nil {panic("failed to start grpc:" + err.Error())}}()//监听订单超时topicc, _ := rocketmq.NewPushConsumer(consumer.WithNameServer([]string{"192.168.124.51:9876"}),consumer.WithGroupName("mxshop-order"),)if err := c.Subscribe("order_timeout", consumer.MessageSelector{}, handler.OrderTimeout); err != nil {fmt.Println("读取消息失败")}_ = c.Start()//不能让主goroutine退出//接收终止信号quit := make(chan os.Signal)signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)<-quit_ = c.Shutdown()_ = closer.Close()if err = register_client.DeRegister(serviceId); err != nil {zap.S().Info("注销失败:", err.Error())} else {zap.S().Info("注销成功:")}}

3 - 增加追踪的span

order_srv/handler/handle_order.go:增加追踪的spanCreateOrder中初始化context

func (*OrderServer) CreateOrder(ctx context.Context, req *proto.OrderRequest) (*proto.OrderInfoResponse, error) {/*新建订单1. 从购物车中获取到选中的商品2. 商品的价格自己查询 - 访问商品服务 (跨微服务)3. 库存的扣减 - 访问库存服务 (跨微服务)4. 订单的基本信息表 - 订单的商品信息表5. 从购物车中删除已购买的记录*/orderListener := OrderListener{Ctx: ctx}p, err := rocketmq.NewTransactionProducer(&orderListener,producer.WithNameServer([]string{"192.168.124.51:9876"}),)//省略。。。

在需要追踪的业务地方增加span进入后从context先获取父span:parentSpan := opentracing.SpanFromContext(o.Ctx)追踪开始:shopCartSpan := opentracing.GlobalTracer().StartSpan("select_shopcart", opentracing.ChildOf(parentSpan.Context()))追踪结束:shopCartSpan.Finish()

func (o *OrderListener) ExecuteLocalTransaction(msg *primitive.Message) primitive.LocalTransactionState {parentSpan := opentracing.SpanFromContext(o.Ctx)var orderInfo model.OrderInfo_ = json.Unmarshal(msg.Body, &orderInfo)var goodsIds []int32var shopCarts []model.ShoppingCartgoodsNumsMap := make(map[int32]int32)shopCartSpan := opentracing.GlobalTracer().StartSpan("select_shopcart", opentracing.ChildOf(parentSpan.Context()))if result := global.DB.Where(&model.ShoppingCart{User: orderInfo.User, Checked: true}).Find(&shopCarts); result.RowsAffected == 0 {o.Code = codes.InvalidArgumento.Detail = "没有选中结算的商品"return primitive.RollbackMessageState}shopCartSpan.Finish()

4 - 过滤掉健康检查的jaeger

order_srv/utils/otgrpc/server.go

func OpenTracingServerInterceptor(tracer opentracing.Tracer, optFuncs ...Option) grpc.UnaryServerInterceptor {otgrpcOpts := newOptions()otgrpcOpts.apply(optFuncs...)return func(ctx context.Context,req interface{},info *grpc.UnaryServerInfo,handler grpc.UnaryHandler,) (resp interface{}, err error) {if info.FullMethod != "/grpc.health.v1.Health/Check" {spanContext, err := extractSpanContext(ctx, tracer)//省略

六、完整源码

完整源码下载:mxshop_srvsV13.0rar源码说明:(nacos的ip配置自行修改,全局变量DEV_CONFIG设置:1=zsz,2=comp,3=home) goods_srv/model/sql/mxshop_goods.sql:包含了建表语句other_import/api.json:YApi的导入文件other_import/nacos_config_export_user.zip:nacos的user配置集导入文件other_import/nacos_config_export_goods.zip:nacos的goods配置集导入文件other_import/nacos_config_export_inventory.zip:nacos的inventory的配置导入文件other_import/nacos_config_export_orders.zip:nacos的orders的配置导入文件other_import/nacos_config_export_userop.zip:nacos的userop的配置导入文件other_import/install.zip:rocketmq的docker-compose安装文件

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。