中间件中的gRPC连接时间指标

huangapple go评论81阅读模式
英文:

grpc connection time metric in the middleware

问题

这是我之前的问题https://stackoverflow.com/questions/70240557/grpc-middlewareinterceptors-for-metric

我想使用中间件。这是我现在的代码。

func RequestTimeStream(mtr *metrics.Metrics) grpc.StreamServerInterceptor {
	return grpc.StreamServerInterceptor(func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo,
		handler grpc.StreamHandler) error {
		beginTime := time.Now()
		label, err := getLabel(info.FullMethod)
		if err != nil {
			return errors.Errorf("未知的方法名:%s", info.FullMethod)
		}
		defer mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())
		if err := handler(srv, stream); err != nil {
			return err
		}
		return nil
	})
}

创建grpc服务器

streamInterceptors := grpc_middleware.ChainStreamServer(
	middleware.RecoveryStream(logger, metrics.InternalGRPCPanicErrors),
	identifyMdw.IdentifyStream,
	middleware.AuthenticateStream(logger, metrics, authService),
	middleware.LimitStream(logger, metrics, limiters),
	middleware.RequestTimeStream(metrics),
)

opts := []grpc.ServerOption{grpc.UnaryInterceptor(unaryInterceptors), grpc.StreamInterceptor(streamInterceptors)}

grpcServer, err := ggrpc.NewServer(cfg.ServerConfig, opts...)

我的代码没有正常工作。度量值太小,只有约30,000纳秒。

英文:

This is my previous question https://stackoverflow.com/questions/70240557/grpc-middlewareinterceptors-for-metric

I want to use middleware. That's what I have now.

func RequestTimeStream(mtr *metrics.Metrics) grpc.StreamServerInterceptor {
	return grpc.StreamServerInterceptor(func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo,
		handler grpc.StreamHandler) error {
		beginTime := time.Now()
		label, err := getLabel(info.FullMethod)
		if err != nil {
			return errors.Errorf("Unknown method name: %s", info.FullMethod)
		}
		defer mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())
		if err := handler(srv, stream); err != nil {
			return err
		}
		return nil
	})
}

Creating grpc server

	streamInterceptors := grpc_middleware.ChainStreamServer(
		middleware.RecoveryStream(logger, metrics.InternalGRPCPanicErrors),
		identifyMdw.IdentifyStream,
		middleware.AuthenticateStream(logger, metrics, authService),
		middleware.LimitStream(logger, metrics, limiters),
		middleware.RequestTimeStream(metrics),
	)

	opts := []grpc.ServerOption{grpc.UnaryInterceptor(unaryInterceptors), grpc.StreamInterceptor(streamInterceptors)}

	grpcServer, err := ggrpc.NewServer(cfg.ServerConfig, opts...)

My code is not working properly. The metrics are too small ~30,000 nanoseconds.

答案1

得分: 1

假设我正确理解了你的问题,我认为问题出在以下代码中:

defer mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())

你似乎期望这段代码在函数退出时运行,并计算此时经过的时间。然而根据语言规范

>每次执行“defer”语句时,函数值和调用的参数都会像平常一样进行求值并保存,但实际的函数不会被调用。

因此,参数在defer语句执行时进行求值,而不是在包围函数退出时(延迟函数运行时)进行求值。可以通过一个简单的程序来证明这一点:

beginTime := time.Now()
defer fmt.Println("defer", time.Since(beginTime).Seconds())
time.Sleep(2 * time.Second)
fmt.Println("non-defer", time.Since(beginTime).Seconds())

这将输出类似以下内容:

non-defer 2
defer 0

有几种可能的解决方案;最简单的可能是使用一个闭包,例如:

defer func() { fmt.Println("defer", time.Since(beginTime).Seconds()) }()

或者在你的情况下:

defer func() { mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())}()
英文:

Assuming I'm understanding your issue correctly I believe the problem is with:

defer mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())

It appears that you expect this to be run at the time the function exits and calculate the time elapsed as at that time. However as per the language spec:

>Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.

So the parameters are evaluated when the defer statement executes NOT when the surrounding function exits (and the deferred function runs). This can be demonstrated with a simple program:

beginTime := time.Now()
defer fmt.Println("defer", time.Since(beginTime).Seconds())
time.Sleep(2 * time.Second)
fmt.Println("non-defer", time.Since(beginTime).Seconds())

This will output something like:

non-defer 2
defer 0

There are a few possible solutions; the simplest is probably to use a closure e.g.

defer func() { fmt.Println("defer", time.Since(beginTime).Seconds()) }()

or in your case:

defer func() { mtr.RequestTime.With(metrics.MakeLabels(label)).Observe(time.Since(beginTime).Seconds())}()

huangapple
  • 本文由 发表于 2021年12月22日 08:17:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/70442975.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定