ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

grpc-go OpenTelemetry 可观测性示例解析:为 gRPC 客户端与服务端接入 Prometheus 指标与 stdout 链路追踪

grpc-go OpenTelemetry 可观测性示例解析:为 gRPC 客户端与服务端接入 Prometheus 指标与 stdout 链路追踪 grpc-go OpenTelemetry 可观测性示例解析为 gRPC 客户端与服务端接入 Prometheus 指标与 stdout 链路追踪【免费下载链接】grpc-goThe Go language implementation of gRPC. HTTP/2 based RPC项目地址: https://gitcode.com/GitHub_Trending/gr/grpc-go本篇技术指南以 grpc-go 官方示例examples/features/opentelemetry为主线讲解如何在 gRPC 客户端与服务端上同时开启 OpenTelemetry 指标采集与链路追踪指标通过 Prometheus exporter 暴露在 HTTP 端点上追踪信息通过stdouttrace输出到标准输出流。读完本文你将掌握opentelemetry.DialOption/opentelemetry.ServerOption的完整配置姿势、实验性 gRPC 指标默认关闭、需显式开启的启用方法以及底层 stats handler 与拦截器如何把一次 RPC 变成可观测的指标和 Span。示例概览一次 RPC 的“全链路观测”示例由三部分构成一个持续发起 RPC 的客户端client/main.go、一个接收请求的 echo 服务端server/main.go以及二者各自挂载的 OpenTelemetry 出口。运行后客户端与服务端都创建一个 Prometheus exporter并用promhttp.Handler()挂到独立的 HTTP 端口上——默认服务端为:9464客户端为:9465客户端与服务端都使用stdouttraceexporter把结构化追踪数据直接打印到各自进程的标准输出客户端每秒钟调用一次UnaryEcho触发两端持续产出遥测数据用curl访问两个 Prometheus 端口即可拉取客户端、服务端各自记录的指标。整个示例不依赖任何外部 Collector全部遥测出口都内嵌在进程里非常适合作为 gRPC 可观测性接入的“最小可运行模板”。快速运行与验证在仓库的examples模块目录下依次执行示例代码位于 examples/features/opentelemetry先启动服务端go run server/main.go再另开一个终端启动客户端go run client/main.go客户端启动后即进入死循环每秒打印一次 echo 响应{this is examples/opentelemetry (from localhost:50051)}随后在第三个终端用 curl 拉取指标curl localhost:9464/metrics curl localhost:9465/metrics9464返回服务端指标9465返回客户端指标。与此同时客户端与服务端的终端里会不断滚动输出 Pretty Print 格式的 Span JSON——每次 RPC 都会产生一条记录执行流与耗时的追踪信息。命令行参数两个程序都通过flag暴露了可覆盖的默认值参数服务端默认值客户端默认值含义addrlocalhost:50051localhost:50051服务端监听地址 / 客户端连接地址prometheus_endpoint:9464:9465Prometheus exporter 的 HTTP 监听端点例如把服务端指标端口改为:9090go run server/main.go -prometheus_endpoint:9090。该定义可见于 server/main.go 与 client/main.go。客户端接入解析DialOption 与实验性指标客户端的关键在于构造grpc.DialOption并把它传给grpc.NewClientclient/main.godo : opentelemetry.DialOption(opentelemetry.Options{ MetricsOptions: opentelemetry.MetricsOptions{ MeterProvider: meterProvider, // 这些是示例性的实验性 gRPC 指标默认关闭 // 必须显式开启才会被记录。 Metrics: opentelemetry.DefaultMetrics().Add( grpc.subchannel.connection_attempts_succeeded, grpc.subchannel.connection_attempts_failed, ), }, TraceOptions: oteltracing.TraceOptions{TracerProvider: traceProvider, TextMapPropagator: textMapPropagator}, }) cc, err : grpc.NewClient(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()), do)这段代码里最值得注意的点是Metrics字段实验性 gRPC 指标默认关闭必须显式列出才会被采集。示例在opentelemetry.DefaultMetrics()的默认集合之上通过.Add(...)追加了两个子通道subchannel级连接指标grpc.subchannel.connection_attempts_succeeded子通道连接尝试成功次数grpc.subchannel.connection_attempts_failed子通道连接尝试失败次数。DefaultMetrics()的实现在 stats/opentelemetry/opentelemetry.go它把该模块自带的按调用per-call指标集合与estats.DefaultMetrics实验性指标注册表中的默认集合合并。而registerMetrics会遍历metrics.Metrics()中的每个指标名通过描述符的类型计数、直方图、gauge、异步 gauge 等创建对应的 OTel instrumentopentelemetry.go。若某个指标不在集合内对应 instrument 会退化为noop实现确保“未启用的指标零开销”。服务端接入解析ServerOption服务端使用opentelemetry.ServerOption把返回的选项传给grpc.NewServerserver/main.goso : opentelemetry.ServerOption(opentelemetry.Options{ MetricsOptions: opentelemetry.MetricsOptions{ MeterProvider: meterProvider, }, TraceOptions: oteltracing.TraceOptions{TracerProvider: traceProvider, TextMapPropagator: textMapPropagator}, }) s : grpc.NewServer(so) pb.RegisterEchoServer(s, echoServer{addr: *addr})服务端示例没有显式设置Metrics字段因此回落到默认指标集——即grpc.server.call.started、grpc.server.call.duration、grpc.server.call.sent_total_compressed_message_size、grpc.server.call.rcvd_total_compressed_message_size等服务端调用级指标。服务端实现类型serverMetrics与这些指标一一对应opentelemetry.go。双端公共配置MeterProvider、TracerProvider 与传播器客户端与服务端在构造 Options 之前有一段几乎相同的 OpenTelemetry 初始化代码构成了接入 gRPC 观测的三件套1. 指标侧MeterProvider Prometheus exporterexporter, err : prometheus.New() // Prometheus exporter meterProvider : otelmetric.NewMeterProvider(otelmetric.WithReader(exporter))prometheus.New()创建 Prometheus 抓取式 exporterNewMeterProvider把它注册为 reader之后 gRPC 埋点产生的所有指标都会经由它暴露。2. 追踪侧TracerProvider stdouttrace exportertraceExporter, err : otelstdouttrace.New(otelstdouttrace.WithPrettyPrint()) traceProvider : sdktrace.NewTracerProvider( sdktrace.WithBatcher(traceExporter), sdktrace.WithResource(otelresource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceName(grpc-server), // 客户端为 grpc-client )), )WithPrettyPrint()让 Span 以缩进 JSON 打印便于人读WithBatcher异步批量导出semconv.ServiceName则给 Span 打上服务名资源属性方便在追踪系统中区分grpc-server与grpc-client。3. 传播器W3C Trace ContexttextMapPropagator : otelpropagation.TraceContext{}客户端用它把 Span 上下文注入出站 metadata服务端用它从入站 metadata 中还原父 Span从而在跨进程场景下串联起“客户端调用链 → 服务端处理链”的完整 Trace。注意MetricsOptions.MeterProvider与TraceOptions.TracerProvider/TextMapPropagator均为可选。从源码看isMetricsEnabled/isTracingEnabled分别以“MeterProvider 是否非空”和“TracerProvider 是否非空”为开关opentelemetry.go不设置 MeterProvider 则完全不记录指标不设置 TracerProvider 则完全不记录追踪若只设置二者之一init()中的检查还会输出告警日志“Tracing will not be recorded because traceOptions are not set properly”opentelemetry.go。底层原理拦截器 stats handler 的双通道埋点DialOption/ServerOption并不是简单的开关而是把多套 gRPC 钩子组合进连接或服务器opentelemetry.go指标开启时注册一元/流式拦截器WithChainUnaryInterceptor/WithChainStreamInterceptor用于 RPC 生命周期维度同时注册stats handler用于消息字节数、压缩前后大小等传输维度追踪开启时同样注册拦截器客户端侧与 stats handler两端最终通过internal.JoinDialOptions/internal.JoinServerOptions把所有选项合并为一个DialOption/ServerOption返回。追踪侧的 stats handler 会把 RPC 生命周期中的统计事件翻译成 Span 上的事件与属性stats/opentelemetry/trace.goDelayedPickComplete→ 添加事件Delayed LB pick complete记录负载均衡延迟InPayload/OutPayload→ 添加Inbound message/Outbound message事件携带sequence-number、message-size压缩场景下还附带message-size-compressedEnd→ 根据rs.Error把 Span 状态置为Error携带状态消息或Ok随后span.End()触发导出。也就是说一次UnaryEcho调用产生的追踪数据不仅包含两端各自 Span 的耗时还包含收发消息的序号与字节数、负载均衡选路等细节这正是示例 README 所述“captures the execution flow and timing of operations”的源码级来源。指标端口暴露方式两个程序都以协程方式启动net/http服务把 Prometheus 采集端点与 gRPC 监听端口完全分离server/main.go、client/main.gogo http.ListenAndServe(*prometheusEndpoint, promhttp.Handler())服务端gRPC 监听:50051指标 HTTP 监听:9464客户端指标 HTTP 监听:9465客户端自身没有 gRPC 监听端口。这也是生产环境的常见形态把 Prometheus 抓取端点独立成一个 HTTP 端口与 RPC 流量隔离。依赖与运行前提示例属于仓库的examples独立 Go module其依赖声明在 examples/go.mod 中核心包括go.opentelemetry.io/otelv1.45.0OpenTelemetry APIgo.opentelemetry.io/otel/sdk、sdk/metricv1.45.0SDK 与指标 SDKgo.opentelemetry.io/otel/exporters/prometheusv0.67.0Prometheus exportergo.opentelemetry.io/otel/exporters/stdout/stdouttracev1.45.0stdout 追踪导出器github.com/prometheus/client_golangv1.24.1promhttpgoogle.golang.org/grpcv1.83.0。运行前需保证 Go 版本满足 module 声明的go 1.25.0并在examples目录下完成依赖拉取。示例中的 echo 服务由 echo.proto 定义本文只使用其中的UnaryEcho一元方法该服务还包含三种流式方法可作为后续自行扩展观测流式调用行为的起点。实验性指标的取舍与后续扩展示例特意展示了“实验性 gRPC 指标默认关闭”的语义这类指标由 gRPC 内部组件如子通道在运行时记录属于实验性 APIgoogle.golang.org/grpc/experimental/stats的一部分必须像示例那样显式枚举进Metrics集合才会生效。对照clientMetrics与serverMetrics结构体opentelemetry.go可以看到官方默认提供的调用级指标包括客户端grpc.client.attempt.started、grpc.client.attempt.duration、grpc.client.attempt.sent_total_compressed_message_size、grpc.client.attempt.rcvd_total_compressed_message_size、grpc.client.call.duration服务端grpc.server.call.started、grpc.server.call.sent_total_compressed_message_size、grpc.server.call.rcvd_total_compressed_message_size、grpc.server.call.duration。此外MetricsOptions还提供两个生产级调优字段opentelemetry.goMethodAttributeFilter func(string) bool服务端专用决定是否把 RPC 方法名作为标签记录不匹配的方法统一归入other用于控制标签基数、避免内存与性能问题OptionalLabels []string按需开启某些支持可选标签的指标。结合直方图指标的默认桶边界DefaultLatencyBounds从 10 微秒到 100 秒共 41 桶与DefaultSizeBounds从 0 到 4 GiB 共 14 桶opentelemetry.go读者可以据此在生产环境中为延迟与消息大小配置一致的边界保证 PromQL 聚合与告警口径统一。【免费下载链接】grpc-goThe Go language implementation of gRPC. HTTP/2 based RPC项目地址: https://gitcode.com/GitHub_Trending/gr/grpc-go创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表