Moby 仓库中的 go-grpc-prometheus:用 Prometheus 监控 gRPC 服务端与客户端拦截器全指南

Moby 仓库中的 go-grpc-prometheus:用 Prometheus 监控 gRPC 服务端与客户端拦截器全指南 Moby 仓库中的 go-grpc-prometheus用 Prometheus 监控 gRPC 服务端与客户端拦截器全指南【免费下载链接】mobyThe Moby Project - a collaborative project for the container ecosystem to assemble container-based systems项目地址: https://gitcode.com/GitHub_Trending/mo/moby导读本文围绕 Moby 仓库中随依赖一并携带的go-grpc-prometheus完整文档见 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/README.md展开系统讲解如何通过 gRPC Go 的拦截器Interceptor机制为服务端与客户端自动采集 Prometheus 指标。该库正是 Moby 仓库内 swarm 编排相关 gRPC 通信manager、node、raft、connection broker所引入的监控基础设施。读完本文你将掌握拦截器的接线方式、grpc_server/grpc_client两套指标体系的标签与计数语义、延迟直方图的启用方法以及一组可直接用于 SLA 告警与容量分析的 PromQL 查询模板。InterceptorsgRPC 监控的天然切入点gRPC Go 提供了拦截器机制——服务端在把请求交给应用业务逻辑之前、客户端在发起/接收 RPC 前后执行的一段中间件适合落地鉴权、日志与监控等横切关注点。服务端拦截器grpc.StreamInterceptor与grpc.UnaryInterceptor客户端拦截器grpc.WithStreamInterceptor与grpc.WithUnaryInterceptor若需要把多个拦截器串联使用官方文档建议参考go-grpc-middleware项目go-grpc-prometheus正是基于这一机制实现的监控方案同时提供服务端与客户端两类拦截器且服务端/客户端指标具有完全对应的“镜像”结构。快速接线服务端与客户端拦截器示例服务端Server-side在初始化 gRPC Server 时挂上拦截器等服务全部注册完成后再调用Register(myServer)预初始化指标使各方法对应的指标序列从一开始就存在Prometheus 查询不会出现“缺失指标”的空窗随后用promhttp.Handler()暴露/metricsimport github.com/grpc-ecosystem/go-grpc-prometheus ... // 初始化 gRPC server 的拦截器。 myServer : grpc.NewServer( grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor), grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor), ) // 注册 gRPC 服务实现。 myservice.RegisterMyServiceServer(s.server, myServiceImpl{}) // 在所有注册完成后确保全部 Prometheus 指标被初始化。 grpc_prometheus.Register(myServer) // 注册 Prometheus metrics handler。 http.Handle(/metrics, promhttp.Handler()) ...客户端Client-side客户端同样只需在grpc.Dial的拨号选项中声明两个拦截器import github.com/grpc-ecosystem/go-grpc-prometheus ... clientConn, err grpc.Dial( address, grpc.WithUnaryInterceptor(grpc_prometheus.UnaryClientInterceptor), grpc.WithStreamInterceptor(grpc_prometheus.StreamClientInterceptor), ) client pb_testproto.NewTestServiceClient(clientConn) resp, err : client.PingEmpty(s.ctx, myservice.Request{Msg: hello}) ...在 Moby 仓库中这些拦截器并非摆设——仓库内随依赖携带的 swarmkit 代码就真实使用了它们来监控 swarm 模式的 gRPC 通信。例如 vendor/github.com/moby/swarmkit/v2/manager/manager.go 在自定义拦截器内部把调用“让渡”给grpc_prometheus.UnaryServerInterceptor与grpc_prometheus.StreamServerInterceptor并在启动时对 manager 主 server 与本地 server 分别调用grpc_prometheus.Register(...)vendor/github.com/moby/swarmkit/v2/node/node.go、vendor/github.com/moby/swarmkit/v2/connectionbroker/broker.go 以及 raft 相关的 util.go 与 transport.go 则统一挂载客户端拦截器。这就是“一套监控库同时服务于 gRPC 服务端与客户端”在真实分布式系统swarm 控制面 raft 共识传输中的落地形态。指标体系Labels 与命名约定服务端指标统一以grpc_server作为 Prometheus subsystem 名称客户端指标以grpc_client开头两者概念互为镜像。所有指标都携带一套丰富的标签标签含义grpc_servicegRPC 服务名即 protobufpackage与service段名的组合。例如package mwitkow.testproto、service TestService时标签值为grpc_servicemwitkow.testproto.TestServicegrpc_method被调用方法的名称例如grpc_methodPinggrpc_typegRPC 请求类型直接影响延迟指标的分组口径unary单请求单响应、client_stream多请求单响应、server_stream单请求多响应、bidi_stream多请求多响应对于“已完成的 RPC”handled还会追加标签含义grpc_code人类可读的 gRPC 状态码常见如OK调用成功、IllegalArgument参数非法、Internal服务端内部错误不向客户端透露细节这些标签正是文档中所说的“富标签”设计为 PromQL 端自由聚合留足了空间。Counters一次 server_stream 调用的完整生命周期四个基础计数器与最新语义详见源码中的 server_reporter.go 与 client_reporter.go。这里以服务端视角跟踪一次典型的server_stream调用mwitkow.testproto.TestService的PingList成功返回 20 条消息1. 服务端刚收到调用立即自增grpc_server_started_total并启动计时若已启用直方图grpc_server_started_total{grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream} 1从源码看这正是newServerReporter构造器内部执行的serverStartedCounter.Inc()见 server_reporter.go。2. 用户逻辑被调用收到 1 条客户端请求消息grpc_server_msg_received_total{grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream} 13. 用户逻辑向客户端回送 20 条消息每发送一条grpc_server_msg_sent_total自增一次grpc_server_msg_sent_total{grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream} 204. 调用结束按其状态码与相关标签自增grpc_server_handled_totalgrpc_server_handled_total{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream} 1流式消息计数并非凭空实现服务端拦截器会用monitoredServerStream包装原始grpc.ServerStream在SendMsg/RecvMsg成功后再回调 reporter 计数见 server_metrics.go。而四个 CounterVec 的定义集中在 server_metrics.go 中——grpc_server_started_total标签为grpc_type/grpc_service/grpc_methodgrpc_server_handled_total额外携带grpc_codeRegister函数最终调用InitializeMetrics通过server.GetServiceInfo()遍历所有已注册方法以“仅引用不累加”的方式预创建零值标签序列见 server_metrics.go。Histograms延迟分布监控默认关闭直方图适合刻画 RPC 延迟分布但高基数标签会让 Prometheus 的存储与查询代价显著上升因此延迟类指标默认关闭。服务端启用方式grpc_prometheus.EnableHandlingTimeHistogram()对应底层实现在 server.go调用DefaultServerMetrics.EnableHandlingTimeHistogram(...)并同时向默认 registryprom.Register直方图指标。方法级接口同样可用例如ServerMetrics.EnableHandlingTimeHistogram()默认桶即prom.DefBuckets见 server_metrics.go。启用后每个完成的 RPC 会记录进直方图指标grpc_server_handling_seconds其下含三个子指标grpc_server_handling_seconds_count——按状态与方法统计的已完成 RPC 总数grpc_server_handling_seconds_sum——按状态与方法累计的处理时间可用于计算平均处理耗时grpc_server_handling_seconds_bucket——各延迟桶内的 RPC 计数供 Prometheus 估算 SLA示例输出grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le0.005} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le0.01} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le0.025} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le0.05} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le0.1} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le0.25} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le0.5} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le1} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le2.5} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le5} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,le10} 1 grpc_server_handling_seconds_bucket{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream,leInf} 1 grpc_server_handling_seconds_sum{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream} 0.0003866430000000001 grpc_server_handling_seconds_count{grpc_codeOK,grpc_methodPingList,grpc_servicemwitkow.testproto.TestService,grpc_typeserver_stream} 1补充说明源码证据Handled中会以time.Since(r.startTime).Seconds()作为采样值调用Observe且计时起点startTime仅在直方图启用时才记录见 server_reporter.go直方图同样携带grpc_type/grpc_service/grpc_method三个标签但不含grpc_code以减少基数需要自定义桶或常量标签时可使用WithHistogramBuckets、WithHistogramConstLabels等HistogramOption见 metric_options.goCounter 侧则提供WithConstLabels客户端直方图通过grpc_prometheus.EnableClientHandlingTimeHistogram()单独开启见 client.go。开箱即用的 PromQL 查询示例该库只负责产出“原始”指标聚合交给监控端完成下面六个查询模板可直接应用于告警规则与仪表盘。请求入站速率request inbound ratesum(rate(grpc_server_started_total{jobfoo}[1m])) by (grpc_service)对jobfooPrometheus 中区分监控目标的常用标签以 1 分钟窗口计算每个 gRPCgrpc_service的每秒请求速率。注意此处刻意省略grpc_method从而把同一服务的所有方法求和。unary 请求错误速率sum(rate(grpc_server_handled_total{jobfoo,grpc_typeunary,grpc_code!OK}[1m])) by (grpc_service)计算grpc_typeunary1:1 请求中未以OK结束即失败的每秒速率并按服务聚合。unary 请求错误百分比sum(rate(grpc_server_handled_total{jobfoo,grpc_typeunary,grpc_code!OK}[1m])) by (grpc_service) / sum(rate(grpc_server_started_total{jobfoo,grpc_typeunary}[1m])) by (grpc_service) * 100.0即前两个查询的组合按服务给出失败请求百分比可用于 SLA 告警例如“失败请求不超过 1%”。平均响应流大小sum(rate(grpc_server_msg_sent_total{jobfoo,grpc_typeserver_stream}[10m])) by (grpc_service) / sum(rate(grpc_server_started_total{jobfoo,grpc_typeserver_stream}[10m])) by (grpc_service)给出 10 分钟窗口内每个服务server_stream调用平均返回的消息条数便于追踪客户端是否开始发起返回大量消息的“宽查询”。分母刻意选择“已启动的 RPC 数”以把进行中的请求也纳入考量。unary 请求的 99% 分位延迟histogram_quantile(0.99, sum(rate(grpc_server_handling_seconds_bucket{jobfoo,grpc_typeunary}[5m])) by (grpc_service,le) )按服务估算 unary RPC 处理时间的 99% 分位。5m滚动窗口会平滑瞬时波动与 50%/90% 等分位组合可深入洞察系统响应性例如缓存对延迟的影响。慢查询占比250ms100.0 - ( sum(rate(grpc_server_handling_seconds_bucket{jobfoo,grpc_typeunary,le0.25}[5m])) by (grpc_service) / sum(rate(grpc_server_handling_seconds_count{jobfoo,grpc_typeunary}[5m])) by (grpc_service) ) * 100.0Prometheus 的le桶天然适合统计“快请求”占比因此这里用简单换算得到超过 0.25 秒的慢请求比例可按“慢于 250ms 的请求占比低于 1%”这类目标设置 SLA 告警。版本状态与使用背景grpc_server/grpc_client指标在 Moby 仓库随附的go.mod/go.sum中被声明为依赖github.com/grpc-ecosystem/go-grpc-prometheus并在仓库的vendor/github.com/grpc-ecosystem/go-grpc-prometheus/目录下随版本冻结同时由仓库内的 swarmkit 代码真实引用见上文列出的 manager/node/raft/broker 使用点。无论你是像 swarm 控制面一样用它监控分布式 gRPC 集群还是在自研微服务里复用同一套接线方式都可以直接以本文的服务端/客户端拦截器模板为起点并结合上述 PromQL 快速建立可告警的观测面。该库遵循 Apache 2.0 许可证发布许可证文本见 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/LICENSE。【免费下载链接】mobyThe Moby Project - a collaborative project for the container ecosystem to assemble container-based systems项目地址: https://gitcode.com/GitHub_Trending/mo/moby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考