当前位置: 首页 > 工具软件 > RK GRPC > 使用案例 >

gRPC自定义函数调用Metrics

和和煦
2023-12-01

GRPC: 如何添加 API Prometheus 监控拦截器/中间件?_点目科技的博客-CSDN博客_grpc 普罗米修斯

 GRPC: 如何在 gRPC 服务中加入 Prometheus 监控?_点目科技的博客-CSDN博客_grpc 监控

RK-BOOT gRPC 框架 | rk-boot

gRPC实现方式调研报告

1.包装成gRPC拦截器

主要针对目前公司内部模块grpc通信状态进行监控,便于进行问题的排查以及模块以及接口运行状态的统计。基于此,对如果以最小程度侵入各个模块代码的方式进行调研。

参考库:rk_boot

func UnaryServerInterceptor(opts ...rkmidprom.Option) grpc.UnaryServerInterceptor {
   set := rkmidprom.NewOptionSet(opts...)
​
   return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
      ctx = rkgrpcmid.WrapContextForServer(ctx)
      rkgrpcmid.AddToServerContextPayload(ctx, rkmid.EntryNameKey, set.GetEntryName())
​
      beforeCtx := set.BeforeCtx(nil)
​
      grpcService, grpcMethod := rkgrpcmid.GetGrpcInfo(info.FullMethod)
      gwMethod, gwPath, _, _ := rkgrpcmid.GetGwInfo(rkgrpcctx.GetIncomingHeaders(ctx))
      beforeCtx.Input.GrpcService = grpcService
      beforeCtx.Input.GrpcMethod = grpcMethod
      beforeCtx.Input.GrpcType = "UnaryServer"
      beforeCtx.Input.RestPath = gwPath
      beforeCtx.Input.RestMethod = gwMethod
​
      set.Before(beforeCtx)
​
      resp, err := handler(ctx, req)
​
      afterCtx := set.AfterCtx(status.Code(err).String())
      set.After(beforeCtx, afterCtx)
​
      return resp, err
   }
}

实现原理

1.利用grpc拦截器(类似http框架的中间件)

2.在处理请求前后对指标需要的参数进行初始化,根据指标数据类项目能够进行修改后发送到对应的url

3.由prometheus配置对应的url进行数据的拉取

代码示例

 

set := rkmidprom.NewOptionSet(opts...)

func NewOptionSet(opts ...Option) OptionSetInterface {
   set := &optionSet{
      entryName:    "fake-entry",
      entryType:    "",
      registerer:   prometheus.DefaultRegisterer,
      pathToIgnore: []string{},
      labelerType:  LabelerTypeHttp,
   }
​
   for i := range opts {
      opts[i](set)
   }
​
   if set.mock != nil {
      return set.mock
   }
​
   set.metricsSet = NewMetricsSet(
      "rk",
      "prom",
      set.registerer)
​
   if _, ok := optionsMap[set.entryName]; !ok {
      optionsMap[set.entryName] = set
   }
​
   var keys []string
​
   switch set.labelerType {
   case LabelerTypeHttp:
      keys = labelKeysHttp
   case LabelerTypeGrpc:
      keys = labelKeysGrpc
   default:
      keys = labelKeysHttp
   }
​
   set.metricsSet.RegisterSummary(MetricsNameElapsedNano, SummaryObjectives, keys...)
   set.metricsSet.RegisterCounter(MetricsNameResCode, keys...)
​
   return set
}

注册两类指标

后续这个模块(例如xbroker.v2)的所有的grpc方法调用都会在这个指标上显示出来

set.After(beforeCtx, afterCtx)里面,里面进行指标的Inc以及其他的Observe操作

func (set *optionSet) After(before *BeforeCtx, after *AfterCtx) {
   if before == nil || after == nil {
      return
   }
​
   if set.ShouldIgnore(before.Input.RestPath) {
      return
   }
​
   var l labeler
​
   switch set.labelerType {
   case LabelerTypeGrpc:
      l = &labelerGrpc{
         entryName:   set.entryName,
         entryType:   set.entryType,
         domain:      rkmid.Domain.String,
         instance:    rkmid.LocalHostname.String,
         restPath:    before.Input.RestPath,
         restMethod:  before.Input.RestMethod,
         grpcType:    before.Input.GrpcType,
         grpcService: before.Input.GrpcService,
         grpcMethod:  before.Input.GrpcMethod,
         resCode:     after.Input.ResCode,
      }
   case LabelerTypeHttp:
      l = &labelerHttp{
         entryName: set.entryName,
         entryType: set.entryType,
         domain:    rkmid.Domain.String,
         instance:  rkmid.LocalHostname.String,
         method:    before.Input.RestMethod,
         path:      before.Input.RestPath,
         resCode:   after.Input.ResCode,
      }
   default:
      l = &labelerHttp{
         entryName: set.entryName,
         entryType: set.entryType,
         domain:    rkmid.Domain.String,
         instance:  rkmid.LocalHostname.String,
         method:    before.Input.RestMethod,
         path:      before.Input.RestPath,
         resCode:   after.Input.ResCode,
      }
   }
​
   elapsed := time.Now().Sub(before.Output.StartTime)
​
   if durationMetrics := set.getServerDurationMetrics(l); durationMetrics != nil {
      durationMetrics.Observe(float64(elapsed.Nanoseconds()))
   }
​
   if resCodeMetrics := set.getServerResCodeMetrics(l); resCodeMetrics != nil {
      resCodeMetrics.Inc()
   }
}

优缺点

优点:

1.可以利用grpc自带的拦截器机制无缝接入代码里面

2.可以对指标的参数进行灵活的设置

3.再方法之前之后都能进行指标的相关操作,以为着可以更细致得进行grpc调用得监控

缺点:

1.随着模块增加,指标数也会增加。如果是模块自己暴露指标,那么可以统一向同一个url发送。

2.有多少grpc服务建立,就绪加入拦截器几次。

 类似资料: