Files
story/docs/observability-and-api-governance.md
T

69 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 可观测性与接口治理设计
## 1. 目标与适用范围
本设计作为 API、Callbacks 与 Worker 三个进程的公共能力基线,统一请求关联、分布式追踪、指标采集、流量保护、列表分页和资源并发更新规则。领域接口不得另行定义不兼容的分页游标或版本标记。
OpenAPI是浏览器、设备和回调接口的事实来源。拉取请求以目标分支契约为基线执行破坏性变更检查;设备接口还由代码测试固定`/device/v2`主版本、禁止以`User-Agent`推测能力,并要求兼容说明与OpenAPI版本同步。设备同主版本的新增行为必须通过可选能力位协商,破坏性变化使用新主版本,具体规则见[设备API兼容性约定](device-api-compatibility.md)。
## 2. 请求关联与分布式追踪
- 每个 HTTP 请求接收或生成 `X-Request-Id`,并在响应、统一错误体和结构化日志中返回。
- `otelhttp` 在最外层创建服务端 Span,接收并传播 W3C `traceparent` 与 `baggage`。
- 访问日志记录 `request_id`、`trace_id`、`span_id`、服务、方法、匹配后的路由模板和耗时;不记录 Authorization、Cookie、录音正文或供应商密钥。
- 本地环境通过 OTLP/gRPC 发送至 OpenTelemetry Collector。Collector 当前使用调试导出器,后续环境可替换为 Tempo、Jaeger或云厂商后端,不改变业务代码。
## 3. Prometheus 指标
| 指标 | 标签 | 用途 |
|---|---|---|
| `voice_platform_http_requests_total` | service、method、route、status | 请求量与错误率 |
| `voice_platform_http_request_duration_seconds` | service、method、route | HTTP延迟分布 |
| `voice_platform_http_inflight_requests` | service | 在途请求数 |
| `voice_platform_dependency_up` | service、dependency | PostgreSQL、Redis最近一次检查状态 |
| `voice_platform_dependency_check_duration_seconds` | service、dependency | 依赖检查耗时 |
| `voice_platform_outbox_events` | status | pending、processing、dead积压 |
`/metrics`与`/health/*`不进入业务限流。Prometheus 每10秒抓取三个进程;本地入口为 `http://localhost:59190`。生产环境应限制指标端点只允许监控网络访问。
API还会按`EXTERNAL_PROBE_INTERVAL`周期验证OIDC JWKS端点可读取、JSON结构有效且至少存在一把公钥。启用方舟的API/Worker会对`ARK_BASE_URL`执行证书校验TLS握手,启用火山RTC的Worker会对`VOLC_RTC_BASE_URL`执行同类握手,启用托管内容安全的Worker会对`CONTENT_SAFETY_ENDPOINT`执行同类握手。TLS探针只做DNS、TCP和TLS协商,不发送供应商业务请求或待分类正文,因此不消耗模型Token、RTC分钟、策略调用或任务配额。
探针结果复用`voice_platform_dependency_up{service,dependency}`,其中外部标签为`oidc_jwks`、`ark_tls`、`volc_rtc_tls`和`content_safety_tls`。失败不会改变服务readiness;模型和内容安全调用本身已有降级或安全重试路径,供应商网络故障不应触发Pod重启风暴。`PlatformExternalDependencyUnavailable`只在指标连续5分钟为0后触发CRITICAL告警。运营验收快照可把四类依赖全部选为必需项,任何记录缺失、不可用或超过三倍探针周期未更新都会阻断技术门禁。
## 4. Redis令牌桶限流
- Key格式:`voice-platform:ratelimit:{scope}:{identifier_hash}`。
- 标识符使用SHA-256截断摘要,Redis中不保存原始IP、用户编号、设备编号或客户组织编号。
- Lua脚本以Redis服务器时间原子完成补充、扣减和过期时间设置,避免多实例竞态及应用服务器时钟偏差。
- HTTP入口当前先启用 `network` 范围;应用服务可复用同一组件增加 `user`、`device`、`tenant` 范围并组合更严格策略。
- 超限返回HTTP 429、错误码 `RATE_LIMITED`、`Retry-After` 和 `X-RateLimit-Remaining`。
- Redis短时故障采用可观测的 fail-open,避免公共缓存故障放大成全站中断;登录、设备注册、密钥操作等高风险接口落地时应叠加本地保护或按接口改为 fail-closed。
本地默认速率为每来源50次/秒、突发100次,可通过 `RATE_LIMIT_RPS` 和 `RATE_LIMIT_BURST` 调整。生产值必须依据容量测试冻结。
## 5. 游标分页规范
- 查询参数 `limit` 缺省为20,只允许1至100。
- `cursor` 是HMAC-SHA256签名的不透明Base64URL值,载荷只含版本、稳定排序键和公开资源ID。
- 服务端按“排序键 + ID”组成确定性顺序,查询下一页时使用严格大于或小于条件,禁止把数据库偏移量作为游标。
- 响应中的 `next_cursor` 仅在确有下一页时返回;客户端不得解析、修改或长期持久化游标。
- 签名失败、版本不支持或字段缺失统一作为无效游标处理,不把解析细节暴露给调用方。
## 6. ETag与乐观并发规范
- 可变资源读取成功时返回强ETag,格式为 `"v{version}"`,例如 `"v3"`。
- PATCH、PUT和状态变更请求必须携带 `If-Match`;缺失时映射HTTP 428,格式无效映射HTTP 400,版本不一致映射HTTP 412。
- 不接受弱ETag `W/` 或通配符 `*`。
- 数据表须包含从1开始的 `version` 列;更新SQL必须带 `WHERE id=? AND version=?`,成功后原子执行 `version=version+1`。
- ETag只解决并发覆盖,不替代幂等键。会产生外部副作用的写请求仍须使用幂等执行器和outbox。
## 7. 验证门禁
1. 日常开发运行变更包测试、OpenAPI类型生成和前端构建;`go test ./...`、`go vet ./...`保留给CI或发布候选。
2. 游标篡改、非法limit、弱ETag、缺失If-Match和版本冲突必须有自动化测试。
3. Redis集成测试必须证明突发上限和令牌恢复。
4. 三个后端 `/health/ready` 返回200,Prometheus三个target均为 `up=1`。
5. Collector日志出现三个服务上报的Span,访问日志出现对应 `trace_id` 与 `span_id`。
6. Worker指标能区分待处理、处理中和死信事件。
7. OpenAPI破坏性变更检查和设备协议兼容门禁必须通过。