第一章:Go语言进阶项目可观测性基建全景概览
现代Go语言高可用服务的稳定运行,高度依赖一套分层协同、轻量嵌入且可扩展的可观测性基建。它并非仅指“加几个监控指标”,而是融合日志、指标、链路追踪、健康检查与运行时诊断能力的统一技术底座,贯穿开发、测试、发布与运维全生命周期。
核心能力维度
- 指标(Metrics):实时采集应用吞吐、延迟、错误率及Go运行时内存/协程/GC等数据,通过Prometheus生态标准化暴露;
- 日志(Logs):结构化、上下文丰富、支持采样与字段索引的日志流,与trace ID对齐以实现问题快速下钻;
- 链路追踪(Tracing):基于OpenTelemetry SDK自动注入span,覆盖HTTP/gRPC/DB调用,实现跨服务请求全路径可视化;
- 健康与就绪探针:遵循Kubernetes规范暴露
/healthz与/readyz端点,集成liveness/readiness逻辑与依赖组件状态(如DB连通性、缓存可用性); - 运行时诊断:利用
runtime/pprof和net/http/pprof暴露CPU、内存、goroutine阻塞等分析端点,支持线上安全采样。
典型集成方式
在Go主程序中,可通过以下方式一键接入基础可观测能力:
import (
"net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/sdk/metric"
)
func setupObservability() {
// 初始化Prometheus指标导出器
exporter, _ := prometheus.New()
provider := metric.NewMeterProvider(metric.WithExporter(exporter))
// 注册HTTP中间件以自动采集请求指标与trace
http.Handle("/api/", otelhttp.NewHandler(http.HandlerFunc(handler), "api"))
// 暴露/metrics端点供Prometheus抓取
http.Handle("/metrics", exporter)
}
该初始化逻辑将指标采集、HTTP链路注入与标准监控端点统一托管,避免各模块重复实现。所有组件均遵循OpenTelemetry规范,确保未来可无缝对接Jaeger、Zipkin或云厂商APM平台。可观测性基建的本质,是让系统行为可表达、可验证、可推理——而非仅“看得见”。
第二章:Prometheus指标建模深度实践
2.1 Prometheus数据模型与Go指标类型语义映射
Prometheus 的核心是 时间序列:metric_name{label1="val1",label2="val2"} → [(timestamp, value), ...]。Go 客户端库(prometheus/client_golang)通过四类原生指标类型实现语义对齐。
四类指标的语义契约
Counter:单调递增计数器(如 HTTP 请求总数),禁止重置(除进程重启)Gauge:可增可减的瞬时值(如内存使用量、goroutine 数)Histogram:分桶统计观测值分布(如请求延迟),自动生成_sum/_count/_bucketSummary:客户端计算分位数(如0.95延迟),含_sum/_count/_quantile
Go 类型到 Prometheus 标签的隐式映射
// 示例:Histogram 自动注入 le="0.1" 等 bucket 标签
httpReqDur := prometheus.NewHistogram(prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Latency distribution of HTTP requests",
Buckets: []float64{0.01, 0.05, 0.1, 0.25, 0.5, 1},
})
此处
Buckets参数决定_bucket时间序列的标签键值对数量;Name成为指标名前缀,Help不影响数据模型但用于/metrics注释。
| Prometheus 类型 | Go 类型 | 关键语义约束 |
|---|---|---|
| Counter | prometheus.Counter |
Inc() / Add(),不可减 |
| Gauge | prometheus.Gauge |
Inc()/Dec()/Set() 均合法 |
| Histogram | prometheus.Histogram |
Observe(float64) 触发分桶聚合 |
| Summary | prometheus.Summary |
Observe() 更新滑动窗口分位数 |
graph TD
A[Go 应用调用 Observe\Add\Set] --> B[客户端 SDK 聚合]
B --> C{指标类型}
C -->|Counter| D[原子累加 + 暴露 _total]
C -->|Histogram| E[分桶计数 + _sum/_count/_bucket]
2.2 自定义业务指标设计:从Gauge到Histogram的场景化选型
何时选择 Gauge?
适用于瞬时状态快照,如当前在线用户数、缓存命中率、任务队列长度。
- ✅ 值可增可减,无累积语义
- ❌ 不支持分位数统计
from prometheus_client import Gauge
# 示例:实时监控订单处理延迟(毫秒)
order_processing_latency = Gauge(
'order_processing_latency_ms',
'Current latency of order processing (ms)',
['region', 'status'] # 多维标签,支持下钻分析
)
order_processing_latency.labels(region='cn-east', status='success').set(142.6)
Gauge.set()直接写入最新值;labels()动态构造多维时间序列,避免指标爆炸;适用于需精确反映“此刻状态”的业务信号。
Histogram 更适合什么场景?
当需观测分布特征(如 P95/P99 延迟)、理解长尾行为时,Histogram 是首选。
| 指标类型 | 数据结构 | 典型用途 | 是否支持分位数 |
|---|---|---|---|
| Gauge | 单个浮点数 | 当前值快照 | 否 |
| Histogram | 桶计数 + 总和 + 计数器 | 延迟/大小分布 | 是(通过 _bucket 和 _sum/_count) |
graph TD
A[HTTP 请求] --> B{响应时间 ≤ 100ms?}
B -->|是| C[+1 to http_request_duration_seconds_bucket{le="0.1"}]
B -->|否| D{≤ 200ms?}
D -->|是| E[+1 to le="0.2"]
D -->|否| F[+1 to le="+Inf"]
Histogram 自动维护预设桶(
buckets),客户端无需计算分位数——Prometheus 服务端通过histogram_quantile()函数实时聚合,兼顾精度与可观测性。
2.3 Go SDK集成与指标生命周期管理(注册、注销、命名规范)
初始化与注册
使用 prometheus.NewRegistry() 创建独立指标注册表,避免全局污染:
reg := prometheus.NewRegistry()
counter := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "api_request_total", // 必须小写字母、数字、下划线
Help: "Total number of API requests",
},
[]string{"method", "status"},
)
reg.MustRegister(counter) // 原子注册,失败 panic
MustRegister 确保指标唯一性校验;重复注册将触发 panic,强制开发者显式处理冲突。
命名规范要点
- ✅ 合法字符:
[a-z0-9_] - ✅ 推荐前缀:
<subsystem>_<name>(如http_request_duration_seconds) - ❌ 禁止:大写字母、连字符、单位后缀(
_seconds除外)
注销机制
Prometheus Go SDK 不支持运行时注销,需通过作用域隔离实现逻辑“卸载”:
| 方式 | 适用场景 | 是否释放内存 |
|---|---|---|
| 新建 Registry | 单元测试/多租户隔离 | ✅ |
| Unregister() | 仅限自定义 Collector | ⚠️ 需手动实现 |
| nil 指针引用 | 不推荐,存在竞态风险 | ❌ |
生命周期图示
graph TD
A[New CounterVec] --> B[MustRegister reg]
B --> C{Usage in Handler}
C --> D[Process metrics]
D --> E[Scrape via /metrics]
E --> F[Registry persists until GC]
2.4 指标采集端点暴露与HTTP中间件嵌入实战
为实现可观测性,需将指标采集端点(如 /metrics)安全、可配置地暴露于应用服务中,并通过轻量级HTTP中间件注入采集逻辑。
指标端点注册示例(Go + Prometheus)
import "github.com/prometheus/client_golang/prometheus/promhttp"
// 注册指标暴露端点
r.Handle("/metrics", promhttp.Handler())
该代码将标准 Prometheus 格式指标响应绑定至 /metrics 路径;promhttp.Handler() 自动聚合全局 Registry 中所有已注册指标,支持 Accept: text/plain;version=0.0.4 等协商格式。
中间件嵌入方式对比
| 方式 | 侵入性 | 动态开关 | 适用场景 |
|---|---|---|---|
| 全局路由注册 | 低 | 否 | 简单服务、调试环境 |
| 条件化中间件链 | 中 | 是 | 生产环境灰度启用 |
| 请求头触发采集 | 高 | 是 | 诊断性按需采样 |
数据同步机制
func MetricsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 记录请求延迟、状态码等基础指标
start := time.Now()
next.ServeHTTP(w, r)
latency.WithLabelValues(r.Method, r.URL.Path).Observe(time.Since(start).Seconds())
})
}
此中间件在每次请求前后注入观测逻辑,latency 为预定义的 HistogramVec 指标,WithLabelValues 动态绑定 HTTP 方法与路径维度,支撑多维下钻分析。
2.5 Prometheus服务发现配置与Kubernetes动态标签注入YAML详解
Prometheus 通过 kubernetes_sd_configs 原生支持 K8s 动态服务发现,自动感知 Pod、Service、Endpoint 等资源生命周期变化。
核心配置结构
- job_name: "kubernetes-pods"
kubernetes_sd_configs:
- role: pod
api_server: https://kubernetes.default.svc
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
该配置仅抓取带 prometheus.io/scrape: "true" 注解的 Pod;__meta_kubernetes_* 是 Prometheus 自动注入的元标签,无需手动维护。
动态标签注入机制
| 标签名 | 来源 | 典型值 |
|---|---|---|
__meta_kubernetes_pod_name |
Pod 元数据 | nginx-deployment-7c54d96bbf-xyz12 |
__meta_kubernetes_namespace |
所属命名空间 | default |
__meta_kubernetes_pod_label_app |
Pod Label | nginx |
标签重写流程
graph TD
A[原始元标签] --> B{relabel_configs 过滤}
B --> C[保留/丢弃目标]
C --> D[drop/replace/keep等动作]
D --> E[最终 target 标签集]
第三章:OpenTelemetry链路追踪一体化落地
3.1 OpenTelemetry Go SDK架构解析与TracerProvider初始化最佳实践
OpenTelemetry Go SDK采用可插拔的分层架构:TracerProvider 为顶层协调者,向下封装 SpanProcessor、SpanExporter 与 Resource,向上提供 Tracer 实例。
核心组件职责
TracerProvider:生命周期管理与配置聚合SpanProcessor:同步/异步 Span 处理(如BatchSpanProcessor)SpanExporter:协议适配(OTLP/gRPC、Jaeger、Zipkin)
推荐初始化模式
import (
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
)
func newTracerProvider() *sdktrace.TracerProvider {
exporter, _ := otlptracegrpc.New(context.Background()) // 生产环境需错误处理
processor := sdktrace.NewBatchSpanProcessor(exporter) // 默认批处理:200 Span / 5s
return sdktrace.NewTracerProvider(
sdktrace.WithSpanProcessor(processor),
sdktrace.WithResource(resource.MustMerge(
resource.Default(),
resource.NewWithAttributes(semconv.SchemaURL,
semconv.ServiceNameKey.String("auth-service"),
semconv.ServiceVersionKey.String("v1.2.0"),
),
)),
)
}
该初始化显式分离导出器与处理器,避免默认 NoopTracerProvider 误用;WithResource 确保服务元数据注入,是可观测性关联的关键依据。
| 配置项 | 推荐值 | 说明 |
|---|---|---|
BatchSpanProcessor size |
512 | 平衡内存占用与延迟 |
| Export timeout | 10s | 防止阻塞关键路径 |
| Resource attributes | 必填 service.name |
支持后端服务发现与分组 |
graph TD
A[TracerProvider] --> B[Tracer]
A --> C[BatchSpanProcessor]
C --> D[OTLP/gRPC Exporter]
D --> E[Collector]
3.2 上下文传播机制实现:HTTP/GRPC拦截器与自定义Span注入
分布式追踪依赖上下文在服务调用链中无缝透传。OpenTelemetry 提供标准化的 TextMapPropagator 接口,支持 HTTP header(如 traceparent)和 gRPC metadata 双通道注入。
HTTP 拦截器注入示例
def http_client_interceptor(request):
# 从当前 SpanContext 提取并注入 W3C TraceContext
carrier = {}
propagator.inject(carrier, context=get_current_span().get_span_context())
request.headers.update(carrier) # 注入 traceparent, tracestate
逻辑分析:propagator.inject() 将当前活跃 Span 的 trace_id、span_id、flags 等序列化为 traceparent 字符串(格式:00-traceid-spanid-01),确保下游服务可无损解析。
gRPC 拦截器关键字段对照
| 传播载体 | 键名 | 值示例 |
|---|---|---|
| HTTP | traceparent |
00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 |
| gRPC | grpc-trace-bin |
二进制编码的 W3C tracestate |
跨协议一致性保障
graph TD
A[Client Span] -->|inject→header/metadata| B[HTTP/gRPC Outbound]
B --> C[Server Interceptor]
C -->|extract→context| D[New Server Span]
3.3 分布式Trace采样策略配置与性能敏感型业务适配
在高并发、低延迟要求的支付与实时风控场景中,全量Trace采集会引入显著的CPU与网络开销。需按业务语义动态调控采样率。
基于QPS与错误率的自适应采样
# application-tracing.yaml
sampler:
type: adaptive
base_rate: 0.01 # 基础采样率(1%)
error_rate_threshold: 0.05 # 错误率 >5% 时升采样至10%
qps_threshold: 1000 # QPS >1k 时降采样至0.1%
该配置通过OpenTelemetry SDK实时聚合指标,每30秒评估一次,避免突发流量下Span爆炸。
多级采样策略优先级表
| 策略类型 | 触发条件 | 采样率 | 适用场景 |
|---|---|---|---|
| 强制采样 | HTTP 5xx 或 biz_error | 1.0 | 故障根因分析 |
| 降级采样 | CPU >90% 持续60s | 0.001 | 服务熔断期间 |
| 标签采样 | trace.tag(“pay_type”: “vip”) | 0.5 | VIP用户全链路追踪 |
采样决策流程
graph TD
A[接收Span] --> B{是否命中强制采样标签?}
B -->|是| C[100%保留]
B -->|否| D[查自适应指标]
D --> E[计算当前采样率]
E --> F[PRNG < rate?]
F -->|是| G[保留Span]
F -->|否| H[丢弃并仅上报统计摘要]
第四章:Loki日志聚合与可观测性三支柱协同
4.1 Go结构化日志输出对接Loki:Zap/Logrus + Promtail Pipeline配置
日志格式对齐要求
Loki依赖标签(labels)而非全文索引,因此Go应用需输出JSON结构化日志,并确保关键字段(如level、service、trace_id)为顶层键。
Zap 配置示例(带注释)
import "go.uber.org/zap"
logger, _ := zap.NewProduction(zap.Fields(
zap.String("service", "auth-api"),
zap.String("env", "prod"),
))
// → 输出形如:{"level":"info","ts":1712345678.90,"caller":"main.go:23","msg":"user logged in","service":"auth-api","env":"prod"}
逻辑分析:NewProduction()启用JSON编码与时间戳;zap.Fields()预置静态标签,被注入每条日志,供Promtail提取为Loki stream selector。
Promtail Pipeline 关键阶段
| 阶段 | 功能 |
|---|---|
docker |
自动解析容器元数据 |
json |
提取 service, level |
labels |
将字段转为Loki标签 |
drop |
过滤 debug 级别日志 |
数据同步机制
graph TD
A[Go App Zap Logger] -->|JSON over stdout| B[Promtail]
B -->|HTTP POST /loki/api/v1/push| C[Loki]
C --> D[Query via LogQL]
Logrus 替代方案要点
- 使用
logrus.JSONFormatter{}+logrus.WithField()注入service/env - 必须禁用
logrus.TextFormatter,避免非结构化输出破坏Pipeline解析
4.2 日志-指标-链路关联建模:trace_id、span_id、request_id多维索引设计
为实现日志、指标与分布式追踪的毫秒级关联,需构建以 trace_id 为根、span_id 为路径节点、request_id 为业务会话锚点的三级索引结构。
核心索引字段语义
trace_id:全局唯一,128-bit UUID,标识一次完整分布式请求span_id:当前调用单元唯一标识,支持父子嵌套(如0xabc→0xabc.def)request_id:HTTP/GRPC Header 中透传的业务ID,用于跨系统身份对齐
Elasticsearch 多字段映射示例
{
"mappings": {
"properties": {
"trace_id": { "type": "keyword", "index": true, "doc_values": true },
"span_id": { "type": "keyword", "index": true },
"request_id": { "type": "keyword", "index": true, "normalizer": "lowercase" }
}
}
}
此映射启用
doc_values支持聚合分析;normalizer确保大小写不敏感匹配,适配不同网关注入习惯。
关联查询性能对比(百万级日志)
| 查询类型 | 平均延迟 | 覆盖率 |
|---|---|---|
trace_id 单跳 |
12ms | 100% |
request_id + span_id |
28ms | 93.7% |
graph TD
A[原始日志] --> B{注入 trace_id/span_id}
B --> C[统一日志管道]
C --> D[ES 多维索引]
D --> E[跨源关联查询]
4.3 Loki查询语法进阶与Grafana日志面板联动可视化实战
多维度日志过滤与标签组合
Loki 查询核心在于 logfmt 标签匹配与流选择器组合。例如:
{job="promtail-k8s", namespace="prod"} |= "timeout" |~ `error|failed` | json | duration > 5000
{...}:指定日志流(基于 Promtail 采集时注入的静态标签)|= "timeout":行内精确匹配字符串|~ regex:正则模糊匹配原始日志行json:自动解析 JSON 日志为动态标签(如status,duration)duration > 5000:对解析出的数值字段做算术过滤
Grafana 面板联动技巧
在 Grafana 中启用「日志上下文」和「追踪跳转」需配置:
- 启用
Explore → Logs → Show labels - 在变量中定义
$namespace,查询中引用{namespace=~"$namespace"} - 添加「Trace to Tempo」链接需日志含
traceID字段且与 Tempo 标签对齐
常见性能优化对照表
| 场景 | 推荐写法 | 避免写法 |
|---|---|---|
| 高基数过滤 | {job="api"} | json | level="error" |
{job="api"} |~ "error"(全量扫描) |
| 时间范围压缩 | [5m](聚合窗口) |
无时间约束导致 OOM |
graph TD
A[用户输入LogQL] --> B{Grafana前端校验}
B --> C[Loki Querier解析AST]
C --> D[Chunk Store并行检索]
D --> E[流式解码+管道过滤]
E --> F[返回结构化日志+统计元数据]
4.4 多租户日志隔离与RBAC权限在K8s环境中的YAML声明式部署
在Kubernetes中实现多租户日志隔离,核心依赖命名空间(Namespace)边界、RBAC策略与日志采集器(如Fluent Bit)的租户感知配置。
日志采集侧租户标签注入
# fluentbit-configmap.yaml:为每租户Pod自动注入namespace_label
apiVersion: v1
kind: ConfigMap
data:
fluent-bit.conf: |
[INPUT]
Name tail
Path /var/log/containers/*.log
Tag kube.*
Parser docker
DB /tail-db/tail-containers-state.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
[FILTER] # 关键:动态注入租户上下文
Name kubernetes
Match kube.*
Merge_Log On
Keep_Log Off
K8S-Logging.Parser On
K8S-Logging.Exclude On
Labels On # → 将namespace作为label透出
该配置启用Labels On,使Fluent Bit自动将kubernetes.namespace_name注入日志字段,为后续ES索引路由或Loki多租户分片提供关键维度。
租户级RBAC最小权限控制
| Role类型 | 可访问资源 | 权限范围 | 适用场景 |
|---|---|---|---|
tenant-viewer |
namespaces/{tenant-ns}/pods/log |
get, list |
日志只读查看 |
tenant-admin |
namespaces/{tenant-ns}/* |
get, list, watch |
租户内全量可观测 |
日志流权限隔离逻辑
graph TD
A[Pod生成容器日志] --> B[Fluent Bit采集并注入namespace_label]
B --> C{RBAC校验}
C -->|通过| D[写入租户专属Loki数据源]
C -->|拒绝| E[丢弃或告警]
第五章:可观测性基建统一交付与生产就绪验证
标准化交付流水线设计
我们基于 GitOps 模式构建了可观测性组件的统一交付流水线,覆盖 Prometheus、Grafana、Loki、Tempo 和 OpenTelemetry Collector 全栈。所有配置均通过 Helm Chart 打包,Chart 版本与语义化版本(如 v1.8.3-20240615)强绑定,并注入 SHA256 配置哈希值至 Release Annotation。CI 阶段执行 helm template --validate + kubeval + conftest 三重校验,确保 YAML 合法性、Kubernetes Schema 兼容性及 SRE 策略合规性(例如:所有 Pod 必须设置 resources.limits.memory <= 2Gi)。流水线日志中自动归档每次部署的完整渲染模板快照,供审计回溯。
生产就绪检查清单自动化执行
交付至预发布集群后,触发一组可插拔的就绪验证任务,以 Bash 脚本+Kubectl 插件形式嵌入 Argo CD 的 PostSync Hook:
# 验证指标端点连通性与基础维度完整性
curl -s "http://prometheus-operated:9090/api/v1/targets" | jq -r '.data.activeTargets[] | select(.health=="up") | .labels.job' | sort -u | wc -l
# 验证 Loki 日志流写入延迟 < 3s(过去5分钟P95)
curl -s "http://loki:3100/loki/api/v1/status/buildinfo" > /dev/null && echo "✅ Loki ready"
验证项固化为 Confluence 表格并同步至内部 SRE 平台,每项对应唯一 ID(如 OBS-CHK-METRICS-001),支持一键触发与结果存档。
多环境差异化配置治理
通过 Kustomize Base + Overlay 实现环境隔离:base/ 包含通用 CRD 和 RBAC;overlays/prod/ 注入 TLS 证书 Secret 引用、高可用副本数(Prometheus StatefulSet replicas=3)、长期存储策略(Thanos Ruler retention=90d);overlays/staging/ 则启用 debug 日志级别与采样率降级(OTel Collector tail_sampling 策略仅保留 10% trace)。所有 Overlay 均经 kustomize build --load-restrictor LoadRestrictionsNone 测试,避免路径遍历风险。
真实故障注入验证闭环
在灰度集群中定期运行 Chaos Engineering 实验:使用 LitmusChaos 注入 pod-delete(针对 Alertmanager)、network-delay(模拟 Grafana 与 Prometheus 间 200ms RTT)、disk-fill(压测 Loki 存储节点)。验证系统是否在 5 分钟内自动恢复告警路由、仪表盘数据刷新延迟回归 ≤1.5s、日志查询 P99 延迟
| 验证维度 | 生产阈值 | 当前达标率 | 自动修复机制 |
|---|---|---|---|
| 指标采集完整性 | ≥99.95% | 99.98% | 自动扩缩 OTel Collector |
| 告警触达时效 | ≤45s(P95) | 38s | 重启 Alertmanager 实例 |
| 日志索引延迟 | ≤120s(P99) | 97s | 动态调优 Loki compactor 并发 |
可观测性自身健康看板
部署专用 “Observability Health Dashboard”,集成 17 个自监控指标:prometheus_build_info{job="prometheus"} == 1(确认进程存活)、kube_pod_container_status_restarts_total{namespace=~"observability|monitoring"} > 0(容器重启告警)、grafana_api_datasources_query_duration_seconds_bucket{le="5"} == 0(慢查询拦截)。该看板作为所有新环境上线的准入门禁——若任一红灯持续 2 分钟,Argo CD 自动暂停同步并通知值班 SRE。
安全合规性嵌入式验证
交付包内置 OPA Gatekeeper 策略:禁止任何可观测组件使用 hostNetwork: true;强制所有对外服务(如 Grafana ingress)启用 nginx.ingress.kubernetes.io/force-ssl-redirect: "true";扫描镜像 otel/opentelemetry-collector-contrib:v0.102.0 的 CVE 数据库,阻断 CVSS ≥7.0 的漏洞组件进入生产。每次交付生成 SBOM(Software Bill of Materials)JSON 文件,经 Sigstore Cosign 签名后存入 Artifactory。
交付产物包含 Helm Release 渲染差异报告、Prometheus Rule 单元测试覆盖率(≥85%)、Loki LogQL 查询性能基线对比图(mermaid):
graph LR
A[Pre-deploy Baseline] -->|P95 latency 112ms| B[Post-deploy Measurement]
B --> C{Delta < 15ms?}
C -->|Yes| D[Auto-approve]
C -->|No| E[Block & Trigger Profiling] 