GRPC: 如何添加 API Prometheus 监控拦截器/中间件?_点目科技的博客-CSDN博客_grpc 普罗米修斯
GRPC: 如何在 gRPC 服务中加入 Prometheus 监控?_点目科技的博客-CSDN博客_grpc 监控
RK-BOOT gRPC 框架 | rk-boot
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服务建立,就绪加入拦截器几次。