feat: add bounded process metrics and private monitoring endpoint

This commit is contained in:
2026-09-18 13:17:33 +08:00
parent 1f1d833f69
commit a7be32f661
24 changed files with 1467 additions and 19 deletions

View File

@@ -30,7 +30,7 @@
| P3 Pulse 完整能力 | 安全重试、延时、Cron/固定间隔、漏跑策略、计划版本、运行中取消、并发许可、配额/背压、可靠结果订阅、批量受理、独立任务核查/人工重试、查询筛选与事务Outbox接入 | 多实例领取/触发竞争、重试上限、取消竞争、队列隔离、积压恢复、事件重复交付 | 已完成平台功能阶段验收:[原范围逐项核对](reports/phase-3.md)、[本轮完整回归](reports/phase-3-delay-recovery.md)。补齐相对延迟、改参数关联示例和四种重试全停恢复场景;20个可运行示例全部通过。全平台生产门槛及SDK首版交付剩余项仍按P6–P7推进 |
| P4 Weave 主流程 | SDK 定义构建与发布校验、实例、顺序/分支/结构化并行汇合、信号/定时等待、版本绑定 | 重启接续、早到/重复信号、并行竞争、内部事件重放、发布版本兼容;端到端通用流程 | 已完成平台功能阶段验收:[原功能及W01–W17逐项核对](reports/phase-4-5.md)、[版本/暂停/全停回归](reports/phase-4-5-races.md)、[提交故障边界](reports/phase-6-fault-boundaries.md)。研发发布、固定版本、顺序/分支/有限并行、信号/时间等待、公共API/SDK及可运行示例均已交付;生产拓扑与发布兼容继续P6/P7 |
| P5 Weave 恢复与查询 | 有界查询、暂停继续、取消、人工核查恢复、控制门控与审计 | 轮次与尝试独立预算;暂停/开始/回执/超时竞争;恢复保留预算;未知结果不盲目重复 | 已完成平台功能阶段验收:[原功能核对](reports/phase-4-5.md)。有界查询、独立预算、暂停继续/取消、六类恢复、历史/筛选/事件/来源与SDK场景均已交付;真实竞争、COMMIT断线及进程全停保留原身份、截止和预算。运维、容量与首版发布继续P6/P7 |
| P6 生产验证与运维 | 完整监控、凭据轮换、备份恢复、滚动升级、运行手册、可复现负载和故障工具 | 对照生产验收清单执行,报告环境/指标/遗留项;容量、RPO/RTO 按真实拓扑验证 | 进行中;已补[首批精确故障边界](reports/phase-6-fault-boundaries.md),继续运行观测、凭据轮换及其余生产门槛 |
| P6 生产验证与运维 | 完整监控、凭据轮换、备份恢复、滚动升级、运行手册、可复现负载和故障工具 | 对照生产验收清单执行,报告环境/指标/遗留项;容量、RPO/RTO 按真实拓扑验证 | 进行中;已补[精确故障边界](reports/phase-6-fault-boundaries.md)和[进程观测](reports/phase-6-observability.md);继续业务积压/阶段延迟、凭据轮换及其余生产门槛 |
| P7 首版交付核对 | SDK 兼容与发布准备、完整 API 手册、场景示例、全量回归及交付清单 | 新接入者按文档跑通全部示例;所有首版能力可追溯到实现与测试;报告实际生产边界 | 待开发 |
SDK、文档与示例随 P1–P5 同步开发,P7 是全量核对,不是最后才开始补文档。
@@ -59,7 +59,7 @@ P4/P5定时等待与后续查询轮次的实现及回归记录见[时钟报告](
### P6 首批实施顺序
1. 已补[首批可复现故障工具](reports/phase-6-fault-boundaries.md):A04“派发已提交但消息尚未送达”、W01/W13事务提交结果不明,以及W16最终回执/旧PENDING结果重放/下一轮竞争。每个切点必须有实际数据库或进程证据,不能用响应错误推断事务是否已提交,也不能用普通SIGNAL竞争替代最终查询场景。
2. 实现运行观测:受理/授权/完成及流程推进延迟、重试/核查/恢复、待处理与到期积压、连接/发送队列和数据库连接池。明确采集范围与开销;任务、流程、业务键和凭据不得作为无界指标标签。
2. 已实现[基础运行观测](api/observability.md):HTTP/WS、数据库连接池、后台批次和进程指标,以及可离线验证的告警规则;独立采集监听默认关闭,固定指标目录拒绝动态标签。仍需受理/授权/完成阶段延迟与持久吞吐、流程推进延迟、重试/核查/恢复量、待处理与到期积压、发送队列及生产采集/通知验证。
3. 补齐凭据签发、轮换、撤销及Worker/订阅安全重绑,保持最小权限、管理审计与未知回执可恢复。
4. 实现保留/归档与受保护记录核对,再执行备份恢复、兼容升级和六类容量负载。未确认交付、有效幂等身份、当前/历史执行证据和未终结流程不能被普通清理破坏。生产HA及RPO/RTO继续按实际拓扑验证,不缩减为本机多进程检查。

View File

@@ -2,7 +2,7 @@
- 文档版本:0.2
- 整理日期:2026-09-17
- 阶段:P0–P3平台功能已通过阶段回归;[P3逐项验收](reports/phase-3.md)保留原范围与证据边界。[相对延迟及重试全停恢复](reports/phase-3-delay-recovery.md)已通过完整回归。继续P4–P7,尚未完成全平台生产验收,数据库保持无外键。
- 阶段:P0–P5平台功能已通过阶段回归;[P4/P5原范围核对](reports/phase-4-5.md)和[首批故障边界](reports/phase-6-fault-boundaries.md)保留证据边界。P6生产观测与运维、P7首版交付继续推进,尚未完成全平台生产验收,数据库保持无外键。
- 适用范围:Orbit 统一平台,包含 Pulse 任务调度模块、Weave 流程编排模块与公共能力。平台面向多个业务系统复用。
## 阅读顺序
@@ -39,6 +39,7 @@
| 数据库关联 | 禁止外键及级联删除,关联存在性与归属由服务端事务验证;保留必要索引、唯一约束和 CHECK |
| 通信方向 | HTTP + WebSocket;生产使用 HTTPS / WSS |
| HTTP 职责 | 任务提交、流程启动与信号、查询、计划管理、配置与管理操作 |
| 运行观测 | 独立监听的`/metrics`提供无业务标识的固定基数运行指标;默认关闭,生产访问需内部网络控制 |
| WS 职责 | Worker 接入、能力与容量上报、任务派发、续租、结果上报、取消通知 |
| 执行位置 | 业务处理器位于业务项目自己的 Worker 中 |
| 外部依赖范围 | 首版以 MySQL 为必需的外部存储依赖;运行不要求 Redis、独立消息队列或独立协调服务 |

View File

@@ -8,6 +8,7 @@
| --- | --- | --- |
| `GET /health/live` | 已实现 | [健康检查](health.md) |
| `GET /health/ready` | 已实现,验证数据库、迁移记录及零外键要求 | [健康检查](health.md) |
| 独立监听的 `GET /metrics` | 已实现基础运行指标,默认关闭 | [运行观测](observability.md) |
| `/v1/tasks` 提交、查询、分页与待执行取消 | 已实现,P3扩展业务键与创建时间筛选 | [任务接口](tasks.md) / [查询契约](task-queries.md) |
| `GET /v1/tasks/{task_id}/source` | 已实现普通、人工重试、计划固定版本及流程历史激活/轮次来源 | [来源查询](task-source.md) |
| `POST /v1/tasks:batch` | P3 已实现逐项受理、独立幂等、部分结果与补交 | [批量任务](batch-tasks.md) |

View File

@@ -42,4 +42,4 @@ curl -i http://127.0.0.1:8080/health/ready
对应 `Client.Liveness(ctx)` 和 `Client.Readiness(ctx)`,见 [SDK 接入](../sdk/README.md)。HTTP 503 返回 `*orbit.HTTPError`。
ready 只表示数据库与迁移基础可用;不检查 Worker、任务积压、流程执行或业务效果。P1 启动时先校验迁移,缺失或 dirty 会拒绝启动;运行后数据库不可用时 ready 返回 503。SDK 默认请求超时为 10 秒,调用方可通过 context 设置更短期限。
ready 只表示数据库与迁移基础可用;不检查 Worker、任务积压、流程执行或业务效果。P1 启动时先校验迁移,缺失或 dirty 会拒绝启动;运行后数据库不可用时 ready 返回 503。SDK 默认请求超时为 10 秒,调用方可通过 context 设置更短期限。运行指标见[观测接口](observability.md),指标端点是否启用由 `ORBIT_METRICS_ADDR` 控制。

91
docs/api/observability.md Normal file
View File

@@ -0,0 +1,91 @@
# 运行指标与告警接入
状态:P6第一批进程观测已实现,指标、采集入口和下方规则均有回归。任务/流程的持久积压和业务阶段延迟仍待补齐;完整生产观测尚未验收。
## 1. 启用独立采集端口
默认不启动指标监听,也不创建指标注册器。显式配置后,业务端口与采集端口分别监听:
```sh
export ORBIT_HTTP_ADDR=127.0.0.1:8080
export ORBIT_METRICS_ADDR=127.0.0.1:9090
# 数据库凭据按现有秘密配置注入;先完成迁移。
go run ./cmd/orbit
```
```sh
curl -fsS http://127.0.0.1:9090/metrics
```
`ORBIT_METRICS_ADDR` 为空或未设置即关闭,`127.0.0.1:0` 可用于测试时分配空闲端口。非法地址、端口超界或绑定失败会拒绝启动;绑定失败不能静默降级为“看起来已经监控”。进程日志用 `metrics_address` 报告实际采集地址。业务端口 `/metrics` 返回404;指标端口不注册业务或健康接口。
指标监听不使用业务凭据,没有多租户查询接口;只面向平台运维人员。部署到远程采集网络时,显式选择内部地址并配置网络策略或带鉴权/TLS的内部代理,不将此端口发布到公网。SDK不封装该端点;业务读取、核查和审计仍使用原有鉴权API。
## 2. HTTP契约和数据范围
仅 `GET /metrics`(及标准HEAD)提供采集,查询参数返回400。正文使用[Prometheus文本格式0.0.4](https://prometheus.io/docs/instrumenting/exposition_formats/),Content-Type为 `text/plain; version=0.0.4; charset=utf-8`,Cache-Control为no-store。输出是本节点的运行快照,没有跨节点或跨指标原子快照保证。
每节点同时最多2个采集请求,超出返回503及 `Retry-After: 1`,不排无限等待队列。独立HTTP服务器的读头/读/写/空闲超时分别为2/3/5/15秒,头部限制8 KiB。采集只访问进程内存,不查询业务表;DB池快照在启动时及之后每5秒读取 `database/sql.DBStats`,该调用不执行SQL。
所有指标名称、类型、标签名和取值在代码目录中固定。未知名称、错误类型、非法标签、非有限数值和计数器倒退会被丢弃,并增加 `orbit_observability_rejected_samples_total`。新增指标需要修改目录和回归,不允许业务方动态注册标签。HTTP标签为8种方法、12种路由分类和6种状态分类,两组HTTP族各最多576种标签组合。禁止将任务/流程/租户ID、业务键、URL、参数、原始错误或凭据写入指标。
格式化输出前只短暂复制注册器引用;不在全局记录锁下排序、格式化或写网络。直方图的桶、count、sum在同一局部锁下获取,保持单条直方图快照一致。指标在重启后重置,不能用于账务审计、幂等判断或恢复授权。
## 3. 指标目录
| 名称 | 类型 | 口径 |
| --- | --- | --- |
| `orbit_http_requests_total` | counter | HTTP响应完成次数;成功WS握手在Hijack完成时计入 |
| `orbit_http_request_duration_seconds` | histogram | HTTP处理/升级握手耗时,不包含成功升级后的连接存续时间 |
| `orbit_http_requests_in_flight` | gauge | 尚未返回或成功升级的HTTP处理器数量 |
| `orbit_http_panics_total` | counter | 非正常返回的HTTP处理器次数;无响应时按5xx观测分类,但不声称客户端收到500;保留原panic传播及已发响应 |
| `orbit_websocket_connections` | gauge | 成功升级且处理器尚未退出的WS连接,按worker_connect/event_connect区分 |
| `orbit_websocket_connections_total` | counter | WS成功升级累计次数;并不表示协议hello、业务鉴权或任务执行成功 |
| `orbit_runtime_batch_total` | counter | 后台批次返回次数,标签component及outcome |
| `orbit_runtime_batch_duration_seconds` | histogram | 后台批次调用耗时,标签component |
| `orbit_runtime_batch_last_success_timestamp_seconds` | gauge | 最后一次无错误批次返回的Unix时间;启动后未成功时为0 |
| `orbit_db_connections_open` / `orbit_db_connections_in_use` / `orbit_db_connections_idle` | gauge | 本节点MySQL连接池当前连接数 |
| `orbit_db_connections_max_open` | gauge | 池配置的最大连接数 |
| `orbit_db_wait_count_total` / `orbit_db_wait_duration_seconds_total` | counter | 连接池累计等待次数/秒数,不是数据库锁等待 |
| `orbit_process_start_time_seconds` / `orbit_process_uptime_seconds` | gauge | 本次指标注册器初始化Unix时间/单调时钟经过的秒数;初始化发生在数据库启动校验之后 |
| `orbit_go_goroutines` | gauge | Go协程数,按5秒采样 |
| `orbit_build_info` | gauge | 恒为1,go_version仅取当前编译运行时版本;不是Orbit发布版本 |
| `orbit_observability_rejected_samples_total` | counter | 内部不合法指标更新次数,正常运行应为0 |
HTTP方法为GET/POST/PATCH/PUT/DELETE/HEAD/OPTIONS/OTHER;路由为health_live、health_ready、worker_connect、event_connect、tasks、queues、workflows、workflow_definitions、schedules、subscriptions、application_resources、other;状态为1xx–5xx及other。路径值不会进入标签;分类不表示路由存在或授权通过。独立采集请求不混入业务HTTP计数。
后台component为workflow、schedule、execution_recovery;outcome为success、error、cancelled。context.Canceled归cancelled,超时与其他错误归error,错误文本不导出。success只说明一批调用无错误返回,允许空批次;不能将它解释为持久任务成功量。已提交但确认不明的状态仍须按原身份核对。
直方图有限桶边界固定为0.005、0.01、0.025、0.05、0.1、0.25、0.5、1、2.5、5、10秒,另有+Inf桶和sum/count。不得将高于10秒的有限分位估计当作精确延迟,后续容量验证需结合样本及合适的桶配置。
## 4. 采集与告警例子
如果已有兼容采集器,可配置job名为orbit(规则按此名筛选):
```yaml
scrape_configs:
- job_name: orbit
scrape_interval: 15s
scrape_timeout: 3s
static_configs:
- targets: ["127.0.0.1:9090"]
```
示例地址仅适用于同机采集;远程采集需替换为受保护的内部目标。平台运行不依赖采集器、Prometheus或额外数据库。
[五条告警规则](../../deploy/monitoring/orbit.rules.yml)和[离线规则测试](../../deploy/monitoring/orbit.rules.test.yml)包含以下场景:
- 目标连续2分钟采集失败:检查指标监听、网络和进程,不直接判断业务任务停止。
- 启动60秒后,某后台组件超过30秒没有成功批次并持续1分钟:结合readiness、批次错误和数据库状态调查。
- 批次错误速率持续为正2分钟:查日志和原任务/流程审计,不把数据库故障改判成业务失败。
- 池累计等待时间增长超过0.1秒/秒并持续5分钟:联查锁等待、慢SQL、CPU和存储,不自动提高连接数。
- 内部非法指标更新持续出现:检查观测代码契约,不能忽略丢弃的样本。
这些阈值是可修改的运行基线,尚未通过生产负载调优;不构成SLO或可用性承诺。规则测试覆盖触发、启动宽限、健康不报警和错误停止后的解除,未发送实际通知或创建外部监控服务。
```sh
promtool check rules deploy/monitoring/orbit.rules.yml
promtool test rules deploy/monitoring/orbit.rules.test.yml
```
HTTP失败率和延迟可按route/status_class统计;受理接口响应成功与已完成业务应分别判断。可靠结果量、排队/授权/完成延迟、流程Inbox积压、发送队列、磁盘/复制等仍须补充专门指标;具体当前证据见[验证报告](../reports/phase-6-observability.md)。

View File

@@ -0,0 +1,83 @@
# P6:进程指标、采集隔离与告警规则
日期:2026-09-18。范围为运行观测第一批,交付HTTP/WS、连接池、后台批次、进程指标和可离线验证的告警规则。P6仍在进行,任务/流程持久积压和阶段延迟没有被本批替代。
## 实现和边界
- [指标目录与注册器](../../internal/observability/metrics.go)只接受[代码中固定的名称、类型及标签集合](../../internal/observability/catalog.go)。没有通用动态注册接口;非法更新丢弃并计数,未知指标不创建族,同名不同类型不会触发空指针或混写。
- [HTTP包装器](../../internal/observability/http.go)保留原始状态、流式写入、Hijack及panic传播。成功WS升级在握手完成时计一次HTTP,连接存续单独计数;普通HTTP延迟不包含长连接生命期。103等临时响应不阻止最终响应。
- [运行采样](../../internal/observability/runtime.go)读取本进程池状态,不在采集路径执行SQL;批次开始/返回时间只观测原调用,不改变事务、重试或状态语义。计数器初始零值和最后成功时间支持“尚未成功”和“随后停滞”的判断。
- [进程入口](../../cmd/orbit/main.go)使用独立指标监听,默认关闭;启用后业务端口仍无`/metrics`,采集端口不提供业务API。服务启动、绑定失败和SIGTERM退出明确处理两种监听。
- [接口及运维手册](../api/observability.md)说明所有名称、单位、标签、采样间隔、超时、限流和剩余范围。[告警规则](../../deploy/monitoring/orbit.rules.yml)是可修改的起始阈值,未对接或发送实际外部通知。
模型仍为36个、直接持久化字段312个、迁移版本25;未改模型/迁移、没有外键或级联。没有新增Go模块依赖、SDK耦合或运行必需服务。官方promtool仅作为一次性离线验证器。
## 针对性证据
[指标竞态与约束回归](../../internal/observability/metrics_test.go)覆盖16个并发写入者及同时采集;每条直方图的桶/count/sum保持一致。3000个动态名称和3000个动态标签均被拒绝;每种HTTP方法/路由/状态组合都写入后,原序列仍继续累计。类型冲突、计数器倒退、非有限数字和错误文本泄露均有直接断言。
[真实TLS WebSocket回归](../../internal/observability/http_test.go)通过现有coder/websocket实际升级,保持连接未关闭时确认HTTP计数完成、HTTP在途为0、WS在途为1;关闭后WS归0且HTTP不重计。另有真实HTTP 103→201及Flush完整响应检查。
[进程专项](../../cmd/orbit/metrics_integration_test.go)使用一次性MySQL和编译为race模式的Orbit二进制:分别启用/关闭指标,验证readiness、业务请求、独立采集、DB池及自然运行的后台批次、请求数据不泄露,最后SIGTERM并确认监听全部关闭。分配优化后的定向入口退出0,5.696秒;这是测试耗时,不是延迟指标。
最终`make fmt test vet build`退出0。未配置外部测试环境时的普通go test会跳过MySQL/进程场景,不能用这些跳过项代替专项与标准集成执行。
## 独立格式与规则验证
全量有限HTTP组合的文本夹具为926666字节,使用本地已有官方promtool 3.5.0(linux/arm64,revision 8be3a9560fbdd18a94dedec4b747c35178177202)执行`check metrics`,退出0且无格式/命名告警。固定验证镜像摘要为`prom/prometheus@sha256:63805ebb8d2b3920190daf1cb14a60871b16fd38bed42b857a3182bc621f4996`,运行时关闭网络;此版本仅描述实际验证器,不是生产部署版本建议。
五条告警规则通过`check rules`;[规则测试](../../deploy/monitoring/orbit.rules.test.yml)通过`test rules`,验证目标失联、启动宽限、组件停滞、健康不报警、错误/等待/非法采样触发及恢复后的解除。
```sh
# 不要求平台在运行,可导出有限指标组合供独立校验。
ORBIT_TEST_METRICS_OUTPUT=/tmp/orbit-metrics.txt go test -count=1 -run '^TestExportExpositionFixture$' ./internal/observability
promtool check metrics < /tmp/orbit-metrics.txt
promtool check rules deploy/monitoring/orbit.rules.yml
promtool test rules deploy/monitoring/orbit.rules.test.yml
```
格式契约以[官方文本说明](https://prometheus.io/docs/instrumenting/exposition_formats/)为依据,框架自身不要求部署Prometheus。
## 全量回归与开销记录
标准`make integration`对应的`GO=… DOCKER=… sh scripts/test-mysql.sh`执行完毕,退出0。标准脚本显式为测试子进程分配独立随机指标端口,让真实SDK/WSS及进程恢复链路在指标启用时执行;进程专项另验证默认关闭场景。环境为Go 1.27.1、darwin/arm64、Docker MySQL 8.4.10。
| 范围 | 本次终态及耗时 |
| --- | --- |
| 存储、升级、事务竞争和COMMIT切点 | PASS,280.152秒 |
| 指标独立监听开/关与退出 | PASS,4.620秒 |
| 流程运行器真实节点恢复 | PASS,48.262秒 |
| SDK任务/Worker、调度、队列、批量、查询、订阅/消费、恢复和流程接口 | 各组PASS;23个SDK示例均运行成功 |
| 独立业务Inbox / Outbox模块及demo | PASS,36.005 / 34.409秒;demo成功 |
| Worker / 事件消费进程故障组 | PASS,127.765秒;包含A04未送达派发、自然租约到期、ACK丢确认和四种重试全停恢复 |
| 公共SDK流程暂停全停恢复 | PASS,13.789秒;两旧节点全部退出后由两新节点接续 |
无外键升级专项再次确认:v7的70条历史外键全部移除,323项原索引组成不变,原任务保留,启动检查拒绝外键漂移。当前schema版本25;业务Inbox和Outbox库也保持零外键。早期迁移文件保留原校验和,通过000008前向移除,禁止将历史DDL误解为当前运行结构。
全量执行结束后的微基准发现标签转义器重复分配,随后唯一生产代码调整是复用一个并发安全的`strings.Replacer`,转义规则不变。该调整后重新通过`make fmt test vet build`,并重新导出完整指标夹具校验格式;真实race二进制的监听/采集/退出专项复验通过,退出0、5.696秒。上表为该分配优化之前的全量结果,不将它写成优化后的重复全量执行。
可复现中间件微基准:
```sh
go test -run '^$' -bench '^BenchmarkHTTPMiddleware$' -benchmem -benchtime=1s -count=3 -cpu=1,8 ./internal/observability
```
Apple M2 Max、12核、32 GiB;全量集成停止后单独运行,退出0。空204处理器复用请求和响应对象,使用`RunParallel`,下表为三次测量范围。
| 指标启用 | GOMAXPROCS | ns/op | B/op | allocs/op |
| --- | --- | --- | --- | --- |
| 否 | 1 | 1.997–2.122 | 0 | 0 |
| 否 | 8 | 0.2581–0.2747 | 0 | 0 |
| 是 | 1 | 1090–1126 | 704 | 19 |
| 是 | 8 | 1404–1482 | 704 | 19 |
优化前启用时为41272 B/op、61 allocs/op;共享转义器消除了每次构建查找表的分配。并行ns/op是总工作量的摊销值,不是单请求延迟;启用后的锁竞争仍需结合真实负载检查。这只是中间件本机开销,不包含网络、MySQL、并发抓取或业务处理,不能换算成受理吞吐或百万企业容量。
文档检查通过:1204个本地链接、68段JSON示例,未发现失效链接、非法JSON或接入方项目标识;`git diff --check`通过。
## 后续原范围
1. 受理/授权/完成的持久吞吐、阶段延迟、重试/核查/恢复量、流程Inbox至推进延迟;区分提交成功、回执丢失、重报和事件重放,不能把HTTP成功数直接当作业务量。
2. 持久待处理、到期积压与发送队列。使用有上限/超时的后台采样及明确的新鲜度/失败状态,不能让每次抓取扫描全库;状态指标和多节点重复采集的聚合口径须先明确。
3. 慢消费者、重连风暴、业务负载下观测开销、真实采集/通知演练,以及数据库锁/磁盘/复制指标和跨故障域验证。
4. 凭据轮换、保留/归档、备份恢复、容量六类负载和P7版本发布继续按[持续计划](../08-development-plan.md)执行。