跳到正文

参考

OpenTelemetry

go-sequent 可选的 obs 包:命令延迟、成功/失败计数、OCC 冲突与 Outbox 积压的 span/指标,以及 Provider 配置与边界。

OpenTelemetry

包:obs

obs 通过厂商中立的 OpenTelemetry API,让运维看到写路径的健康状况。它是可选的:没配置 provider 时,所有 instrument 都是空操作。

instrumentation 名称为 github.com/go-sequent/go-sequent。

作用

对账本来说,延迟和冲突都集中在 CommandService.Execute:事务、追加、以及 SyncInTxn(写事务内同步更新读模型)的 Projector。obs 暴露命令耗时、结果、OCC(用 ExpectedVersion 挡住并发写冲突)冲突,以及可选的 Outbox(事务内记待发消息,事后轮询投递)积压。库本身不绑定某一家 APM。

OpenTelemetry 数据是运行时信号,不是审计事实来源。对账与合规仍依赖事件流、hash chain(按聚合串联事件哈希,用来发现篡改)和命令记录(command.AuditOf、commands 表)。

能看到什么

  • 慢命令:按 command.type 看 sequent.command.duration_ms。
  • 成功与失败率:sequent.command.total,带 status=ok|error。
  • 热点聚合上的冲突风暴:sequent.optimistic_conflict.total。
  • Outbox 积压:sequent.outbox.depth(需提供深度函数)。

接线

obs 不是命令中间件。通过门面选项挂接,会设置 App.Obs 与 Service.Obs:

// 应用侧:先安装 TracerProvider、MeterProvider 与 exporter。
inst, err := obs.New(obs.Config{
    OutboxDepth: func(ctx context.Context) int64 {
        n, _ := ob.Depth(ctx)
        return n
    }, // 可选;为 nil 时不产生 sequent.outbox.depth
})
app := sequent.New(sequent.Config{},
    sequent.WithObs(inst),
    sequent.WithStore(store, tx),
)

也可以直接赋值 svc.Obs = inst。nil 表示不产生遥测。

Provider 由你负责

obs.New 使用全局的 otel.Tracer 与 otel.Meter。若应用没有调用 otel.SetTracerProvider 和 otel.SetMeterProvider,instrument 就是空操作,测试里也很安全。库不自带 OTLP、Prometheus 或 stdout exporter,由宿主进程安装。

Execute 如何使用它

  1. StartCommand 开始 span sequent.Execute。
  2. 运行事务与 UnitOfWork。
  3. Commit 返回 ErrOptimisticConcurrency 时,RecordConflict 增加冲突计数。
  4. RecordCommand 记录延迟与结果计数,然后结束 span。

批量 Execute 的 command.type 是第一条命令的类型加 +batch。

产出的 span 与指标

类型 名称 说明
Span sequent.Execute 属性 command.type。出错时记录错误并把状态设为 Error。
Histogram sequent.command.duration_ms command.type;单位毫秒
Counter sequent.command.total command.type、status = ok 或 error
Counter sequent.optimistic_conflict.total 无额外属性
Counter sequent.events.appended API 存在,但框架在追加时不会调用
Observable gauge sequent.outbox.depth 仅当设置了 Config.OutboxDepth

公开 API:Instruments、Config、New、StartCommand、RecordCommand、RecordConflict、RecordEvents。

它不做什么

  • 不内置 exporter,也不创建 provider。
  • 不自动埋点 HTTP 或 gRPC。
  • 没有 Projector、Workflow 或 Outbox 轮询器的 span。
  • RecordEvents 没有挂到 Repository.Commit 或 EventStore.Append 上。留给应用在自己的边界调用;不调用的话 sequent.events.appended 会一直为零。
  • 不能替代审计轨迹。

不要把密钥和个人数据放进 span 属性与日志。内置属性只包含命令类型。

如何使用这些信号

  • 对 error 率上升,以及各命令类型 sequent.command.duration_ms 的 p99 设告警。
  • sequent.optimistic_conflict.total 往上爬,往往说明有热点聚合,或故障切换后正在追赶。见 唯一键与 OCC与 故障转移。
  • sequent.outbox.depth 持续升高,说明轮询器落后或卡住了。见 Publisher。

相关

文档随 go-sequent 源码更新;若与 API 不一致,以源码为准。