docs(观测): 阶段四设计二轮 Opus REVISE 三条修回(便宜档 OTLP 现状/脱敏验收/sot-impact 改动面)
二轮 Opus 评审裁 REVISE(小幅定向)。亲验源码坐实后订正: - Finding 1(一轮改过头):便宜档 Service+CLI 用 make_jsonl_sink 写 trace.jsonl 不产 OTLP; 唯一 OTLP exporter=tier2 专属 studio_sink、发 AgentScope Studio 私有端点、私有 root 不读入站 context。 订正 §3 面二/面三·§4 图·§5 面二/面四·§6 表;删「重定向十分钟」旧断言,改写为两条线各一处真实接线。 - Finding 2:§8 补第 7 条脱敏可跑验收(注入手机号/token→验 Tempo/Loki 打码)。 - Finding 3:frontmatter sot-impact 补明两 canonical 真实改动面(观测体系 §1 现状订正+告警多段; k8s迁移落点反转牵动目标/拓扑/阶段/风险/验收)。 - Finding 4 顺手:§5 面三 scrape 拉/推方向澄清、面四 Java traceparent 注入依赖面一先装 agent。 docs-gate 七检全绿。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8409f19c2a
commit
aceea4e52f
@ -1,8 +1,8 @@
|
||||
---
|
||||
date: 2026-07-05
|
||||
topic: 观测体系-阶段四落地
|
||||
status: 草案(fable 主笔 · Codex+Opus 双评审 REVISE→9+6 条已修回)· 方向 B 全栈 OTel、落点 mini-infra 加内存(创始人 2026-07-05 两拍)· 待创始人评审
|
||||
sot-impact: 修订两份 canonical——①《观测体系》(docs/architecture/运维/观测体系.md):补全五面落地与埋点清单、告警件夜莺→Grafana 统一(§7,推翻其件选型,待创始人确认)、脱敏 processor 与 admin 一键进盘的本期/排期表态、new-api 冻结阀去留;②《k8s迁移》(docs/architecture/运维/k8s迁移.md,亦 canonical):落点从其 §阶段3 规划的「mini-desktop 单节点 k3s observability namespace」反转为「mini-infra 扩内存后 docker-compose」,取代其观测落点段。两份 canonical 实施收口后同批回写。落点反转属横切一致性主人的灰色判断,已交创始人拍。
|
||||
status: 草案(fable 主笔 · 双评审两轮:一轮 Codex+Opus REVISE→9+6 条已修、二轮 Opus REVISE→便宜档 OTLP 现状订正/脱敏验收判据/sot-impact 改动面 三条已修)· 方向 B 全栈 OTel、落点 mini-infra 加内存(创始人 2026-07-05 两拍)· 待创始人评审
|
||||
sot-impact: 修订两份 canonical,实施收口后同批回写。①《观测体系》(docs/architecture/运维/观测体系.md):**订正 §1 现状把 monitor starter 说成「classpath 上根本没有」的旧断言**(实为经 system/infra 传递在席、只是 actuator/micrometer optional 未装、SkyWalking Bean 注释掉 = 在席但残缺);补全五面落地与埋点清单;告警件由夜莺改 Grafana 统一,牵动其 §3.4 告警规则、§3.5 admin 告警概览 API、§5.1 验收多段(推翻件选型,待创始人确认);脱敏 processor 补进 §5.1 可跑验收;成功率告警阈值(80% 达标线与预警线)口径回写时统一;admin 一键进盘的本期/排期表态、new-api 冻结阀去留。②《k8s迁移》(docs/architecture/运维/k8s迁移.md,亦 canonical):落点从其规划的「mini-desktop 单节点 k3s observability namespace」反转为「mini-infra 扩内存后 docker-compose」——不止取代观测落点段,凡把观测栈算进 k3s 资源隔离的叙述(目标、拓扑、阶段规划、风险、验收各段)回写时逐段落地,免得留自相矛盾残句。两处改动面都以回写时对源核对为准。落点反转属横切一致性主人的灰色判断,已交创始人拍。
|
||||
上级: docs/architecture/运维/观测体系.md
|
||||
---
|
||||
|
||||
@ -34,9 +34,9 @@ sot-impact: 修订两份 canonical——①《观测体系》(docs/architecture/
|
||||
|
||||
**game-cloud 的观测能力是「starter 在席、但残缺」,不是「不存在」。** monitor starter 经 huijing-module-system-server 和 huijing-module-infra-server 两个模块传递进了线上单体 huijing-server(两个模块的 pom 都引了它)。但它在席不等于能用:SkyWalking 追踪的 Bean 整段被注释、只剩一个写响应头 `trace-id` 的过滤器,而这个 trace-id 取自 SkyWalking 的上下文、agent 不在时是空串;真正出指标要的 actuator 和 micrometer 是 optional、并没有随传递装进来,所以 `/actuator/prometheus` 端点不存在、Nacos 和 RocketMQ 和 Sentinel 的 micrometer 指标无处可出、aigc 那条已经挂好的 SAA 图节点 observation 也因为拿到的是 NOOP 的 ObservationRegistry 而产不出信号。**这一面的结论是:starter 已在 classpath、但要上 OTel Java agent 自动织入 span,并引 actuator 加 micrometer 让那个 registry 不再是 NOOP、让指标端点成立;OTel 与既有(半死的)starter 是共存收编、不是从零装。**
|
||||
|
||||
**Python 生成线已经在讲 OTLP,otel 依赖也齐,缺的只是一个地址。** 这一面之前被误判过,亲验纠正:两条 Python 线共用的 observability 模块里,studio_sink 已经是完整的 OpenTelemetry OTLP/HTTP exporter,把每步生成组成符合 gen-ai 语义约定的 span 往外发;otel 的运行时依赖(api、sdk、exporter-otlp,含 proto-http)是随 agentscope 2.0.2 传递装齐的——agentscope 的 Requires-Dist 无条件带这几个,cheap-worker 的 venv 里确有 1.43.0 全套,requirements 不单列它们恰恰是对的依赖卫生。studio_sink 现在不发数据,不是缺 wheel、不会惰性 import 炸,**真因是没配到一个地址**:解析导出端点时取不到 Studio 的地址就降级成 no-op。所以重定向到 Collector 是十分钟的事——把导出端点配成 Collector 的 OTLP/HTTP 入口、确认 live 路那条默认构造的导出真开;真正要 double-check 的是 Collector 的端口与 exporter 拼 `/v1/traces` 的口径对齐,而不是装没装 wheel。
|
||||
**Python 生成线的 OTLP 现状要分两条线看,不能笼统说「依赖齐、重定向即可」——这一面第一轮评审我自己缝错过,亲验纠正。** 依赖是真齐的:otel 全套(api、sdk、exporter-otlp 含 proto-http,1.43.0)随 agentscope 2.0.2 装进了 cheap-worker 的 venv,不单列 requirements 是对的依赖卫生——**但装了依赖不等于在发 OTLP**。真实现状:**便宜档这条 MVP 主生成路,Service 与 CLI 两个入口都用 `make_jsonl_sink` 把每步 trace 直接写进产物目录的 `trace.jsonl` 文件,不产 OTLP span。** 全仓唯一的 OTLP exporter 是 tier2 富游戏线专属的 studio_sink,可它有两点决定不能简单重定向:一是它发的目标是 AgentScope Studio 的私有端点(取环境变量,取不到即 no-op、默认关),不是通用 Collector;二是它自带私有 TracerProvider、给每步自造 root span、靠 gen-ai conversation id 归组,结构上就不读入站上下文。加上 tier2 本地并无独立 venv、studio_sink 惰性 import otel(源码自陈按无 wheel 环境设计),其运行 venv 的 otel 到位与否还要在扩容后的运行环境实测。所以这一面不是配个地址的十分钟活,是两条线各有一处真实接线:**便宜档要新接一个 OTLP sink 让主路真产 span,tier2 的 studio_sink 要从发 Studio 改发 Collector、并放弃私有 root 接住入站 context**——都落在 §5 面四。
|
||||
|
||||
**但「重定向即可统一 trace」不成立——这是 Python 侧的真实拓扑决定的。** 一次生成的真实链路是三跳不是两跳:Java 的 WorkerDispatchClient 用 JDK HttpClient 把 job 发给 Python 的 worker_service,worker_service 是一个裸的标准库 http.server、OpenTelemetry 对它没有自动埋点,worker 再用 httpx 打本机的 AgentScope Service(生成 span 真正产出的进程),最后用 urllib 回调 game-cloud。三个断点:worker_service 收到的 traceparent 没人提取;worker 打本机 Service 那一跳的 header 只有 X-User-Id、trace 上下文在此断,而生成 span 恰恰产在 Service 进程;studio_sink 用的是私有的 TracerProvider、给每个生成步起独立的 root span、靠 gen-ai 的 conversation id 属性归组,既不是父子 trace 树、也不读传入的上下文。所以光改端点,Tempo 里会是一堆按属性散落的 root span,挂不到 Java 的 trace 下——端到端一个 trace 串到底这个头号卖点,按「只改端点」实现不出来。要打通得改三处(见 §5 面四)。
|
||||
**但「重定向即可统一 trace」不成立——这是 Python 侧的真实拓扑决定的。** 一次生成的真实链路是三跳不是两跳:Java 的 WorkerDispatchClient 用 JDK HttpClient 把 job 发给 Python 的 worker_service,worker_service 是一个裸的标准库 http.server、OpenTelemetry 对它没有自动埋点,worker 再用 httpx 打本机的 AgentScope Service(生成过程真正发生的进程——便宜档在这里现在只写 jsonl、还没有 OTLP span),最后用 urllib 回调 game-cloud。三个断点:worker_service 收到的 traceparent 没人提取;worker 打本机 Service 那一跳的 header 只有 X-User-Id、trace 上下文在此断,而生成 span 恰恰产在 Service 进程;tier2 的 studio_sink 用的是私有的 TracerProvider、给每个生成步起独立的 root span、靠 gen-ai 的 conversation id 属性归组,既不是父子 trace 树、也不读传入的上下文(而便宜档主路连 span 都还没有、是 jsonl)。所以光改端点,Tempo 里会是一堆按属性散落的 root span,挂不到 Java 的 trace 下——端到端一个 trace 串到底这个头号卖点,按「只改端点」实现不出来。要打通得改三处(见 §5 面四)。
|
||||
|
||||
**deploy/infra 现在只有 Nacos 和 RocketMQ,观测栈是零。** 观测栈的自然落点是新增一个 `deploy/infra/observability/` compose。
|
||||
|
||||
@ -50,7 +50,7 @@ sot-impact: 修订两份 canonical——①《观测体系》(docs/architecture/
|
||||
flowchart LR
|
||||
subgraph 源["信号源(全服务 + 两条生成路,跨机经 Tailscale)"]
|
||||
GC["game-cloud 单体(别处)<br/>OTel Java agent 自动 span<br/>+ actuator/micrometer 指标<br/>+ SAA 节点 observation(仅 saa 路)"]
|
||||
PY["Python 生成线(mini-desktop)<br/>Service :8300 生成 span<br/>studio_sink OTLP(重定向+接传入 context)"]
|
||||
PY["Python 生成线(mini-desktop)<br/>便宜档主路 jsonl→新接 OTLP sink<br/>tier2 studio_sink 改发 Collector<br/>两路接入站 context(面四)"]
|
||||
INFRA["Nacos / RocketMQ / Sentinel<br/>micrometer 指标"]
|
||||
end
|
||||
|
||||
@ -83,11 +83,11 @@ flowchart LR
|
||||
|
||||
**面一 · game-cloud 接入。** 主路是 OTel Java agent:给 huijing-server 的启动加一个 `-javaagent` 参数,零代码自动织入 Spring MVC、JDBC、Redis、出网 HTTP(包括调 Python Service 和 new-api)的 span,一步拿到 Java 侧全链 trace 并在出网时自动注入 traceparent。为了让已经挂好的 SAA observation 从 NOOP 活过来、并让 Nacos/RocketMQ/Sentinel 的 micrometer 指标有处可出,给单体引入 actuator 加 micrometer 的 OTLP 或 prometheus registry。既有那套半死的 monitor starter 是共存收编:SkyWalking 的 toolkit 依赖留着不删(不动 yudao 框架层)、profile 里不启用,响应头过滤器的 trace-id 来源从 SkyWalking 换成 OTel 当前 span,让前端拿到的 trace-id 真能在 Grafana 里查到。
|
||||
|
||||
**面二 · Python 生成线重定向。** 依赖不用补——otel 运行时依赖已随 agentscope 齐备。要做的是:把 studio_sink 的导出端点从(默认取不到的)Studio 地址配成 Collector 的 OTLP/HTTP 入口、确认 live 路那条默认构造的导出真开、核对端口与 `/v1/traces` 口径。再给 Python 侧补一个 OTLP 的 metrics exporter,把成本、token、耗时、门结果从「落盘等后端反推」升级成 metric 直发 Collector。
|
||||
**面二 · Python 生成线接 OTLP(是接线,不是重定向)。** 依赖层面 cheap-worker venv 的 otel 全套已在、不用补 wheel;但如 §3,便宜档主路现在只写 jsonl、tier2 的 studio_sink 又发的是 Studio 私有端点,所以要**两条线各接一处**:便宜档在 jsonl sink 之外新接一个 OTLP span 发射(让主路真产 span 并发 Collector),tier2 的 studio_sink 把导出端点从 Studio 改成 Collector 的 OTLP/HTTP 入口、核对端口与 `/v1/traces` 口径、并按面四改掉私有 root;两条都要接住入站 context。再给 Python 侧补一个 OTLP 的 metrics exporter,把成本、token、耗时、门结果从「落盘等后端反推」升级成 metric 直发 Collector。
|
||||
|
||||
**面三 · 部署编排与存储治理。** 新增 `deploy/infra/observability/` 一个 compose,把 Collector、Prometheus、Tempo、Loki、Grafana 五件起在 mini-infra(扩容后)。资源纪律要比 Nacos/RocketMQ 那套更严,因为同箱的是跨项目生产件:每个观测容器设死内存上限、**同时设 CPU 限额并把进程优先级压到低于 mini-infra 的生产件**,不让失控的 Prometheus/Tempo 在 CPU 和 IO 上挤兑 new-api。存储治理不能只写「存 MinIO」四个字——既有 MinIO 是 ragflow 共用实例、现有 bucket 只有 tier2 源文件,所以要给观测单独定 bucket 命名、保留期(Prometheus 7 到 15 天起步)、容量阈值配额、对象生命周期回收、MinIO 不可达时的降级(本地缓冲丢弃而非阻塞)、以及回滚时的删除策略。拓扑按跨机写:scrape 目标和 OTLP 端点都指 100.64.0.8,余量按跨机计。
|
||||
**面三 · 部署编排与存储治理。** 新增 `deploy/infra/observability/` 一个 compose,把 Collector、Prometheus、Tempo、Loki、Grafana 五件起在 mini-infra(扩容后)。资源纪律要比 Nacos/RocketMQ 那套更严,因为同箱的是跨项目生产件:每个观测容器设死内存上限、**同时设 CPU 限额并把进程优先级压到低于 mini-infra 的生产件**,不让失控的 Prometheus/Tempo 在 CPU 和 IO 上挤兑 new-api。存储治理不能只写「存 MinIO」四个字——既有 MinIO 是 ragflow 共用实例、现有 bucket 只有 tier2 源文件,所以要给观测单独定 bucket 命名、保留期(Prometheus 7 到 15 天起步)、容量阈值配额、对象生命周期回收、MinIO 不可达时的降级(本地缓冲丢弃而非阻塞)、以及回滚时的删除策略。拓扑按跨机写、且分清拉推方向:OTLP 上报是被观测端(game-cloud、两条生成线,都在别处)主动推到 mini-infra 的 Collector;Prometheus 在 mini-infra、是它主动去 scrape 抓别处暴露的指标端点。推的端点、拉的目标各按跨机连通与余量算,别混成「都指 .8」。
|
||||
|
||||
**面四 · 贯穿(三跳,不是两跳)。** 把端到端一个 trace 串起来要改四处:Java 的 WorkerDispatchClient 出网时由 agent 自动注入 traceparent(已有);Python 的 worker_service 是裸 http.server,要手动用 propagator 从入站 header 提取 traceparent、建一个 server span;worker 打本机 AgentScope Service 那一跳的 httpx 请求要手动注入 traceparent;Service 侧让生成 span 接住这个传入的 context(而不是像现在 studio_sink 那样用私有 provider 自造 root),这样生成 span 才挂在 Java 的 trace 下;回调 game-cloud 那跳同样手动注入、Java 入口提取。业务 traceId 与 W3C traceId 采「并存关联」——业务 traceId 作为 span 的一个属性保留(它承担产物归位和回调关联),W3C traceparent 负责跨语言贯穿,不强行升级业务 traceId 的格式。
|
||||
**面四 · 贯穿(三跳,不是两跳)。** 把端到端一个 trace 串起来要改四处:Java 的 WorkerDispatchClient 出网时由 OTel agent 自动注入 traceparent(依赖面一先把 agent 装上,不是现成的);Python 的 worker_service 是裸 http.server,要手动用 propagator 从入站 header 提取 traceparent、建一个 server span;worker 打本机 AgentScope Service 那一跳的 httpx 请求要手动注入 traceparent;Service 侧让生成 span 接住这个传入的 context——便宜档主路现在是 jsonl、连 span 都没有,得先按面二让它产 OTLP span 再接 context,tier2 的 studio_sink 有 span 但私有 root、要改成读入站 context 建子 span——这样两条线的生成 span 才都挂在 Java 的 trace 下;回调 game-cloud 那跳同样手动注入、Java 入口提取。业务 traceId 与 W3C traceId 采「并存关联」——业务 traceId 作为 span 的一个属性保留(它承担产物归位和回调关联),W3C traceparent 负责跨语言贯穿,不强行升级业务 traceId 的格式。
|
||||
|
||||
**面五 · 埋点。** 见第 6 节。原则是能靠 agent 自动出的不手埋,只有业务语义的指标才手埋、且埋在终态收口处一次埋全。
|
||||
|
||||
@ -104,7 +104,7 @@ flowchart LR
|
||||
| 服务可用性 ≥99.5% | game-cloud + Collector | metric | OTel agent 自动出 HTTP server 指标 + actuator health | 需装 agent/actuator |
|
||||
| feed 首屏 P75<3s | game-studio 前端 | metric/RUM | 现有业务遥测埋点已在;OTel 前端观测排三期 | 业务 RUM 有 |
|
||||
| new-api 多通道健康 **+ 批跑冻结阀** | 后台巡检 job | metric **+ 控制动作** | 巡检探活每通道 + 查 key 额度;**可用通道掉到下限自动冻结后台批跑**(2026-06 通道整批作废的直接教训,巡检与冻结阀是一套) | 需新建;冻结阀本期与巡检一起做还是排后续,见 §10 |
|
||||
| 全链路 trace | 全链 | trace | Java agent + Python 三跳 traceparent(面四) | Python 有、Java 无、三跳未打通 |
|
||||
| 全链路 trace | 全链 | trace | Java agent + Python 三跳 traceparent(面四) | 便宜档主路写 jsonl 无 span、tier2 studio_sink 发 Studio 私有 root、Java 无 agent;三跳均未打通 |
|
||||
| 集中日志(脱敏后) | 全进程 | log | Collector filelog / logback OTLP,trace_id 注入 MDC,只收 WARN/ERROR;**进库前经脱敏 processor** | 需新建 |
|
||||
| 脱敏 processor | Collector | 安全红线 | 手机号/token 进 Tempo/Loki 前最后一道,继承《观测体系》§3.1/§5.2 | **必做,不能丢** |
|
||||
| SAA 图节点 span | game-cloud aigc | trace | 装 micrometer 即活,**但仅 dispatcher=saa 的 opt-in 进程内路有效;默认 http 路生成不跑 SAA 图、其 trace 来自 Python 线** | 依赖就位,限定路 |
|
||||
@ -134,6 +134,7 @@ flowchart LR
|
||||
4. **可用性 error budget** 燃尽图与 health 探测对得上。
|
||||
5. **停 Collector 主链不变**:停掉 Collector 后生成主链行为不变、冒烟门全绿。
|
||||
6. **agent 性能量化**:staging 挂 agent 压一轮,启动耗时差、P95/P99 请求耗时差、生成任务耗时差在阈值内,agent 的 queue/drop 指标可见——「冒烟绿」不足以发现 agent 注入的启动变慢和批量上报内存积压。
|
||||
7. **脱敏真打码(安全红线,必须能跑)**:往一次生成的 brief / prompt 里注入构造的手机号和 token,跑完在 Tempo 的 span 属性和 Loki 的日志正文里都查不到明文、只见掩码——脱敏不能只写进「必做」叙述,要有这条能真跑的判据兜住,漏配即安全回退。
|
||||
|
||||
分波实施(每波都在扩容窗口之后,按依赖串):先起观测栈后端五件并自监控;再给 game-cloud 挂 agent 加 actuator;再重定向 Python 的 OTLP 加 metrics;再打通三跳 traceparent;最后落业务埋点、脱敏 processor、建看板和告警。前端 OTel Web SDK 排三期。
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user