可观测性体系:Metrics、日志与追踪

梳理 go-ai-scheduler 的可观测性实现,包括 Prometheus Metrics、结构化日志、分布式追踪与 Grafana 看板。

可观测性三支柱

go-ai-scheduler 在三个维度上实现了可观测性:

Metrics(指标)    ──▶  Prometheus + Grafana
Logs(日志)       ──▶  结构化 JSON 日志
Tracing(追踪)    ──▶  TraceID 贯穿全链路

Metrics

指标注册

// pkg/metrics/metrics.go
type Registry struct {
    counters   map[string]*prometheus.CounterVec
    histograms map[string]*prometheus.HistogramVec
    gauges     map[string]*prometheus.GaugeVec
}

var DefaultRegistry = NewRegistry()

核心指标

指标名类型说明
scheduler_dispatch_totalCounter任务分发次数,label: result=success/error
scheduler_trigger_totalCounter任务触发次数
scheduler_retry_totalCounter重试次数
leader_election_totalCounterLeader 选举次数,label: backend=mysql/etcd/local, result=acquired/contended
worker_heartbeat_totalCounterWorker 心跳次数
ai_tokens_totalCounterAI Service LLM Token 消耗
ai_requests_totalCounterAI Service 请求次数
dispatch_latency_msHistogram分发延迟分布
pending_instancesGauge当前 pending 实例数
worker_loadGaugeWorker 当前负载

使用示例

// 记录分发成功
metrics.DefaultRegistry.IncCounter("scheduler_dispatch_total",
    map[string]string{"result": "success"})

// 记录分发失败
metrics.DefaultRegistry.IncCounter("scheduler_dispatch_total",
    map[string]string{"result": "error"})

// 记录 Leader 选举
metrics.DefaultRegistry.IncCounter("leader_election_total",
    map[string]string{"backend": "mysql", "result": "acquired"})

Prometheus 采集

所有服务在 /metrics 路径暴露 Prometheus 格式指标:

http.Handle("/metrics", promhttp.Handler())

结构化日志

日志格式

{"ts":"2026-05-26T10:30:00Z","level":"INFO","service":"scheduler","msg":"task dispatched","task_id":123,"worker_id":"worker-1","shard":"0/1"}

字段规范

字段说明
tsISO8601 时间戳
levelDEBUG / INFO / WARN / ERROR
serviceapi / scheduler / worker / ai-service
msg日志消息
trace_id分布式追踪 ID(如有)
业务字段task_id, worker_id, instance_id

使用方式

logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelInfo,
}))

logger.Info("task dispatched",
    "task_id", task.ID,
    "worker_id", worker.ID,
    "shard", fmt.Sprintf("%d/%d", shard, shardTotal))

分布式追踪

TraceID 传递

TraceID 在任务全链路中传递:

// Scheduler 创建实例时生成 TraceID
instance.TraceID = generateTraceID()

// 通过 HTTP Header 传递给 Worker
req.Header.Set("X-Trace-ID", instance.TraceID)

// Worker 执行时携带 TraceID
logger.Info("task execution started",
    "trace_id", traceID,
    "schedule_instance_id", instanceID)

// Worker 上报结果时带回 TraceID
result.TraceID = traceID

全链路追踪

用户创建任务
    │ TraceID: abc-123
    ▼
API Service 处理请求
    │ TraceID: abc-123
    ▼
Scheduler 创建实例
    │ TraceID: abc-123
    ▼
Dispatcher 发送任务
    │ TraceID: abc-123
    ▼
Worker 执行任务
    │ TraceID: abc-123
    ▼
Worker 上报结果
    │ TraceID: abc-123
    ▼
Scheduler 更新状态
    │ TraceID: abc-123

Grafana 看板

项目内置了 Grafana Dashboard 配置(deployments/grafana/dashboard.json),包含以下面板:

Scheduler 面板

  • 分发速率:每分钟成功/失败分发次数
  • 触发速率:每分钟 Cron 触发次数
  • Pending 队列:当前 pending 实例数趋势
  • 重试队列:retry_waiting 实例数趋势
  • 分发延迟 P99:分发延迟的百分位分布

Worker 面板

  • Worker 在线状态:各 Worker 心跳状态
  • Worker 负载分布:各 Worker CurrentLoad 对比
  • 任务执行时长:各类型任务的执行耗时

AI Service 面板

  • AI 请求速率:每分钟 AI 接口调用次数
  • Token 消耗:每分钟 LLM Token 消耗量
  • AI 响应延迟:AI 接口的响应时间分布
  • 错误率:AI 接口的错误比例

告警规则建议

基于指标可以配置以下告警:

groups:
  - name: scheduler-alerts
    rules:
      - alert: HighPendingInstances
        expr: pending_instances > 800
        for: 5m
        annotations:
          summary: "Pending 实例数过高"
          description: "当前 pending 实例数 {{ $value }},接近上限 1000"

      - alert: WorkerOffline
        expr: worker_heartbeat_total{status="offline"} > 0
        for: 1m
        annotations:
          summary: "Worker 离线"

      - alert: HighFailureRate
        expr: rate(scheduler_dispatch_total{result="error"}[5m]) > 0.1
        for: 5m
        annotations:
          summary: "分发失败率过高"

      - alert: LeaderElectionFailing
        expr: rate(leader_election_total{result="contended"}[5m]) > 10
        for: 5m
        annotations:
          summary: "Leader 选举竞争激烈"

小结

可观测性体系的设计要点:

  1. Metrics 覆盖核心路径:分发、触发、重试、选举、AI 请求,全部有指标
  2. 日志结构化:JSON 格式,统一字段,便于日志系统解析和检索
  3. TraceID 贯穿全链路:从 API 到 Worker 再到 AI Service,一个 ID 追踪到底
  4. 开箱即用的 Grafana:内置 Dashboard,部署后即可查看系统状态
  5. 告警可配置:基于 Prometheus 指标,支持常见告警场景

可观测性不是"锦上添花",而是分布式系统的必需品。没有 Metrics 就不知道系统是否健康,没有日志就无法排查问题,没有 TraceID 就追踪不了跨服务调用。go-ai-scheduler 用不到 200 行 Metrics 代码 + 标准库 slog,就搭建了一套完整的可观测体系。