第一章:Golang全局Metrics暴露规范:Prometheus指标命名黄金法则+12个必埋点场景清单
Prometheus指标命名不是随意拼接,而是遵循 namespace_subsystem_metric_name 三段式结构,其中 namespace 表示应用或组织标识(如 myapp),subsystem 描述模块边界(如 http、db、cache),metric_name 使用下划线分隔的蛇形命名并以语义后缀结尾(如 _total、 _duration_seconds、 _count、 _gauge)。禁止使用驼峰、空格、特殊字符,且所有指标必须附带明确的 HELP 文本与 TYPE 声明。
指标命名黄金法则
- ✅ 推荐:
myapp_http_request_duration_seconds_bucket - ❌ 禁止:
MyAppHttpRequestLatencyMs(驼峰)、http_requests(缺失namespace)、request_count(无subsystem和语义后缀) - 所有计数器(Counter)必须以
_total结尾;直方图(Histogram)默认生成_bucket、_sum、_count;仪表盘类(Gauge)应反映瞬时状态,如myapp_cache_items_gauge
12个必埋点场景清单
| 场景类别 | 推荐指标名 | 类型 | 说明 |
|---|---|---|---|
| HTTP请求总量 | myapp_http_requests_total |
Counter | 按 method、status、path 标签区分 |
| 请求延迟直方图 | myapp_http_request_duration_seconds |
Histogram | buckets: [0.01, 0.05, 0.1, 0.3, 1] |
| 数据库连接池使用 | myapp_db_connections_used_gauge |
Gauge | 实时连接数 |
| Goroutine数量 | myapp_go_goroutines_gauge |
Gauge | runtime.NumGoroutine() |
| 内存分配总量 | myapp_go_mem_allocs_total |
Counter | runtime.ReadMemStats().TotalAlloc |
在 main.go 中初始化指标示例:
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
httpRequests = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: "myapp",
Subsystem: "http",
Name: "requests_total",
Help: "Total number of HTTP requests processed",
},
[]string{"method", "status", "path"},
)
)
func init() {
prometheus.MustRegister(httpRequests) // 注册到默认注册表
}
// 在HTTP handler中调用
httpRequests.WithLabelValues(r.Method, status, path).Inc()
暴露端点需启用 promhttp.Handler(),并在 http.ListenAndServe(":9090", nil) 前注册路由:
http.Handle("/metrics", promhttp.Handler())。所有指标必须可被 curl http://localhost:9090/metrics 正确解析,且无重复注册或类型冲突。
第二章:Prometheus指标命名的黄金法则与工程实践
2.1 指标名称的语义化设计:namespace_subsystem_name_suffix 命名范式解析
指标命名不是字符串拼接,而是可观测性契约的具象表达。namespace_subsystem_name_suffix 范式将维度信息编码进名称本身:
namespace:租户/环境隔离层(如prod、tenant_a)subsystem:模块边界(如auth、payment)name:业务语义核心(如token_validations)suffix:指标类型标识(如_total、_duration_seconds、_failed)
# Prometheus 指标定义示例
http_requests_total{namespace="prod", subsystem="api_gateway", job="ingress"} 12483
# 注:此处 labels 承载动态维度,而 metric name 保持静态语义结构
# suffix "_total" 明确指示累加型计数器,避免与 _rate 或 _bucket 混淆
该设计使指标具备自解释性,支持跨团队无歧义查询。
| 组件 | 示例值 | 作用 |
|---|---|---|
| namespace | staging |
隔离部署环境 |
| subsystem | cache_redis |
标识技术栈与职责域 |
| suffix | _bucket |
表明是 Histogram 的分桶指标 |
graph TD
A[metric_name] --> B[namespace]
A --> C[subsystem]
A --> D[name]
A --> E[suffix]
E --> F["_count: 计数器总量"]
E --> G["_sum: 求和值"]
E --> H["_bucket: 分位统计"]
2.2 标签(Label)策略:高基数陷阱规避与业务维度正交建模
Prometheus 中标签设计直接影响存储效率与查询性能。高基数标签(如 request_id、user_email)极易引发时间序列爆炸,单个指标实例数可突破百万级。
高基数陷阱典型场景
- 用户ID作为标签 → 每个用户生成独立时间序列
- 订单号、TraceID等唯一标识符混入标签集
- 动态路径参数未聚合(如
/api/user/{id}中{id}未替换为:user_id)
正交建模实践原则
- 业务维度分离:将
env、service、region等稳定维度作为标签; - 动态属性降维:将高基数字段转为指标注解(
__meta_*)或落库关联; - 命名规范约束:
| 维度类型 | 推荐标签名 | 基数控制 | 示例值 |
|---|---|---|---|
| 环境 | env |
≤5 | prod, staging |
| 服务 | service |
≤100 | payment-api, auth-svc |
| 错误类型 | error_code |
≤50 | 404, 503, timeout |
# ✅ 合规:错误码正交,基数可控
http_requests_total{env="prod", service="checkout", error_code="503"} 127
# ❌ 高风险:email引入高基数
http_requests_total{env="prod", service="checkout", user_email="a@b.com"} 1 # → 单日生成数万序列
逻辑分析:
user_email标签使每个邮箱地址创建独立时间序列,导致 TSDB 存储膨胀与查询索引失效;而error_code作为有限枚举值,天然支持高效分组聚合(如sum by(error_code)),且不破坏维度正交性。
标签治理流程
graph TD
A[原始埋点数据] --> B{是否唯一/动态?}
B -->|是| C[移至metric annotation或外部DB]
B -->|否| D[映射为稳定业务标签]
D --> E[通过Relabeling规则标准化]
E --> F[写入TSDB]
2.3 类型选择指南:Counter、Gauge、Histogram、Summary 的适用边界与反模式
何时用 Counter?
仅用于单调递增的累计指标(如 HTTP 请求总数、错误发生次数)。
不可重置、不可减少,否则监控系统将误判为采集异常或服务重启。
# ✅ 正确:只调用 inc()
http_requests_total = Counter('http_requests_total', 'Total HTTP Requests', ['method', 'status'])
http_requests_total.labels(method='GET', status='200').inc()
# ❌ 反模式:试图设置或减量
# http_requests_total.labels(...).dec() # 不支持!
# http_requests_total.set(100) # 破坏单调性,Prometheus 拒绝
inc() 是唯一安全操作;标签组合需稳定,避免高基数。
Gauge 的弹性边界
适合可增可减、带瞬时意义的值:内存使用率、活跃连接数、队列长度。
⚠️ 避免用 Gauge 替代 Counter 记录事件频次(丧失速率计算能力)。
| 类型 | 是否支持重设 | 是否支持负值 | 典型 PromQL 聚合 |
|---|---|---|---|
| Counter | 否 | 否 | rate(), increase() |
| Gauge | 是 | 是 | avg_over_time() |
| Histogram | 否 | 否 | histogram_quantile() |
| Summary | 否 | 否 | 原生分位数(无聚合回溯) |
Histogram vs Summary:关键抉择
- Histogram:服务端分桶,支持跨实例聚合(推荐用于延迟、大小类指标);
- Summary:客户端计算分位数,无法事后重新聚合(仅适用于单实例 SLA 追踪)。
graph TD
A[原始观测值] --> B{Histogram}
A --> C{Summary}
B --> D[服务端记录 bucket_count + sum + count]
C --> E[客户端直接输出 quantile=0.99: 124ms]
2.4 单位标准化与文档注释规范:HELP文本编写与单位一致性校验
HELP文本编写原则
HELP文本需嵌入函数/模块头部,采用统一模板:@brief 描述用途,@param 标明物理量及SI单位,@return 注明量纲。
单位一致性校验机制
def validate_unit(param_name: str, value: float, expected_unit: str) -> bool:
"""校验输入参数是否符合预设单位(如'm'、'kg/s')"""
# 从配置中心加载单位白名单与换算因子
unit_db = {"m": 1.0, "cm": 0.01, "inch": 0.0254} # 基准:米
base_unit = "m"
if expected_unit not in unit_db:
raise ValueError(f"Unsupported unit: {expected_unit}")
return abs(value * unit_db[expected_unit] - value) < 1e-9 # 防止隐式换算
逻辑说明:该函数强制所有长度类参数以米为基准校验,避免height=180(无单位)或height=180.0(单位缺失)引发歧义;unit_db确保单位可扩展,且拒绝未注册单位。
常见单位映射表
| 物理量 | 推荐单位 | 禁用单位 | 校验示例 |
|---|---|---|---|
| 长度 | m |
px, pt |
length=2.5 ✅;length=250 ❌(缺单位) |
| 流量 | kg/s |
L/min |
必须显式声明 @param flow: kg/s |
graph TD
A[解析HELP注释] --> B{提取@param单位声明}
B --> C[匹配unit_db白名单]
C --> D[运行时校验输入值]
D --> E[触发警告或异常]
2.5 多实例/多租户场景下的指标隔离:instance_id、tenant_id、cluster_name 标签治理实践
在可观测性体系中,指标混杂是多租户系统最常见隐患。核心解法在于标签(label)的语义化分层设计与采集时强制注入。
标签职责划分
tenant_id:租户级隔离锚点,用于计费、权限与告警策略路由instance_id:同一租户内服务实例唯一标识(如svc-order-01)cluster_name:物理/逻辑集群归属(如prod-us-west),支撑跨集群对比分析
Prometheus 配置示例(自动注入)
# scrape_configs 中启用标签重写
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_tenant]
target_label: tenant_id
action: replace
- source_labels: [__meta_kubernetes_pod_name, __meta_kubernetes_namespace]
separator: "-"
target_label: instance_id
action: replace
- source_labels: [__meta_kubernetes_cluster_name]
target_label: cluster_name
action: replace
逻辑分析:
relabel_configs在抓取前完成标签注入;__meta_kubernetes_*是Kubernetes服务发现元数据;separator: "-"避免命名冲突;所有标签均不可为空(需配合action: keep_if_equal做兜底校验)。
治理效果对比表
| 场景 | 未治理指标 | 治理后指标 |
|---|---|---|
| 租户A误查租户B数据 | http_requests_total{job="api"} |
http_requests_total{tenant_id="a", ...} |
| 实例扩容后指标混淆 | 多个 pod_name 共享同名标签 |
instance_id="api-v2-03" 独立可溯 |
graph TD
A[原始指标] --> B{是否含 tenant_id?}
B -->|否| C[丢弃或打标失败告警]
B -->|是| D[路由至租户专属TSDB分片]
D --> E[按 cluster_name 聚合对比]
第三章:Golang全局Metrics注册与生命周期管理
3.1 全局注册器(DefaultRegisterer)的初始化时机与并发安全陷阱
DefaultRegisterer 在应用启动早期即被静态初始化,但其内部 sync.Map 与 atomic.Bool 的协同使用存在隐性竞态窗口:
var defaultReg = &DefaultRegisterer{
services: sync.Map{}, // 非线程安全的初始化时机!
initialized: atomic.Bool{},
}
// ⚠️ 注意:此时 services 已可被并发读写,但 initialized 尚未置 true
逻辑分析:sync.Map{} 构造函数本身无锁,但若在 initialized.Store(true) 前触发 Register() 调用,将导致 services.Load/Store 与 initOnce.Do() 逻辑错序。
数据同步机制
- 初始化依赖双重检查:先查
initialized.Load(),再执行sync.Once - 所有注册操作必须通过
mu.RLock()保护元数据快照
常见陷阱对比
| 场景 | 是否安全 | 原因 |
|---|---|---|
init() 中直接调用 Register() |
❌ | initialized 仍为 false,绕过同步控制 |
main() 启动后首次调用 |
✅ | initOnce 已完成,services 处于受控状态 |
graph TD
A[goroutine1: Register] --> B{initialized.Load?}
B -->|false| C[initOnce.Do(initFunc)]
B -->|true| D[services.Store]
C --> E[atomic.StoreTrue]
E --> D
3.2 指标复用与内存泄漏防控:NewCounterVec vs. NewCounter 的选型决策树
核心差异:维度 vs. 单点
NewCounter 创建无标签的单一计数器;NewCounterVec 生成带标签维度的指标向量,支持动态标签组合。
内存风险场景
- 未限制标签 cardinality(如
user_id)→ 标签爆炸 → 内存持续增长 - 静态标签(如
env="prod")适合CounterVec;高基数动态键应避免或预定义白名单
选型决策依据
| 场景 | 推荐类型 | 原因 |
|---|---|---|
| 记录 HTTP 总请求数 | NewCounter |
无需区分维度,零开销 |
按 method, status 统计请求 |
NewCounterVec |
标签组合有限且可枚举 |
按 user_id 计数 |
❌ 禁用 CounterVec |
可能无限扩张,改用 NewCounter + 外部聚合 |
// ✅ 安全用法:预定义有限标签
requests := prometheus.NewCounterVec(
prometheus.CounterOpts{Name: "http_requests_total"},
[]string{"method", "status"},
)
// .WithLabelValues("GET", "200").Inc() —— 固定组合,内存可控
此处
[]string{"method", "status"}定义静态维度集,WithLabelValues仅在注册时生成对应 metric 实例,避免运行时动态扩容。
graph TD
A[是否需多维分类统计?] -->|否| B[NewCounter]
A -->|是| C[标签基数是否 ≤100?]
C -->|是| D[NewCounterVec]
C -->|否| E[改用直方图/外部聚合]
3.3 应用启停阶段的Metrics优雅注销与Prometheus scrape一致性保障
核心挑战
应用重启时,旧进程未及时从Prometheus目标列表中移除,导致 scrape 出现 503 或 stale metrics,引发告警抖动与数据断层。
生命周期钩子设计
Spring Boot Actuator + ApplicationRunner 结合 JVM shutdown hook 实现双保险注销:
@Component
public class MetricsUnregisterHook implements ApplicationRunner, DisposableBean {
private final MeterRegistry registry;
private final PrometheusMeterRegistry prometheusRegistry;
public MetricsUnregisterHook(MeterRegistry registry) {
this.registry = registry;
this.prometheusRegistry = (PrometheusMeterRegistry) registry;
}
@Override
public void run(ApplicationArguments args) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// 主动触发 /actuator/prometheus 内容清空
prometheusRegistry.clear(); // 清空所有 Meter
System.out.println("✅ Metrics registry cleared on shutdown");
}));
}
@Override
public void destroy() {
prometheusRegistry.close(); // 释放 native collector 资源
}
}
逻辑分析:
clear()清除注册表中所有Meter实例,避免/actuator/prometheus接口返回过期指标;close()释放CollectorRegistry底层引用,防止内存泄漏。二者缺一不可。
scrape 一致性保障策略
| 阶段 | 行为 | Prometheus 响应 |
|---|---|---|
| 启动中 | /actuator/health 返回 STARTING |
Target 状态:down |
| 就绪后 | livenessProbe 通过 |
Target 状态:up |
| 关闭中 | readinessProbe 失败 → Pod 终止 |
kubelet 触发 preStop |
数据同步机制
采用 preStop + sleep 延迟确保 scrape 完成最后采集:
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 5"] # 留出 5s 窗口供 Prometheus 抓取末次指标
流程协同示意
graph TD
A[应用启动] --> B[注册Metrics & 上报健康]
B --> C[Prometheus首次scrape]
C --> D[应用关闭请求]
D --> E[preStop sleep 5s]
E --> F[执行Metrics clear/close]
F --> G[Pod Terminated]
第四章:12个必埋点场景的落地实现清单
4.1 HTTP服务层:请求总量、延迟分布、错误率(status_code、method、path 维度)
HTTP服务层可观测性需聚焦三大核心指标:请求总量(QPS)、P50/P90/P99延迟分布与多维错误率(按 status_code、method、path 切片)。
指标采集维度设计
method: GET/POST/PUT/DELETE,区分读写负载特征path:/api/usersvs/api/orders/{id},支持路由级瓶颈定位status_code: 2xx/4xx/5xx 分类聚合,识别客户端误用或服务端崩溃
Prometheus 查询示例
# 按 method 和 path 统计 5xx 错误率(过去5分钟)
rate(http_server_requests_total{status_code=~"5.."}[5m])
/
rate(http_server_requests_total[5m])
此表达式计算各
method+path组合的 5xx 占比;分母为总请求数,分子为 5xx 计数;rate()自动处理计数器重置与时间窗口对齐。
延迟分布热力表示例
| path | method | P90 (ms) | error_rate (%) |
|---|---|---|---|
/api/users |
GET | 128 | 0.3 |
/api/orders/{id} |
GET | 412 | 2.7 |
数据流拓扑
graph TD
A[HTTP Server] --> B[OpenTelemetry SDK]
B --> C[Prometheus Exporter]
C --> D[Prometheus Server]
D --> E[Grafana Dashboard]
4.2 gRPC服务层:Unary/Streaming调用成功率、端到端延迟、消息大小直方图
核心可观测性指标设计
gRPC服务层监控聚焦三大黄金信号:
- 调用成功率:按
method和grpc_code维度聚合,区分 Unary(/pkg.Service/Method)与 Streaming(/pkg.Service/StreamMethod); - 端到端延迟:从客户端
Start到Finish的histogram_quantile(P50/P90/P99); - 消息大小直方图:分别采集
request_size_bytes与response_size_bytes,桶区间为[0, 1KB, 10KB, 100KB, 1MB, 10MB]。
Prometheus 指标采集示例
# grpc_server_handled_histogram_seconds{le="0.1",method="UnaryEcho",service="echo"}
# grpc_client_msg_size_bytes_bucket{le="10240",method="StreamChat",type="request"}
le表示“小于等于”边界;type="request"区分请求/响应方向;method标签保留原始 gRPC 方法名,便于按调用模式下钻分析。
延迟与大小联合分析表
| 调用类型 | P99 延迟 | P99 请求大小 | P99 响应大小 | 异常关联特征 |
|---|---|---|---|---|
| Unary | 128ms | 2.1KB | 4.7KB | 延迟突增时请求大小稳定 |
| Server Streaming | 342ms | 1.8KB | 126KB | 响应大小 >100KB 时 P99 延迟跳变 |
流量模式诊断流程
graph TD
A[采集原始指标] --> B[按 method + code 分组]
B --> C{是否 Streaming?}
C -->|Yes| D[聚合每条流的首包延迟与末包延迟]
C -->|No| E[计算单次 RPC 全链路耗时]
D & E --> F[叠加消息大小直方图交叉分析]
4.3 数据库连接池:活跃连接数、等待队列长度、获取连接耗时(driver、db_name 维度)
连接池监控需按 driver(如 mysql-connector-java、pgjdbc)和 db_name(如 auth_db、order_db)双维度聚合,避免跨库干扰。
关键指标语义
- 活跃连接数:当前正在执行 SQL 的连接(非空闲态)
- 等待队列长度:阻塞在
getConnection()调用中的线程数 - 获取连接耗时:从调用
DataSource.getConnection()到返回连接的 P95 延迟
Prometheus 指标示例
# Micrometer + HikariCP 自动暴露(需启用 tagging)
hikari_connections_active{driver="com.mysql.cj.jdbc.Driver",db_name="user_db"} 12
hikari_connection_acquire_seconds_max{driver="org.postgresql.Driver",db_name="report_db"} 0.842
此指标由 HikariCP 内置 MeterRegistry 注册,
driver和db_name通过HikariConfig.setPoolName()配合自定义MeterFilter注入标签,确保多数据源隔离观测。
典型异常模式对照表
| 现象 | 活跃连接数 | 等待队列长度 | 获取耗时 | 可能根因 |
|---|---|---|---|---|
| 连接泄漏 | 持续增长 | 波动上升 | 显著升高 | Connection.close() 未调用 |
| DB 响应慢 | 稳定高位 | 快速堆积 | P95 > 2s | 数据库锁或慢查询 |
graph TD
A[应用请求 getConnection] --> B{连接池有空闲?}
B -- 是 --> C[返回连接,耗时≈0ms]
B -- 否 --> D[入等待队列]
D --> E{maxPoolSize 未达上限?}
E -- 是 --> F[新建连接]
E -- 否 --> G[阻塞直至超时或释放]
4.4 缓存操作层:Hit/Miss比率、TTL分布、序列化开销(cache_type、key_pattern 维度)
缓存健康度需从多维实时观测:cache_type(如 redis, local_caffeine)与 key_pattern(如 user:profile:{id}, order:batch:{date})共同决定指标语义。
关键指标分片分析
- Hit/Miss 比率:按
cache_type聚合可识别底层瓶颈(Redis网络延迟 vs. Local缓存GC压力) - TTL 分布直方图:
key_pattern维度下,session:*类 TTL 集中于 30m,而config:global多为永不过期(TTL=-1) - 序列化开销:JSON 序列化在
user:profile:{id}场景占比 CPU 时间 12%,而 Protobuf 下降至 3.2%
示例:TTL 分布统计查询(Prometheus Metrics)
# 按 key_pattern 和 cache_type 统计平均 TTL(单位秒)
histogram_quantile(0.9, sum(rate(cache_ttl_seconds_bucket[1h])) by (le, cache_type, key_pattern))
此 PromQL 查询聚合每小时 TTL 直方图,
le标签提供分位数切片能力;cache_type和key_pattern作为关键标签支撑下钻分析,避免指标混叠。
| cache_type | key_pattern | avg_hit_rate | p95_serialization_ms |
|---|---|---|---|
| redis | user:profile:{id} | 0.87 | 4.2 |
| caffeine | config:global | 0.999 | 0.08 |
graph TD
A[请求到达] --> B{key_pattern 匹配}
B -->|user:*| C[查 Redis + JSON]
B -->|config:*| D[查本地 Caffeine + Protobuf]
C --> E[反序列化耗时高]
D --> F[反序列化几乎无开销]
第五章:附录:可直接集成的Go Metrics工具链与最佳实践检查清单
开箱即用的轻量级指标采集器
prometheus/client_golang 是 Go 生态事实标准,支持 Counter、Gauge、Histogram、Summary 四类原语。以下代码片段可在 30 秒内完成 HTTP 请求延迟监控接入:
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var httpDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: prometheus.ExponentialBuckets(0.01, 2, 8),
},
[]string{"method", "path", "status"},
)
func init() {
prometheus.MustRegister(httpDuration)
}
生产环境必备的指标导出端点
建议在服务启动时暴露 /metrics 端点,并通过反向代理(如 Nginx)添加基础认证保护:
| 路径 | 认证方式 | 暴露内容 | 推荐权限 |
|---|---|---|---|
/metrics |
Basic Auth (htpasswd) | Prometheus 格式指标 | 只读角色 |
/debug/metrics |
IP 白名单 + TLS 客户端证书 | runtime.MemStats + goroutine 数量 | 运维专属 |
/healthz |
无认证 | HTTP 200 + uptime | 公开可访问 |
避免指标爆炸的命名规范
错误示例:request_latency_ms{user_id="12345", path="/api/v1/users"}
问题:user_id 是高基数标签,将导致时间序列数量失控。
正确实践:使用 user_tier(free/premium)或 region(us-east-1/cn-shanghai)等低基数维度替代。
自动化健康检查脚本
以下 Bash 片段用于 CI/CD 流水线中验证指标端点可用性及关键指标存在性:
#!/bin/bash
curl -s http://localhost:8080/metrics | \
grep -q "http_requests_total\|go_goroutines" || \
{ echo "Critical metrics missing"; exit 1; }
基于 OpenTelemetry 的统一观测栈集成
采用 otelcol-contrib 作为后端 Collector,配置 YAML 示例:
receivers:
prometheus:
config:
scrape_configs:
- job_name: 'go-service'
static_configs:
- targets: ['localhost:2112']
exporters:
otlp:
endpoint: "otel-collector:4317"
tls:
insecure: true
指标采集频率与资源开销对照表
| 采集间隔 | CPU 增量(单核) | 内存占用(MB) | 适用场景 |
|---|---|---|---|
| 1s | ≤0.8% | ≤2.1 | 高频交易系统核心路径 |
| 15s | ≤0.12% | ≤0.3 | Web API 服务 |
| 60s | 后台任务调度器 |
关键指标黄金信号检查清单
- [ ]
http_requests_total{code=~"5.."} > 0在过去 5 分钟内是否持续增长 - [ ]
process_cpu_seconds_total导数超过阈值(>0.8 核/秒)且持续 3 分钟 - [ ]
go_goroutines> 5000 并持续上升趋势(需结合 pprof 分析) - [ ]
http_request_duration_seconds_bucket{le="0.5"}占比低于 95% - [ ]
redis_client_requests_total{err!="nil"}非零计数持续存在
本地开发调试工作流
使用 docker-compose 快速搭建可观测性沙盒:
services:
prometheus:
image: prom/prometheus:latest
ports: ["9090:9090"]
grafana:
image: grafana/grafana:latest
ports: ["3000:3000"]
启动后访问 http://localhost:3000,导入 ID 为 1860 的 Go Runtime Dashboard,实时观察 GC 周期、堆分配速率、goroutine 泄漏迹象。
指标生命周期管理策略
所有自定义指标必须声明 expiration_ttl 字段并写入 README.md;超过 90 天未被任何 Grafana 面板或告警规则引用的指标,由 CI 脚本自动标记为 @deprecated 并触发 PR 提醒移除。
高并发场景下的采样降频机制
当 QPS > 10k 时,启用动态采样:
if rand.Intn(100) < 5 { // 5% 采样率
httpDuration.WithLabelValues(r.Method, r.URL.Path, status).Observe(latency.Seconds())
} 