Service Mesh 可观测性集成:Envoy 指标如何对接 Prometheus
Service Mesh 可观测性集成Envoy 指标如何对接 Prometheus一、你的 Service Mesh 部署好了但 Grafana 面板上还是只有第一层的 Node Exporter 数据Service Mesh如 Istio的最大卖点之一是自动可观测性——流量经过 Envoy sidecar 时自动产生指标、链路、日志。很多团队部署了 Istio 之后以为可观测性就自动好了打开 Grafana 发现默认面板确实有一些图表——但全是 Envoy 层面的指标请求数、延迟分布、状态码分布看不到你自己服务内部的业务指标。Envoy 自动暴露的指标是 HTTP/TCP 层面的——请求数、响应码、耗时。这对基础设施排障有价值但对业务排障不够。你的服务内部发生了什么数据库查询慢缓存命中率低Agent 推理耗时分布——这些需要你自己在代码里埋点并通过 Prometheus Exporter 暴露。Service Mesh 可观测性集成的正确姿势是Envoy 指标做第一层流量层你的业务指标做第二层业务层两套指标在 Grafana 中做联合查询和关联分析。二、底层机制与原理剖析Envoy 提供的重要指标分组HTTP 连接管理器指标envoy_http_downstream_rq_xx下游请求客户端 → Envoy → 服务端envoy_http_downstream_cx_active当前活跃连接数这些指标告诉你多少流量进来了、多少成功了、多少失败了上游集群指标envoy_cluster_upstream_rq_xx上游请求Envoy → 后端服务envoy_cluster_upstream_cx_connect_timeout连接超时次数envoy_cluster_upstream_cx_active到后端的活跃连接数这些指标告诉你Envoy 到你的服务之间发生了什么Listener 指标envoy_listener_downstream_cx_activeListener 级别活跃连接envoy_listener_ssl_*TLS 握手相关指标Networking 指标envoy_server_liveEnvoy 进程存活状态envoy_server_memory_allocatedEnvoy 内存使用三、生产级代码实现# istio-operator.yaml # Istio 的 Prometheus 指标集成配置 apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: istio-control-plane namespace: istio-system spec: profile: default meshConfig: # 开启 Envoy 的 Prometheus 指标搜集 enablePrometheusMerge: true # 配置 Envoy 的 access log —— 输出为 JSON 格式方便解析 accessLogFile: /dev/stdout accessLogEncoding: JSON # 配置 Envoy 指标 defaultConfig: # 允许自定义的 Prometheus 注解发现 proxyStatsMatcher: inclusionPrefixes: - envoy_http - envoy_cluster - envoy_listener - envoy_server inclusionRegexps: - .*upstream_rq.* - .*downstream_cx.*# k8s/prometheus-pod-monitor.yaml # 用 PodMonitor 让 Prometheus 自动发现 Envoy sidecar 的指标端点 # Envoy 在 :15020/stats/prometheus 暴露指标 apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: name: envoy-sidecar-metrics namespace: istio-system spec: selector: matchLabels: {} # 捕获所有 Pod namespaceSelector: any: true podMetricsEndpoints: - port: http-envoy-prom # Envoy 的 Prometheus 端点端口 path: /stats/prometheus interval: 15s # 每 15 秒抓取一次 relabelings: # 添加 namespace label - sourceLabels: [__meta_kubernetes_namespace] targetLabel: namespace # 添加 pod name label - sourceLabels: [__meta_kubernetes_pod_name] targetLabel: pod # 添加 Service name通过 istio 注入的 label - sourceLabels: [__meta_kubernetes_pod_label_app] targetLabel: app --- # 同时监控应用自身的 /metrics 端点 apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: name: app-metrics namespace: production spec: selector: matchLabels: app.kubernetes.io/component: backend podMetricsEndpoints: - port: metrics # 应用暴露 Prometheus 指标的端口 path: /metrics interval: 15s# envoy_metrics_analyzer.py Envoy 指标分析工具 功能从 Prometheus 查询 Envoy 指标做关联分析 场景发现延迟升高时判断是 Envoy 层还是业务层的问题 import time import logging from typing import Dict, List, Optional, Tuple from dataclasses import dataclass from datetime import datetime, timedelta # prometheus-api-client 推荐或直接用 requests import requests logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) dataclass class LatencyBreakdown: 延迟分解——从 Envoy 到业务的多层分析 total_latency_p99: float # 端到端 P99 延迟 # Envoy 层 envoy_processing_ms: float # Envoy 处理延迟从接收到转发 envoy_upstream_ms: float # Envoy → 后端的网络延迟 # 后端层 app_processing_ms: float # 应用处理延迟由业务 Exporter 暴露 db_query_ms: Optional[float] # 数据库查询延迟如果有 # 判定 bottleneck: str # 瓶颈层级: envoy / app / db / network confidence: float # 判定置信度 0-1 class EnvoyMetricsAnalyzer: Envoy 指标分析器 通过对比 Envoy 层的延迟和业务层的延迟 快速定位延迟瓶颈在哪一层 def __init__(self, prometheus_url: str): self.prometheus prometheus_url.rstrip(/) def _query(self, promql: str, lookback_minutes: int 5) - Optional[float]: 执行 PromQL 查询并返回单一数值 为什么用单一数值而不是时序数据 分析瓶颈只需要当前 P99 是多少不需要历史趋势。 趋势应放在 Grafana 面板中展示。 try: now datetime.utcnow() params { query: promql, time: now.timestamp(), } resp requests.get( f{self.prometheus}/api/v1/query, paramsparams, timeout10, ) resp.raise_for_status() data resp.json() if data[status] ! success: return None results data[data][result] if not results: return None return float(results[0][value][1]) except Exception as e: logger.error(Prometheus query failed: %s, e) return None def analyze_latency(self, service_name: str, namespace: str production) - Optional[LatencyBreakdown]: 分析指定服务的延迟定位瓶颈 分析逻辑 1. 查 Envoy 层总延迟 P99 2. 查 Envoy 处理延迟sidecar 自身消耗 3. 查上游Envoy → 服务网络延迟 4. 查业务层处理延迟 5. 如果 Envoy 总延迟 - Envoy 自身延迟 - 上游延迟 业务层延迟 50ms 说明 Envoy 到业务之间有额外的网络延迟可能是跨 AZ # 1. Envoy 总请求延迟 P99 envoy_total_p99 self._query( fhistogram_quantile(0.99, fsum(rate(istio_request_duration_milliseconds_bucket{{ fdestination_service_name~.*{service_name}.*, fdestination_workload_namespace{namespace} f}}[10m])) by (le)) ) # 2. Envoy 到上游 (upstream) 的延迟 P99 upstream_p99 self._query( fhistogram_quantile(0.99, fsum(rate(envoy_cluster_upstream_rq_time_bucket{{ fenvoy_cluster_name~.*{service_name}.* f}}[10m])) by (le)) ) # 3. 业务层处理延迟 P99由应用 Exporter 暴露 app_p99 self._query( fhistogram_quantile(0.99, fsum(rate(http_request_duration_seconds_bucket{{ fservice{service_name} f}}[10m])) by (le)) * 1000 # 转毫秒 ) # 4. 数据库查询延迟 P99 db_p99 self._query( fhistogram_quantile(0.99, fsum(rate(db_query_duration_seconds_bucket{{ fservice{service_name} f}}[10m])) by (le)) * 1000 ) # 5. 分析和判定 if envoy_total_p99 is None: return None envoy_processing envoy_total_p99 - (upstream_p99 or 0) envoy_processing max(0, envoy_processing) # 避免负值 # 计算瓶颈 if upstream_p99 and upstream_p99 envoy_total_p99 * 0.6: bottleneck network # 上游网络延迟占主导 confidence 0.8 elif db_p99 and app_p99 and db_p99 app_p99 * 0.7: bottleneck db # 数据库查询占主导 confidence 0.9 elif app_p99 and app_p99 envoy_total_p99 * 0.5: bottleneck app # 业务逻辑占主导 confidence 0.8 else: bottleneck envoy # 其他情况Envoy 自身或无法归因 confidence 0.5 return LatencyBreakdown( total_latency_p99envoy_total_p99, envoy_processing_msenvoy_processing, envoy_upstream_msupstream_p99 or 0, app_processing_msapp_p99 or 0, db_query_msdb_p99, bottleneckbottleneck, confidenceconfidence, ) # --------------------------------------------------------------------------- # 使用示例 # --------------------------------------------------------------------------- if __name__ __main__: analyzer EnvoyMetricsAnalyzer(prometheus_urlhttp://prometheus:9090) result analyzer.analyze_latency(agent-api, production) if result: print(fAgent API 延迟分解分析:) print(f 端到端 P99: {result.total_latency_p99:.0f}ms) print(f Envoy 处理: {result.envoy_processing_ms:.0f}ms) print(f 上游网络: {result.envoy_upstream_ms:.0f}ms) print(f 应用处理: {result.app_processing_ms:.0f}ms) if result.db_query_ms: print(f 数据库查询: {result.db_query_ms:.0f}ms) print(f 瓶颈判定: {result.bottleneck} (置信度: {result.confidence:.0%}))四、边界分析与架构权衡Envoy 指标的膨胀问题Envoy 暴露的指标数量取决于集群中 Service、Cluster、Listener 的数量。大规模集群1000 Service中单 Envoy 可能暴露几千条时间序列解决用proxyStatsMatcher配置只暴露需要的指标前缀减少 Prometheus 的时间序列压力Envoy 指标 vs 业务指标的区分Envoy 指标回答的是请求去哪了、多快流量层面业务指标回答的是请求做对了没业务层面两者缺一不可——Envoy 告诉你延迟高了但不告诉你为什么高了兼容性注意事项Istio 1.5 使用istio_request_duration_milliseconds替换了早期的istio_request_duration_seconds指标名和 bucket 定义都变了升级 Istio 版本时Grafana 面板和告警规则需要同步更新 PromQL五、总结Service Mesh 的自动可观测性只覆盖流量层。Envoy 指标请求数、延迟、状态码加上你自己的业务指标数据库延迟、缓存命中率、Agent 推理耗时两层指标在 Grafana 中做联合查询才是完整的可观测性。关键是用 Envoy 的 upstream 延迟和应用处理延迟作对比——差值就是网络开销或 Envoy 本身的开销。这个差值是你优化网络架构的关键输入。