# 运行指标与告警接入 状态: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。每次HTTP采集只访问进程内存,不查询业务表;DB池快照在启动时及之后每5秒读取 `database/sql.DBStats`,该调用不执行SQL。指标启用后同一个5秒后台采样器另外执行一次有界业务快照:查询固定状态、固定表和固定索引,单状态或事件类别最多读取10000条;固定事件类别窗口为最近5分钟;数据库调用使用900ms截止时间;失败只增加错误/超时计数并保留上次成功值,不改变业务事务。 所有指标名称、类型、标签名和取值在代码目录中固定。未知名称、错误类型、非法标签、非有限数值和计数器倒退会被丢弃,并增加 `orbit_observability_rejected_samples_total`。新增指标需要修改目录和回归,不允许业务方动态注册标签。HTTP标签为8种方法、12种路由分类和6种状态分类,两组HTTP族各最多576种标签组合。禁止将任务/流程/租户ID、业务键、URL、参数、原始错误或凭据写入指标。Worker/Event连接上限、Hub领取协程数和内存排队槽位也以固定基数导出,便于核对节点实际生效的背压边界。 格式化输出前只短暂复制注册器引用;不在全局记录锁下排序、格式化或写网络。直方图的桶、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_runtime_tick_interval_seconds{component}` | gauge | 节点实际生效的后台扫描间隔,component为workflow、schedule、execution_recovery | | `orbit_runtime_batch_limit` | gauge | 节点实际生效的后台批量上限 | | `orbit_shutdown_timeout_seconds` | gauge | 节点实际生效的排空与优雅关闭窗口(秒) | | `orbit_worker_connection_limit` | gauge | 节点实际生效的 Worker WebSocket 连接上限 | | `orbit_event_connection_limit` | gauge | 节点实际生效的 Event WebSocket 连接上限 | | `orbit_dispatch_workers` | gauge | 每个 WebSocket Hub 同时执行数据库领取调用的协程上限 | | `orbit_dispatch_capacity` | gauge | 每个 WebSocket Hub 领取调用的有界内存排队槽位 | | `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_db_transaction_retries_total` | counter | 本进程提交前因 MySQL 1205/1213 实际执行的事务重试次数;不包含 Begin/Commit 错误或提交回执不明 | | `orbit_db_transaction_retry_exhausted_total` | counter | 本进程提交前因 MySQL 1205/1213 达到最多两次重试上限的事务次数;需要结合原操作身份和数据库锁观测核查 | | `orbit_pulse_tasks_state{state}` | gauge | Pulse任务固定状态的有界计数;单状态达到10000时只保留上限并置截断标记 | | `orbit_pulse_tasks_oldest_age_seconds` | gauge | WAITING/LEASED/RUNNING/NEEDS_REVIEW样本中最早可处理时间的年龄 | | `orbit_result_deliveries_state{state}` | gauge | 结果交付固定状态的有界计数 | | `orbit_result_delivery_oldest_age_seconds` | gauge | PENDING/LEASED交付样本中最早可处理时间的年龄 | | `orbit_weave_workflows_state{state}` | gauge | Weave实例固定状态的有界计数 | | `orbit_weave_workflow_oldest_age_seconds` | gauge | RUNNING/WAITING/CANCELLING/NEEDS_REVIEW实例样本中最早更新时间的年龄 | | `orbit_weave_inbox_state{state}` | gauge | Weave内部Inbox固定状态的有界计数,状态为PENDING、LEASED、PROCESSED、QUARANTINED | | `orbit_weave_inbox_oldest_age_seconds` | gauge | PENDING/LEASED Inbox样本中最早可处理时间的年龄 | | `orbit_business_events_recent{event}` | gauge | 最近5分钟内固定事件类别的有界数量,用于观察受理、完成、核查、恢复和流程推进趋势 | | `orbit_pulse_task_terminal_latency_seconds` / `_max_seconds` | gauge | 最近5分钟终态任务从创建到完成的平均/最大耗时样本,单位秒 | | `orbit_weave_workflow_terminal_latency_seconds` / `_max_seconds` | gauge | 最近5分钟终态流程从创建到完成的平均/最大耗时样本,单位秒 | | `orbit_pulse_task_accept_to_start_latency_seconds` / `_max_seconds` | gauge | 最近5分钟同时采到 `task.accepted` 与 `task.started` 的任务受理到开始平均/最大耗时样本,单位秒 | | `orbit_pulse_task_accept_to_terminal_latency_seconds` / `_max_seconds` | gauge | 最近5分钟同时采到任务受理与确定终态事件的平均/最大耗时样本,单位秒 | | `orbit_weave_workflow_start_to_terminal_latency_seconds` / `_max_seconds` | gauge | 最近5分钟同时采到 `workflow.started` 与 `workflow.stopped` 的流程开始到停止平均/最大耗时样本,单位秒 | | `orbit_business_snapshot_total{outcome}` | counter | 有界业务快照成功、错误或超时次数 | | `orbit_business_snapshot_duration_seconds` | histogram | 有界业务快照耗时;包含数据库读取 | | `orbit_business_snapshot_last_success_timestamp_seconds` | gauge | 最近一次完整成功快照的Unix时间;失败不会推进 | | `orbit_business_snapshot_truncated` | gauge | 任一固定状态达到10000上限时为1,否则为0 | | `orbit_process_start_time_seconds` / `orbit_process_uptime_seconds` | gauge | 本次指标注册器初始化Unix时间/单调时钟经过的秒数;初始化发生在数据库启动校验之后 | | `orbit_process_draining` | gauge | 节点是否正在优雅排空;0为服务中,1为排空中 | | `orbit_go_goroutines` | gauge | Go协程数,按5秒采样 | | `orbit_build_info{go_version,version,revision}` | gauge | 恒为1,导出当前Go版本、发布版本和源码提交;构建时间及完整协议身份通过 `/version` 获取 | | `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分钟:查日志和原任务/流程审计,不把数据库故障改判成业务失败。 - 有界业务快照连续没有成功超过30秒(启动宽限60秒):检查采样超时/错误和MySQL健康;已有状态值可能已经陈旧。 - 固定状态采样连续达到10000条上限5分钟:状态指标只是有限样本,转用权威数据库查询并进行容量核查。 - 池累计等待时间增长超过0.1秒/秒并持续5分钟:联查锁等待、慢SQL、CPU和存储,不自动提高连接数。 - 提交前 MySQL 事务重试达到有界上限:检查锁等待、死锁和原操作身份,不按告警盲目重放;提交回执不明不计入此规则。 - 内部非法指标更新持续出现:检查观测代码契约,不能忽略丢弃的样本。 这些阈值是可修改的运行基线,尚未通过生产负载调优;不构成SLO或可用性承诺。规则测试覆盖触发、启动宽限、健康不报警和错误停止后的解除,未发送实际通知或创建外部监控服务。 ```sh promtool check rules deploy/monitoring/orbit.rules.yml promtool test rules deploy/monitoring/orbit.rules.test.yml ``` HTTP失败率和延迟可按route/status_class统计;受理接口响应成功与已完成业务应分别判断。业务状态、事件窗口、Inbox状态和终结耗时指标是本节点有限样本,不能相加作为全局精确数量;未知事件类型不会进入标签,终结耗时从持久化`created_at`到`completed_at`计算,不包含端到端外部副作用,Inbox年龄从`available_at`计算,不等于流程推进完成延迟。应结合 `orbit_business_snapshot_last_success_timestamp_seconds` 和 `orbit_business_snapshot_truncated` 判断新鲜度与完整性。可靠结果量、授权阶段延迟、全局发送队列、磁盘/复制等仍须补充专门指标;具体当前证据见[进程观测报告](../reports/phase-6-observability.md)和[有界业务采样报告](../reports/phase-6-business-observability.md)。