外观
VMax 服务端可观测性
1. 目标与隐私预算
可观测性用于发现消息积压、错误、容量和依赖故障,不用于建立用户关系图谱、内容分析或长期行为画像。默认收集能少则少,先定义问题再增加信号。
- 来源 MUST:日志、指标、追踪、崩溃报告和诊断不得包含消息正文、私钥、备份密码、完整地址、APNs token、主/假密码或可逆口令材料。
- 来源 MUST:服务日志默认保留 7 天且脱敏;生产默认不记录 URL query、token 或 ID 全值。
- 建议方案:OpenTelemetry 兼容接口、结构化 JSON 日志和 Prometheus 风格指标;供应商可替换。
- 已验证事实:当前没有服务实现或采集栈,本文字段和告警尚未通过运行验证。
2. 数据分类
2.1 允许的结构化字段
timestamp、level、service、environment、request_id、低基数 route_template、method、status_code、latency_ms、稳定 error_code、release_version、config_version。
需要 actor 关联时只使用短期、带环境隔离和轮换盐的哈希,且不得跨天/跨服务长期稳定。该机制的盐周期和用途为 ADR-008 的待总控决策。
2.2 禁止字段
- 消息正文、密文全值、原始信封、消息预览、联系人名。
- 身份/设备/会话私钥、会话密钥、备份密码、主密码、假密码、派生值。
- Authorization、access/refresh token、challenge 签名、APNs token、Gateway secret。
- 完整 VMax 地址、完整设备 ID、完整 IP 长期历史、备份路径。
- 伪装槽位命中、真实 Profile 存在或格式化触发的可识别事件。
- 原始 URL query、请求/响应正文、数据库连接串和 secret 环境变量。
密文仍是敏感数据;“服务器读不懂”不等于可以记录。
3. 日志
- 入口、API、Worker、Gateway 使用同一字段字典和拒绝默认的脱敏库。
- 路由记录模板
/v1/messages/{id},不记录具体路径参数。 - 错误只记录稳定错误码和安全上下文,不打印结构体、headers、SQL 参数或 payload。
- panic/crash handler 关闭内存、请求正文和环境变量抓取;第三方 SDK 上线前逐项验证。
- 安全审计事件与应用 debug 日志分离,访问和保留权限更严格。
- debug 日志在生产构建关闭;临时提高级别要有审批、自动过期和事后复查。
4. 指标
4.1 服务指标
- HTTP 请求率、错误率、P50/P95/P99 延迟,标签只用 route template、方法、状态/错误码。
- 认证 challenge 发放/成功/过期/重放计数。
- 消息入队、拉取、ACK、过期、配额拒绝、幂等重放/冲突计数。
- 按实例总量统计的队列深度、最老信封年龄和总字节;不以设备、地址或会话作标签。
- Worker outbox 待处理数、最老任务年龄、重试/隔离数。
- Redis 队列连接、ready/scheduled/active/retry/dead-letter 数、最老任务年龄、领取超时和重复执行数;不得把 job ID 或业务标识作为 label。
- Push 请求、成功、APNs 稳定错误类别、退避和禁用路由数;不含 token。
- PostgreSQL 连接、锁等待、事务失败、磁盘/WAL、复制延迟;Redis 观察任务队列、连接与短期加速状态,但任何 Redis 指标都不能替代 PostgreSQL outbox 完成状态。
- 对象存储上传/下载/删除、孤儿对账与字节量,仅附件启用时存在。
4.2 禁止高基数标签
不得使用 message_id、device_id、VMax 地址、route ID、IP、request ID 或游标作为指标 label。需要单次排障时,以短期 request ID 在受控日志中关联。
5. 追踪
- 追踪只覆盖服务端内部请求和依赖调用;不将 trace ID 写入 E2EE 协议对象。
- 默认不采集请求/响应 body、headers、SQL bind 参数或队列 payload。
- 采样依据服务健康和错误类别,不按特定用户定向长期采样。
- Gateway 与消息实例之间的追踪边界默认断开或使用一次性关联,避免形成可长期关联的通信时间图谱。
6. 告警建议
| 告警 | 触发信号 | 首要动作 |
|---|---|---|
| 消息入队失败 | 稳定 5xx/事务失败率 | 检查数据库与磁盘,禁止盲目重放非幂等请求 |
| 队列积压 | 深度、总字节、最老年龄持续上升 | 区分客户端离线、Worker 故障与容量不足 |
| Redis 任务积压 | outbox 与 Redis backlog 差值、最老 job、重试增长 | 检查 dispatcher/Worker/Redis,必要时限制新写入并从 outbox 补偿 |
| ACK 清理滞后 | cleanup_after 超过 1 小时 | 检查 Worker/锁/磁盘并启动补偿 |
| 幂等冲突激增 | IDEMPOTENCY_KEY_REUSED | 排查客户端键复用或攻击,不记录原请求体 |
| Push 故障 | Gateway/APNs 错误与延迟 | 保证拉取路径,按错误码退避/停用无效 token |
| 过期清理滞后 | 最老过期记录年龄 | 限速补偿,监控数据库负载 |
| 备份失败 | 备份/校验/恢复演练状态 | 立刻确认最近可恢复点 |
| 隐私守卫触发 | 敏感字段扫描命中 | 停止外发、隔离数据并按事件响应处理 |
阈值需基于负载测试与基线,待总控决策。告警消息本身不得包含敏感值。
7. 脱敏验证
- 在测试环境注入带唯一 canary 的消息正文、token、地址、APNs token 和口令样本。
- 执行正常、错误、超时、panic、数据库失败和 Gateway 失败路径。
- 执行 Redis 断连、清空、任务重复、毒任务和 outbox 补偿路径;确认 job payload 与 dead-letter 不含敏感数据。
- 扫描应用日志、代理日志、指标 label、trace、崩溃包、告警、备份和诊断导出。
- 任一 canary 出现即阻断发布,修复后重新全链路验证。
- 生产定期执行 schema/字段审计和抽样,不导出真实敏感值做测试。
8. 待总控决策
| 决策 | 选项 | 建议 | 验证 |
|---|---|---|---|
| actor 短期哈希 | 每请求 / 每小时 / 每天轮换 | 最短能满足一次事件排障的周期,禁止跨环境复用盐 | 链接性评估与轮换测试 |
| 日志后端 | 本地轮转 / 自托管聚合 / 云服务 | Compose 提供本地安全默认,后端可替换 | 传输、权限、删除和区域检查 |
| trace 采样 | 固定比率 / 错误优先 / 尾采样 | 低比例 + 错误类别,不按用户 | 敏感字段扫描与成本压测 |
| 日志保留 | 默认 7 天;部署者可缩短 | 不提供无上限默认 | TTL 实测与备份副本检查 |
| 隐私事件上报 | 本地告警 / 外部通知 | 只发事件类别和实例级汇总 | 通知内容审查与泄漏演练 |
9. 验收
- 每个核心流程有指标但不含高基数用户标识。
- 敏感 canary 全链路扫描为零命中。
- 告警能区分网络 peer reset、连接超时、读超时、数据库拒绝和配额拒绝,避免错误归因。
- 保留策略实际删除日志、trace 和告警副本;监控系统备份也纳入检查。
- 未通过隐私扫描和故障演练前,不得称可观测性“已合规”或“已生产验证”。