跳转到内容

可观测性规范

日志、指标、追踪与告警


详细的日志级别、结构化字段、脱敏规则见 日志规范。本章聚焦可观测性场景下的日志采集、检索与留存。

[Requirement] 所有服务的日志必须统一采集到集中式日志平台(ELK / Loki / SLS),禁止仅输出到本地文件。

[Standard] 日志采集架构:

应用容器 → stdout/stderr → Fluent Bit/Fluentd → 日志平台(ES/Loki)

[Requirement] 日志必须为 JSON 结构化格式,包含以下必选字段:

字段说明示例
timestampISO 8601,带毫秒2024-01-01T12:00:00.123Z
level日志级别INFO
service服务名user-service
trace_id链路追踪 IDabc123def456
message日志消息用户登录成功

[Standard] 生产环境日志级别默认 INFO,ERROR 及以上级别必须告警。

级别采集留存告警
DEBUG生产默认关闭,可动态开启1 天否
INFO采集7 天否
WARN采集30 天否
ERROR采集90 天是
FATAL采集180 天是(立即)

[Standard] 日志平台必须支持按 trace_id、service、level、时间范围检索,单次查询响应时间 ≤ 5 秒。

  • ❌ 日志只输出到本地文件,容器销毁后丢失。
  • ❌ 日志使用 print() 非结构化输出,无法检索。
  • ❌ ERROR 日志不告警,故障无人感知。

[Requirement] 指标分为四类:黄金指标(RED)、资源指标、业务指标、自定义指标。

[Requirement] 每个 HTTP/RPC 接口必须暴露以下三个指标:

指标说明
Rate(请求量)每秒请求数 QPS
Errors(错误率)错误请求占比
Duration(耗时)请求响应时间 P50/P95/P99

[Standard] 每个服务必须采集以下资源指标:

指标说明告警阈值参考
CPU 使用率容器/主机 CPU> 80% 持续 5 分钟
内存使用率RSS 内存> 85% 持续 5 分钟
磁盘使用率数据盘> 85%
网络流入/流出网络流量> 带宽 80%
连接数数据库/Redis 连接> 连接池 80%

[Standard] 核心业务流程必须埋点上报业务指标:

业务指标
电商下单量、支付成功率、退款率
内容DAU、停留时长、点击率
通用注册量、登录成功率、消息发送量

[Suggestion] 业务关键流程可自定义指标,如队列积压量、缓存命中率、重试次数等。

[Standard] 指标命名遵循 namespace_subsystem_name_unit 格式,使用 snake_case。

# 示例
http_requests_total # 请求总数
http_request_duration_seconds # 请求耗时(秒)
db_connections_active # 活跃数据库连接数
cache_hit_ratio # 缓存命中率
business_order_created_total # 订单创建总数

[Standard] 服务通过 /metrics 端点暴露 Prometheus 格式指标。

# FastAPI + prometheus_client 示例
from prometheus_client import Counter, Histogram, generate_latest
 
REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint', 'status'])
REQUEST_DURATION = Histogram('http_request_duration_seconds', 'HTTP request duration', ['endpoint'])
 
@app.middleware("http")
async def metrics_middleware(request, call_next):
    start = time.time()
    response = await call_next(request)
    duration = time.time() - start
    REQUEST_COUNT.labels(request.method, request.url.path, response.status_code).inc()
    REQUEST_DURATION.labels(request.url.path).observe(duration)
    return response
 
@app.get("/metrics")
async def metrics():
    return Response(generate_latest(), media_type="text/plain")

[Caution] 指标标签(label)的取值集合必须有限,禁止使用用户 ID、订单 ID 等高基数值作为 label,否则会导致指标爆炸。

# 正确:label 取值有限
REQUEST_COUNT.labels(method="GET", endpoint="/users", status="200").inc()
 
# 错误:user_id 是高基数 label
REQUEST_COUNT.labels(user_id="12345").inc()

[Requirement] 全链路必须传播 trace_id,支持跨服务追踪。使用 W3C Trace Context 标准。

[Standard] 入口服务生成 trace_id,通过 HTTP Header traceparent 向下游传递。

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
│ └──────────── trace_id ────────────┘ └── span_id ──┘ │
└─ version └─ flags

[Requirement] 以下操作必须创建 Span:

操作类型说明
入站 HTTP 请求创建根 Span
出站 HTTP/RPC 调用创建子 Span
数据库操作创建子 Span,包含 SQL 摘要
缓存操作创建子 Span
消息队列生产/消费创建子 Span

[Standard] 生产环境使用概率采样,默认采样率 10%,错误请求 100% 采样。

场景采样率
正常请求10%
错误请求100%
慢请求(>1s)100%
压测环境100%

[Standard] 使用 Jaeger / Zipkin / SkyWalking 作为追踪后端,UI 支持按 trace_id 查询完整调用链。

[Standard] Span 名称格式:<HTTP方法> <路由> 或 <服务名>.<方法名>。

# HTTP 入站
GET /api/users/{id}
# RPC 调用
order-service.createOrder
# 数据库
SELECT FROM users WHERE id = ?

[Requirement] 告警分为三级,不同级别通知方式和响应时间不同:

级别名称通知方式响应时间示例
P0紧急电话 + 短信 + IM立即响应(5 分钟内)服务不可用、核心接口错误率 > 5%
P1重要短信 + IM15 分钟内响应错误率 1-5%、响应时间劣化
P2一般IM1 小时内响应磁盘使用率 > 85%、单实例异常

[Requirement] 每个服务必须配置以下告警规则:

告警项条件级别
服务不可用健康检查失败 ≥ 1 分钟P0
错误率5xx 错误率 > 1% 持续 3 分钟P0
响应时间P99 > 2s 持续 5 分钟P1
CPU 使用率> 90% 持续 5 分钟P1
内存使用率> 90% 持续 5 分钟P1
磁盘使用率> 85%P2
实例重启Pod 重启 ≥ 3 次/10 分钟P1

Prometheus AlertManager 规则:

groups:
  - name: service-alerts
    rules:
      - alert: HighErrorRate
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m]))
          / sum(rate(http_requests_total[5m])) > 0.01
        for: 3m
        labels:
          severity: P0
        annotations:
          summary: "服务 {{ $labels.service }} 错误率过高"
          description: "错误率 {{ $value | humanizePercentage }},持续 3 分钟"
 
      - alert: HighLatency
        expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 2
        for: 5m
        labels:
          severity: P1
        annotations:
          summary: "服务 {{ $labels.service }} 响应缓慢"
          description: "P99 响应时间 {{ $value }}s"

[Standard] 配置告警抑制规则,避免告警风暴:

  • 父告警触发时,抑制子告警(如服务不可用时抑制该服务的所有子告警)
  • 同类告警在 5 分钟内只通知一次
  • 维护期间自动静默告警
  • ❌ 告警阈值设得过低,导致告警疲劳,真正的告警被忽略。
  • ❌ 所有告警都发到同一个群,无法区分紧急程度。
  • ❌ 告警只发邮件,无人及时查看。

[Standard] Dashboard 分为三层,面向不同角色:

层级受众内容
全局总览管理层、值班所有服务健康状态、核心业务指标
服务视图研发、运维单个服务的 RED 指标、资源指标、依赖状态
实例视图运维单个实例的 CPU、内存、网络、日志

[Requirement] 必须包含以下面板:

  • 所有服务健康状态(红/黄/绿)
  • 全局 QPS、错误率、P99 响应时间
  • 核心业务指标(订单量、支付成功率等)
  • 正在触发的告警列表

[Standard] 每个服务必须有独立 Dashboard,包含:

面板组指标
请求量QPS(按接口、按状态码)
错误率5xx 占比、4xx 占比
响应时间P50/P95/P99 延迟分布
资源使用CPU、内存、磁盘、网络
依赖状态数据库连接池、Redis、下游服务
JVM/运行时线程数、GC 次数、堆内存(Java)

[Standard] Dashboard 设计遵循以下原则:

  1. 一屏可见:核心指标在一屏内展示,无需滚动
  2. 时间对齐:同一 Dashboard 所有面板使用相同时间范围
  3. 阈值标线:关键指标面板标注告警阈值线
  4. 颜色编码:正常绿色、警告黄色、异常红色
  5. 可下钻:点击异常指标可跳转到日志或追踪详情
  • ❌ Dashboard 放满几十个面板,关键指标被淹没。
  • ❌ 不同面板时间范围不一致,无法关联分析。
  • ❌ 只有技术指标,没有业务指标,无法判断业务影响。