拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Grafana Tempo Service Graphs 详解:从 metrics-generator 配置、虚拟节点识别到 PromQL 拓扑分析

Grafana Tempo Service Graphs 详解从 metrics-generator 配置、虚拟节点识别到 PromQL 拓扑分析【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempoService graphs服务图是 Grafana Tempo 基于 metrics-generator 或 Grafana Alloy 从 trace 数据派生出的一类 Prometheus 指标用于可视化分布式系统中服务间的调用关系与依赖。本文将围绕 service_graphs/_index.md 这一核心文档结合 Tempo 仓库中 servicegraphs 处理器源码 与配置参考完整讲解服务图的工作原理、指标体系、虚拟节点识别、子处理器开关、采样倍数修正与过滤策略并给出可直接落地的启用配置和 PromQL 分析查询。读完本文你将能独立完成服务图的启用、调优、指标解读与自定义过滤。什么是服务图服务图是各服务之间相互关系的可视化表示。它通过展示服务间的请求边edge帮助运维与研发人员推断分布式系统拓扑随着分布式系统规模增长、复杂度上升服务图可以帮助你理解系统整体结构提供系统健康的高层概览服务图直接呈现错误率、延迟以及其他相关数据提供系统拓扑的历史视图分布式系统变化频繁服务图可以呈现系统随时间演进的方式。在 Tempo 中服务图由 metrics-generator 或 Grafana Alloy 从 trace 生成 Prometheus 指标后再由 Grafana 以节点图node graph形式呈现。启用方式详见 enable-service-graphs.md。工作原理如何从 trace 生成服务图指标metrics-generator 和 Grafana Alloy 都会处理 trace 并生成服务图形式的 Prometheus 指标。其核心机制是检查 trace 中具有父子关系的 span 对将其配对为一次请求。处理器使用 OpenTelemetry 语义约定来识别多种请求类型。支持的请求类型处理器支持以下三类请求两个服务之间的直接请求出站 span 与入站 span 的span.kind必须分别为client与server跨消息系统的请求出站与入站 span 的span.kind必须分别为producer与consumer数据库请求处理器查找包含span.kindclient且带有db.namespace、db.name、db.system、db.system.name之一属性的 span。数据库 span 的识别属性可通过database_name_attributes配置项自定义。在源码层面servicegraphs.go 中的isClient与isServer辅助函数定义了 span kind 到边方向的映射func isClient(kind v1_trace.Span_SpanKind) bool { return kind v1_trace.Span_SPAN_KIND_CLIENT || kind v1_trace.Span_SPAN_KIND_PRODUCER } func isServer(kind v1_trace.Span_SpanKind) bool { return kind v1_trace.Span_SPAN_KIND_SERVER || kind v1_trace.Span_SPAN_KIND_CONSUMER }即client与producer被视为客户端侧server与consumer被视为服务端侧这也是过滤策略只针对这四种 span kind 求值的原因见下文。边的配对与超时处理器会将所有可能组成请求对的 span 保存在内存存储中直到对应的配对 span 到达或超过最长等待时间。无论哪种情况先发生处理器都会记录这次请求并将其从本地存储中移除。这一逻辑在 store/store.go 中实现Store使用map[edgeKey]*Edge缓存边edgeKey由 trace ID 与 span ID服务端场景下为 parent span ID构成边一旦同时具备ClientService与ServerService即视为完成并触发onComplete回调见 edge.go 的isComplete判断。未能在wait默认 10s内配对的边由后台 worker 定期调用Expire()清理默认每 2 秒执行一次。每条发出的指标序列都带client和server标签分别对应发起请求的服务与接收请求的服务。典型输出如下traces_service_graph_request_total{clientapp, serverdb, connection_typedatabase} 20需要特别注意的是服务图处理器必须处理一条 trace 的所有 span 才能正常工作。如果一条 trace 的 span 分散在多个 metrics-generator 实例上处理器就无法可靠地完成配对因为 client 侧与服务端侧分别落在不同实例的本地 store 中。虚拟节点Virtual nodes虚拟节点是 trace 生命周期中真实存在、但因其处于用户可达范围之外或未被插桩而没有采集到 span 的节点。例如一个不受用户交互控制的外部支付处理服务可能就不会采集它的 span。处理器通过两种方式检测虚拟节点未插桩的客户端缺少 client span当根 span 的span.kind为server或consumer且找不到匹配的 client span 时说明请求或消息是由外部未插桩系统发起的例如调度器、前端应用或工程师手动执行的curl在Tempo metrics-generator中处理器会先在 server span 上检查配置的peer_attributes。如果找到匹配属性则用该值作为客户端节点名否则客户端节点名默认为user在Grafana Alloy与 OpenTelemetry Collectorservicegraphconnector 中connector 不会为此场景求值 peer 属性客户端节点名始终默认为user且不可覆盖。未插桩的服务端缺少 server span当 client span 没有匹配的 server span但带有 peer 属性时说明客户端调用了外部不发 span 的服务。处理器使用 peer 属性的值作为虚拟服务端节点名默认 peer 属性为peer.service、db.name、db.system、db.system.name处理器按顺序搜索这些属性使用第一个匹配值作为虚拟节点名。数据库节点的识别与命名当 span 带有db.namespace、db.name、db.system、db.system.name中至少一个属性时处理器将其识别为数据库节点。数据库节点名的确定按以下属性顺序取优先级peer.service→server.address→network.peer.address:network.peer.port→ 最后使用 span 携带的database_name_attributes列表中的第一个匹配属性。这一逻辑在 upsertDatabaseRequest 中实现源码注释明确说明先检查peer.service再检查server.address随后检查network.peer.address若存在network.peer.port则拼接为host:port最后回退到db.name以保持向后兼容行为。源码级验证在过期回调 onExpire 中若ClientService为空且边是根边IsRoot()则客户端节点名取PeerNode否则为user若ServerService为空但有PeerNode则以 peer 值命名服务端虚拟节点。启用enable_virtual_node_label后还会分别写入virtual_nodeclient或virtual_nodeserver维度。子处理器按需启用特定指标默认情况下service-graphs处理器会生成全部服务图指标。如果你只想启用其中一部分指标类别可以通过 overrides 配置中的子处理器subprocessors实现service-graphs-request—— 仅启用traces_service_graph_request_total和traces_service_graph_request_failed_total两个计数器service-graphs-latency—— 仅启用traces_service_graph_request_server_seconds和traces_service_graph_request_client_seconds两个直方图。其中traces_service_graph_request_messaging_system_seconds直方图还需在 metrics-generator 配置中额外设置enable_messaging_system_latency_histogram: trueservice-graphs-connection-info—— 仅启用traces_service_graph_connection_info仪表盘gauge。子处理器的语义规则裸名service-graphs启用 request 与 latency 指标与历史行为保持一致service-graphs-connection-info默认关闭必须显式列出将service-graphs-connection-info与裸名并列列出时是叠加生效不会关闭 RED 指标将service-graphs-request或service-graphs-latency与裸名并列列出属于冗余会被静默丢弃。源码中subprocessors.go 定义了Request、Latency、ConnectionInfo三个枚举config.go 的默认配置只开启 Request 与 LatencyConnectionInfo 保持关闭opt-in。示例 overrides 配置overrides: defaults: metrics_generator: processors: - service-graphs - service-graphs-connection-info对应到处理器实例化逻辑servicegraphs.goRequest子处理器创建两个 CounterLatency子处理器创建两个或三个直方图ConnectionInfo子处理器创建一个 Gauge。连接信息指标connection info metrictraces_service_graph_connection_info是一个仅表示存在性的仪表盘当两个服务之间的边正在被观测时其值保持为1。该指标面向拓扑发现而非速率计算只要观测到单个 span仪表盘就会保持存在因此在低流量端点、或激进头部采样导致rate(traces_service_graph_request_total[...])噪声很大甚至为零时服务间的依赖关系依然可见。推荐使用长窗口的last_over_time查询来探测边的存在性last_over_time(traces_service_graph_connection_info[1h]) 0在源码中onComplete 会以值1写入该 gauge注释说明该序列在对应标签集的边停止完成后会过期并被清除。导出指标一览服务图处理器导出的全部指标如下MetricTypeLabelsDescriptiontraces_service_graph_request_totalCounterclient, server, connection_type两个节点之间的请求总数traces_service_graph_request_failed_totalCounterclient, server, connection_type两个节点之间的失败请求总数traces_service_graph_request_server_secondsHistogramclient, server, connection_type从服务端视角观察到的两个节点间一次请求耗时traces_service_graph_request_client_secondsHistogramclient, server, connection_type从客户端视角观察到的两个节点间一次请求耗时traces_service_graph_request_messaging_system_secondsHistogramclient, server, connection_type默认关闭通过消息系统通信的服务publisher 与 consumer 之间的耗时traces_service_graph_connection_infoGaugeclient, server, connection_type默认关闭服务间边关系的存在性信号每条活跃边取值 1traces_service_graph_unpaired_spans_totalCounterclient, server, connection_type未配对 span 的总数traces_service_graph_dropped_spans_totalCounterclient, server, connection_type被丢弃 span 的总数几点重要说明处理器会从客户端和服务端两侧分别测量请求耗时对应两个*_seconds直方图connection_type的可能取值unset未设置、virtual_node、messaging_system、database。对应源码常量见 store/edge.go可通过dimensions配置项或enable_virtual_node_label选项为指标附加更多标签。关于重复维度允许在 Prometheus 标签名转换后出现重复维度这适用于不同插桩库使用不同属性命名约定的场景例如deployment.environment与deployment_environment。发生冲突时最后配置的值生效。启用enable_virtual_node_label启用该功能后指标会额外增加一个virtual_node标签显式标记未插桩的一侧LabelPossible ValuesDescriptionvirtual_nodeunset,client,server显式指示未插桩的一侧从源码看启用后该标签作为维度被加入指标并在onExpire生成虚拟节点边时写入对应值见 servicegraphs.go。配置选项详解服务图处理器的配置项远不止dimensions与enable_virtual_node_label。完整的 YAML 结构与默认值请参考 configuration/_index.md 中的 metrics-generator 段落以及源码 config.go 中的RegisterFlagsAndApplyDefaults。以下为完整配置骨架与默认值metrics_generator: processor: service_graphs: # 等待一条边完成的最长时间 [wait: duration | default 10s] # store 中缓存的最大边数量 [max_items: int | default 10000] # 用于处理边的 worker 数量 [workers: int | default 10] # 延迟直方图的分桶秒 [histogram_buckets: list of float | default 0.1, 0.2, 0.4, 0.8, 1.6, 3.2, 6.4, 12.8] # 附加维度标签在 resource 与 span 属性中查找 [dimensions: list of string] # 为附加维度添加 client_ 与 server_ 前缀每个维度生成两个标签 [enable_client_server_prefix: bool | default false] # 为消息系统交互额外生成一个直方图 # 若该特性需要覆盖长时间范围高延迟考虑增大 wait 值 [enable_messaging_system_latency_histogram: bool | default false] # 用于创建 peer 边的属性按配置顺序搜索 [peer_attributes: list of string | default [peer.service, db.name, db.system, db.system.name]] # 用于放大 span 指标的属性键在 resource 与 span 属性中查找 [span_multiplier_key: string | default ] # 从 W3C tracestate 概率采样阈值 (otth:hex) 提取放大倍数 # 启用后优先级高于 span_multiplier_key [enable_tracestate_span_multiplier: bool | default false] # 为未插桩服务与虚拟节点启用额外标签 [enable_virtual_node_label: bool | default false] # 用于识别数据库名称的属性列表按顺序搜索、首个匹配生效 # 数据库节点依次按 peer.service - server.address - network.peer.address # - 本列表首个匹配属性 命名 [database_name_attributes: list of string | default [db.namespace,db.name,db.system,db.system.name]] # 应用于 span 的包含/排除策略列表 [filter_policies: list of filter policies config | default []]Span 倍数采样补偿当 trace 被采样时服务图处理器产生的原始请求计数会低于实际流量。span_multiplier_key选项指定一个携带采样比例的 span 或 resource 属性处理器计算该值的倒数来放大指标。例如若 span 带有属性X-SampleRatio0.110% 采样设置span_multiplier_key: X-SampleRatio后每个被采样的 span 会计作 10 次请求。enable_tracestate_span_multiplier提供了另一种方式从 W3C tracestate 头中按 OpenTelemetry 概率采样阈值otth:hex提取倍数。启用后tracestate 阈值的优先级高于span_multiplier_key。在源码 servicegraphs.go 中当任一选项开启usesSpanMultiplier为 true时每个 span 都会调用GetSpanMultiplier计算倍数边完成时Counter 的增量与直方图的观测值都会乘以SpanMultiplier见onComplete中的IncBorrowed(..., 1*e.SpanMultiplier, ...)。数据库名称属性database_name_attributesdatabase_name_attributes控制处理器用哪些 span 属性将 span 识别为数据库请求。默认值为db.namespace、db.name、db.system、db.system.name。处理器按列表顺序搜索使用 span 携带的第一个匹配属性。选值考量db.namespace与db.name标识的是数据库本身例如mydb因此优先级高于仅标识数据库产品例如postgresql的db.system与db.system.name在该第二对中db.system.name在语义约定 v1.30.0 中取代了db.system排在最后因此仍然发送db.system的插桩会得到与之前相同的节点名保证向后兼容如果你的插桩使用了非标准属性名可以覆盖此列表。该默认顺序同样体现在源码默认值中config.godb.namespace、db.name来自 semconv v1.25.0在前db.system与db.system.name来自 semconv v1.34.0在后。过滤策略filter_policiesfilter_policies允许你从服务图生成中包含或排除 span其格式与 span metrics 的过滤策略 相同。服务图处理器只评估能够构成边的 spanSPAN_KIND_CLIENT、SPAN_KIND_SERVER、SPAN_KIND_PRODUCER、SPAN_KIND_CONSUMER。当一条边的某一侧被过滤掉时Tempo 会为被丢弃的一侧保留一个 best-effort 标记并在另一侧稍后到达或已被缓冲时丢弃匹配侧。这可以减少偏斜的边和不想要的虚拟节点。该标记缓存的 TTL 使用wait最大容量使用max_items。策略行为语义include所有 include 策略都必须匹配include_any任一 include_any 策略匹配即可。如果只配置了 include_any 策略不匹配的 span 会被排除exclude匹配的 span 被拒绝即使它也匹配某个 include 规则。使用 resource 与 span 属性的 scoped key例如resource.service.name或span.http.route。支持的内建intrinsic键为name、status、kind。支持的属性值类型为bool、double、int、string。示例排除来自shop-backend的服务图 spanmetrics_generator: processor: service_graphs: filter_policies: - exclude: match_type: strict attributes: - key: resource.service.name value: shop-backend从源码看servicegraphs.go 中只有能构成边的 span 才会执行filter.ApplyFilterPolicy被过滤的 span 会通过addDroppedSpanSide写入丢弃侧标记并递增filteredSpansCounter。该标记缓存及溢出逻辑位于 store/store.go。你可以通过以下指标监控服务图过滤的效果tempo_metrics_generator_spans_discarded_total{reasonservice_graphs_filtered, processorservice-graphs}tempo_metrics_generator_processor_service_graphs_dropped_edges_totaltempo_metrics_generator_processor_service_graphs_dropped_span_side_cache_overflow_total如何启用服务图服务图可通过 Tempo 自带的 metrics-generator 生成也可由 Grafana Alloy 生成。官方推荐在较大规模部署中使用 metrics-generator因为它更高效。使用 metrics-generator 启用需要以下组件配合才能完整使用服务图在 Tempo 中启用启用 metrics-generator并在 overrides 中启用service-graphs处理器详见 enable-service-graphs.md。metrics-generator 处理器默认是关闭的需要对指定租户在 overrides 的metrics_generator.processors中配置在 Grafana 中启用Grafana 中服务图默认开启早于 Grafana 9.0.4 的版本需通过tempoServiceGraph特性开关启用。将 Tempo 数据源链接到 metrics 所在的 Prometheus 后端apiVersion: 1 datasources: # Prometheus backend where metrics are sent - name: Prometheus type: prometheus uid: prometheus url: prometheus-url jsonData: httpMethod: GET version: 1 - name: Tempo type: tempo uid: tempo url: tempo-url jsonData: httpMethod: GET serviceMap: datasourceUid: prometheus version: 1使用 Grafana Alloy 启用Grafana Alloy 使用otelcol.connector.servicegraph组件生成同样的服务图指标。以下示例将http.method和http.target两个 span 属性作为 Prometheus 标签加入生成的服务图指标然后写入 Grafana OTLP 网关接收到的 trace span 则直接转发到 OTLP 网关otelcol.receiver.otlp default { grpc {} http {} output { traces [ otelcol.connector.servicegraph.default.input, otelcol.exporter.otlp.default.input, ] } } otelcol.connector.servicegraph default { dimensions [http.method, http.target] output { metrics [otelcol.exporter.otlp.default.input] } } otelcol.exporter.otlp default { client { endpoint env(OTLP_ENDPOINT) } }用 PromQL 分析服务图数据Grafana 使用 Tempo 生成的服务图指标绘制可视化但你也可以直接用 PromQL 查询这些指标以编程方式分析服务间的互联关系甚至构建下游应用。以下查询摘自 metrics-queries.md分即时查询与范围查询两类。即时查询服务间连通性展示最近 7 天每对 client/server 的总调用量sum(increase(traces_service_graph_request_server_seconds_count{}[7d])) by (server, client) 0只看某个服务作为服务端时的客户端分布sum(increase(traces_service_graph_request_server_seconds_count{serverfoo}[7d])) by (client) 0只看某个服务作为客户端时的服务端分布sum(increase(traces_service_graph_request_server_seconds_count{clientfoo}[7d])) by (server) 0以上查询均可调整时间区间例如将7d改为1d即可改为一天内的分析。范围查询服务间速率使用rate计算任意服务作为客户端或服务端时的速率5 分钟窗口能获得更灵敏的曲线sum(rate(traces_service_graph_request_server_seconds_count{serverfoo}[5m])) by (client) 0 sum(rate(traces_service_graph_request_server_seconds_count{clientfoo}[5m])) by (server) 0范围查询服务间延迟分位数使用histogram_quantile计算延迟分位数。以下查询计算 90 分位.9可改为p50、p95、p99等任意分位histogram_quantile(.9, sum(rate(traces_service_graph_request_server_seconds_bucket{clientfoo}[5m])) by (server, le))使用可选的traces_service_graph_request_messaging_system_seconds直方图观察消息系统的中间件延迟需启用enable_messaging_system_latency_histogramhistogram_quantile(.9, sum(rate(traces_service_graph_request_messaging_system_seconds_bucket{}[5m])) by (client, server, le))在 Grafana 中使用服务图视图Grafana 的服务图视图基于 metrics-generator 或 Grafana Alloy 生成的指标展示 span 请求速率、错误率、耗时以及服务图本身。使用前提Tempo或 Grafana Cloud Traces已启用并配置 metrics-generator或已启用并配置 Grafana Alloy 将数据发送到 Prometheus 兼容的指标存储启用 服务图Grafana 中默认开启在 Tempo 数据源配置中启用 span metrics。该视图提供 span metrics 表格含 Name、Rate、Error Rate、Duration、Links 等列与服务图节点图node graph并支持通过标签过滤器缩小数据范围。视图细节请参阅 service-graph-view.md。总结与监控建议服务图是理解分布式系统拓扑与健康状况最直观的入口之一。围绕本文内容实践时的关键要点可归纳为确保单实例可处理一条 trace 的全部 span否则边无法可靠配对wait默认 10s与max_items默认 10000决定了内存 store 的容量与配对窗口利用子处理器按需裁剪指标尤其是默认关闭的service-graphs-connection-info它适合低流量拓扑发现在采样环境下务必配置采样补偿span_multiplier_key或enable_tracestate_span_multiplier否则请求计数会系统性低估通过filter_policies排除噪声服务并利用tempo_metrics_generator_processor_service_graphs_dropped_edges_total等指标监控过滤是否造成了边丢失或异常虚拟节点。如需进一步深入可以阅读 servicegraphs 处理器的单元测试 与 store 的配对/过期测试其中包含大量真实 trace 样例如trace-with-virtual-nodes.json、trace-with-db-namespace.json等有助于理解各类边配对与虚拟节点场景的实际行为。【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门