阶段十三:OmniRoute latest stable 原生迁移
计划 ID:phase-13-omniroute-latest-stable-migration
阶段状态:已完成并归档
计划状态:已完成
当前工作包:无;P13-6 已完成并归档
权威边界:本文件是 P13 的唯一正式计划入口。P12 已完成 102 节点纳管并归档;P13-0 至 P13-4 已完成,P13-B 已把公网入口直接切到 102,P13-C 已按用户决定取消观察等待期并删除 RR 上的 omni 数据、包、unit 与备份。102 上的官方 omniroute@3.8.51 是唯一生产权威和唯一 SQLite 写者;RR 不再保留回退点,恢复改为从 Cloudreve P13-4 快照恢复或在 102 重装。
📌 结论摘要
2026-10-01 已执行 P13-4 受控切换:RR 在切换时刻停止本地 OmniRoute 写入、生成最终备份与一致性快照,102 恢复该快照后启动 3.8.51;RR 的 2 处公网回源和 Runtime 私有代理均已切到 100.64.0.4:39200。随后 P13-B 把 MM 公网入口改为直连 102,避免继续经过 RR 共用回源网关;公网 health、模型目录、Boss/Worker Combo、Codex Responses SSE/tools、管理 API、SQLite 回读和负向鉴权均通过。依据是 RR/102/MM 现场命令输出、Cloudreve 哈希回读和 计划历史;影响是生产模型核心权威已从 RR 3.8.50 转为 102 3.8.51。
迁移还完成了一次真实回退与再次切换闭环:102 停止写入并生成清洁快照,RR 恢复该快照并执行 rollback,RR 本地服务恢复、真实调用返回精确成功文本;随后 RR 再次 freeze、生成回流快照,102 恢复并重新 activate。整个流程证明 RR 回退点可用,且最终只有一个 SQLite 写者。依据是最终快照路径、大小、SHA-256 和两轮 health/真实调用记录;影响是 P13-5 可以观察 102 稳定性,而不必重新讨论迁移是否可行。
现场发现并修复了两个会破坏长期可重复性的缺陷:102 缺少 sqlite3 会让官方快照退化为“主库 + WAL 复制”,RR systemd 255 未按预期通过 drop-in 空赋值清除 Runtime 代理对本机 OmniRoute 的依赖。前者已在部署脚本增加 sqlite3 预检并用 VACUUM INTO 做负向回归;后者已通过包外 unit 的精确两行改写、原始备份和依赖回读修复。依据是脚本版本、哈希、快照文件和 systemd 输出;影响是干净节点重装和后续回退不会再依赖人工记忆。
进入 P13-5 后又发现并修复了第三个生产缺陷:102 edge 代理的 FD 软上限仍为 1024,在长期连接累积后出现 Too many open files,导致 RR 与公网入口超时。修复脚本已升为 v0.1.2,显式设置 LimitNOFILE=65536:65536、--connections-max=4096 和失败重启,并把 FD 上限纳入 check;修复后 RR 私有入口与公网 health 均恢复 200。依据是 102 journal、进程 FD 计数、RR→102 探测和公网回归;影响是同类连接耗尽不会再只表现为“服务 active 但转发失效”。
P13-C 已取消观察等待期并完成 RR omni 全量退役:RR 上不再存在 /root/.omniroute、3.8.50 全局包、旧 service unit、cutover 备份和 omni vhost;RR 仅保留正在被本机 AI Runtime 容器使用的 172.30.70.1:39181 → 100.64.0.4:39200 私有代理,以及 RR Codex 使用的 MCP 凭据。原 P13-5 相位观察器已迁移为无阶段阻塞含义的健康观察器,继续每 15 分钟只读检查 102 生产、公网入口和 RR 退役边界。
P13 已完成最终验收、文档状态同步和 Git/CI 门禁;完整归档见 completed-phase-13-omniroute-latest-stable-migration.md。本页保留全部执行细节与稳定 URL,不再代表当前工作包。
🗂️ 目录
- 计划状态
- 目标、成果与验收契约
- 当前事实与版本差异
- 技术栈与架构选型
- 执行位置与阶段关系
- 工作包与依赖
- 验收与回退
- 回退与再次切换
- 根因、修复与防复发
- 分布式底座接入声明
- 数据、凭据与回退边界
- P13-5 取消与 P13-6 健康观察
- 未决项 / 需要用户决策
🧾 计划状态
| 项目 | 当前值 | 依据 |
|---|---|---|
| 当前阶段 | 已归档,后续为 P14 需求评审占位 | docs/plans/state.json |
| 阶段状态 | 已完成并归档 | 迁移、公网直连、RR 全量退役和最终门禁均已完成 |
| 计划状态 | 已完成 | 工作包、依赖、验收和回退均已冻结 |
| 当前工作包 | 无;P13-6 已完成并归档 | 后续状态变化作为新运维事件或新阶段处理 |
| 生产权威 | 102 官方 omniroute@3.8.51 |
MM 公网入口与 RR Runtime 私有代理均指向 100.64.0.4:39200 |
| 回退点 | 已退役 | 用户决定不再保留 RR 回退点;恢复以 Cloudreve P13-4 快照和 102 原生重装为准 |
| 公网入口 | MM 仍为唯一 80/443 入口 | MM omni.yohan.fun.conf 已改为直连 proxy_pass http://100.64.0.4:39200;(P13-B) |
| 数据写者 | 仅 102 | RR omni 服务、数据和包已删除,102 为唯一 SQLite 写者 |
| 健康观察器 | 101 每 15 分钟只读检查 102、RR 退役边界和公网 | agentmeshos-omniroute-health-observation.timer |
P13-0 至 P13-4 的状态如下:
| 工作包 | 状态 | 完成口径 |
|---|---|---|
| P13-0 版本与回退冻结 | 已完成 | 官方 Node、npm latest、integrity、shasum、unpackedSize、Release 与 CHANGELOG 已固定 |
| P13-1 102 一次性安装 | 已完成 | 直接安装 Node 22.23.0 与 OmniRoute 3.8.51,没有旧版中间态 |
| P13-2 隔离恢复 | 已完成 | 从 RR 官方备份与一致性快照恢复,完成数据计数、解密、健康与 schema 核对 |
| P13-3 切换剧本冻结 | 已完成 | 102 私有入口、RR freeze/activate/rollback、停写与哈希流程已实做 |
| P13-4 受控切换与验收 | 已完成 | 最终快照、生产切换、全链路验收、回退演练、再次切换和文档化修复均通过 |
| P13-5 稳定性观察 | 已取消等待期 | 用户明确取消观察等待期;长期健康检查迁移为 P13-6 的非阻塞观察器 |
| P13-6 RR 全量退役与阶段收口 | 已完成并归档 | RR omni 全部删除、入口与脚本统一、最终验收和归档门禁全部通过 |
🎯 目标、成果与验收契约
本阶段的目标是把生产 OmniRoute 从 RR 旧版本迁移到 102 官方最新稳定版,同时保持 MM、公网入口和 Runtime 调用面稳定。最终验收契约为:102 成为唯一生产写者;MM 公网入口直连 102;RR omni 数据和包全部退出;RR 仅保留本机容器所需的 Runtime 私有代理;恢复以 Cloudreve 快照和 102 原生重装为准。
| 项目 | 切换前 | 切换后当前值 | 证据 |
|---|---|---|---|
| 生产版本 | RR 3.8.50 |
102 3.8.51 |
102 CLI 与 systemd 运行态 |
| RR 公网上游 | 2 处 127.0.0.1:39180 |
2 处 100.64.0.4:39200;P13-B 后 MM 不再经此入口 |
agentmeshos-origin-gateway.conf |
| RR Runtime 代理 | 127.0.0.1:39180 |
100.64.0.4:39200 |
agentmeshos-omniroute-runtime-proxy.service.d/upstream-p13.conf |
| RR 本地 OmniRoute | active | 数据、包和 unit 已删除(P13-C) | RR 路径存在性检查与 nginx -T |
| MM 回源 | 100.64.0.1:39200 |
P13-B 改为直连 100.64.0.4:39200 |
/www/server/panel/vhost/nginx/omni.yohan.fun.conf |
| 公网 health | RR 本地 | 102 直连(MM → 102) |
https://omni.yohan.fun/api/monitoring/health 返回 200 |
| 102 数据计数 | 隔离副本 | 70 连接、19 Combo、4 API Key、迁移 193 |
102 SQLite 只读查询 |
结论是:公网用户、Runtime 和现有调用方的最终后端都是 102 3.8.51。P13-4 把 RR 的最终上游从本机 3.8.50 换成 102;P13-B 进一步把 MM 公网入口从“经 RR 私有网关”改成“直连 102 私有入口”;P13-C 删除 RR 的全部 omni 数据和包,只保留 RR 本机 AI Runtime 容器正在使用的私有代理。
🌐 P13-B:公网入口直连 102,RR 退出 omni 路径
动机:RR 的 100.64.0.1:39200 是 *.yohan.fun 的共用回源网关,按域名分流到 8 个后端,其中 7 个后端就在 RR 本机,只有 omni 已被迁到 102。omni 直连 102 可以摘掉一个失败域(RR)并缩短排查链路,代价是 MM 需要为 omni 单独记住一个后端地址。
改动:MM 有两个存储必须同时改。第一是宝塔面板的反代配置源 /www/server/proxy_project/sites/omni.yohan.fun/omni.yohan.fun.json,面板列表和目标保存都以它为准;第二是渲染出来的 nginx 配置 /www/server/panel/vhost/nginx/omni.yohan.fun.conf。两处的 proxy_pass 都由 http://100.64.0.1:39200 改为 http://100.64.0.4:39200,并在面板 server_block 与 nginx 配置补齐 location = /、location = /dashboard(302 到 /login)和 location = /login(保留 auth_token 已存在时 302 到 /home 的规范化)。改动前按时间戳备份到 MM /root/omni-conf-backups/,nginx -t 通过后 reload。102 私有入口的放行来源本就是 100.64.0.1(RR)与 100.64.0.6(MM),因此直连无需改 102 防火墙。
失败教训(必须记住):第一次只改了渲染 conf,没改面板 JSON。结果是 nginx 运行态已经直连 102,但面板仍显示 100.64.0.1:39200,而且任何人从面板点保存都会按 JSON 把 conf 回写成 100.64.0.1。判据是面板 JSON 与渲染 conf 出现分歧;结论是凡经宝塔面板管理的反代,改目标必须同时改面板 JSON 与渲染 conf,并以「面板显示值 + conf 值 + 运行态 + 抓包来源」四项一致作为完成口径。
验证:公网 https://omni.yohan.fun/api/monitoring/health 返回 200、/ 返回 302 → /login、/login 返回 200;并发打公网时在 102 实时抓到 100.64.0.4:39200 ← 100.64.0.6(MM)的连接(48 个样本全部来自 MM,RR 为 0),证明公网已直连 102,不再经 RR。
回退边界更正:P13-B 之后,公网回退不再由 RR origin gateway 决定,而由 MM 面板 JSON + 渲染 conf 决定。P13-C 已删除 RR cutover 脚本,因为 RR 本地 OmniRoute 与 omni vhost 都已不存在;任何未来公网切换必须在 MM 两处配置中显式完成,不能恢复已退役脚本。
RR 清理:P13-B 先清除了 Gemini Web 补丁文件与 .omniroute-patches、PR14787 实验目录、VNC 实验目录、omni 镜像测试目录、已退役 discovery 的 unit 与 /opt、/etc 配置;P13-C 随后按用户决定删除 OmniRoute 数据、包、unit、cutover 备份与网关 vhost。RR 的 Runtime 私有代理继续保留,因为本机 AI Runtime 容器通过 172.30.70.1:39181 访问 102。
🧹 P13-C:RR omni 全量退役与入口统一
用户决定取消 P13-5 观察等待期,直接删除 RR 上全部 omni 物料。本段记录删除范围、保留项与保留理由,供后续审计。
删除:/root/.omniroute(2.1G)、/usr/lib/node_modules/omniroute(3.8.50,2.7G)、/etc/systemd/system/agentmeshos-omniroute.service 与 .d、/root/.omniroute-cutover-backups、/root/omniroute-*、/etc/agentmeshos/omniroute-core、/etc/agentmeshos/nginx-tailnet/agentmeshos-origin-gateway.conf*、/backup/agentmeshos/omniroute-*(含 discovery 与历史备份)、RR 侧 /root/agentmeshos-omniroute-cutover.sh。删除前在该备份盘留下清单与小组件归档。
| 保留项 | 保留理由(已实测) |
|---|---|
RR agentmeshos-omniroute-runtime-proxy.service/.socket(172.30.70.1:39181 → 100.64.0.4:39200) |
不是残留。RR 本机 agentmeshos-ai-runtime 容器的 AI_RUNTIME_OMNIROUTE_BASE_URL=http://172.30.70.1:39181 正在使用它;同机 39120、39184 也用同一 172.30.70.1 网关模式。容器经代理与直连 102 实测都返回 200,选择代理是因为它让容器不硬编码 Tailnet IP、后端再迁移时无需重建容器,更灵活也更一致 |
/var/lib/agentmeshos/swap/omniroute-install.swap(4G) |
不是 omni 数据,是 active swap;RR 仅 3.8G 内存、swap 已用约 895M,删除会降低 swap 余量 |
RR /root/.codex/credentials/omniroute-mcp.env 与 /root/.codex/bin/omniroute-mcp-headers.sh |
RR 本机 Codex 通过 https://omni.yohan.fun/api/mcp/stream 调用 MCP,需要该凭据 |
脚本与入口统一:agentmeshos-main-origin-gateway.sh 升 v0.6.2,删除 omni server 块与 OMNIROUTE_UPSTREAM/OMNIROUTE_DISCOVERY_UPSTREAM 变量,RR 网关不再生成 omni vhost;agentmeshos-omniroute-cutover.sh 退役删除,因为 RR 本地 OmniRoute 与 RR 网关 omni 都已不存在,其 freeze/activate/rollback 已无对象,公网回退改由 MM 侧决定。
验证:RR nginx -T 中 server_name omni.yohan.fun 计数为 0;RR 网关上其余 7 个域名 docs/status/api/auth/nomad/console/mesh 全部 200/302;公网 omni health 200;RR 容器经 172.30.70.1:39181 返回 200;RR systemctl --failed 为 0;RR 根盘用量从 41G 降到 35G。
审计与影响:退役清单和小组件归档在 101 备份盘 /srv/codex-hub-backup/agentmeshos/omniroute-rr-retire-20261001T022315Z/,tar SHA-256 为 b4b4072cdd57477e64232f05411eb54de1ca1096a88720a6799737b7de4039c0。从此 RR 不再有回退点,102 故障的恢复方式变为从 Cloudreve 的 P13-4 快照恢复或在 102 重装,而不再是切回 RR。
📊 当前事实与版本差异
3.8.51 是在 P13-0 执行时重新查询到的官方 npm latest,不是把旧版本先装上再升级。下表用于说明与上一生产版本 3.8.50 的主要变化方向;具体使用仍以真实 Smoke 和权限边界为准。
| 变化方向 | 主要变化 | 对 AgentMeshOS 的影响 | 当前使用口径 |
|---|---|---|---|
| 路由与稳定性 | 分层并发准入、自适应推理强度、Provider 断路器、冷却与 429 判断修正 | 改善长 Responses、Worker 并发、Combo 故障切换 | 已随迁移启用;继续观察真实错误率 |
| Provider 与模型目录 | 模型 allowlist/denylist、账号实时目录、模型别名扩充 | 降低目录漂移并支持更细粒度可见性 | 已启用现有正式目录,不因升级全量开放 |
| Free tier 与 Radar | 免费资格、isFree、限速展示和训练提示 |
影响免费 Combo 和额度解释 | 继续受“零成本优先”和隐私规则约束 |
| 可观测性 | 编排图、历史对比、Repeat、日志导出、首包耗时和 MCP 时间线 | 提升 Console 与故障复盘能力 | 只读验证后采用,日志正文导出默认关闭 |
| 安全加固 | 请求钩子隔离、IP allow/deny、内网端点拒绝、OAuth 路由保护、常量时间比较、路径穿越防护 | 直接影响管理面、反代和 Responses 子路径 | 已做未授权、错误 Token、路径穿越负向回归 |
| 媒体与上下文压缩 | Video/Audio Bridge、STT、压缩线程池、可选语义缓存 | 对多模态和长上下文有潜在价值 | 暂不默认启用,后续单项评估资源与隐私 |
| 数据与迁移 | schema 收敛、懒建表迁移、迁移数量与运行目录变化 | 影响备份恢复和版本升级 | 已通过最终快照恢复、quick_check 和迁移计数验证 |
后续使用优先级固定为:现有 Boss/Worker Combo 与 Chat Completions 第一优先;Codex Responses SSE/tools 第一优先但继续做真实回归;管理 API 和可观测性只读能力第二优先;媒体、语义缓存、日志正文导出和训练相关能力第三优先且默认关闭。
🧱 技术栈与架构选型
| 选型面 | 最终选择 | 选择依据 | 未采用方案及原因 |
|---|---|---|---|
| OmniRoute 运行方式 | 102 官方 npm 原生安装 3.8.51 + systemd |
满足用户要求的“一次性安装最新版”,不修改官方包内容;运行版本、Node 22.23.0 和 health 均有现场证据 |
先装旧版再升级会增加一次无必要迁移;容器迁移会改变既有宿主边界,均不采用 |
| 数据权威 | 102 /root/.omniroute/storage.sqlite 唯一写者 |
RR 最终快照恢复到 102 后,SQLite quick_check=ok,并验证 70 条连接、19 个 Combo、4 个 API Key、迁移 193 |
不让 RR 与 102 双写,也不手工拼接数据库;避免迁移后出现分叉或不可判定数据 |
| 公网与 Runtime 入口 | MM 直连 100.64.0.4:39200,RR Runtime 私有代理也指向 102 |
公网不再经过 RR,RR 本机容器继续使用稳定的 172.30.70.1:39181 本地入口 |
不在 102 暴露公网监听,也不让容器硬编码 Tailnet IP |
| 102 私有入口 | agentmeshos-omniroute-edge.socket 监听 100.64.0.4:39200,经 raw PREROUTING guard 放行 RR 与 MM |
仅允许管理链路访问,101 负向连接超时;RR 与 MM 正向访问返回 200 |
不开放公网监听,也不把数据库或管理端点直接暴露到 Tailnet 范围 |
| 恢复边界 | Cloudreve P13-4 快照与 102 原生重装流程 | 回退演练已真实执行,证明切换前恢复路径可行;用户随后要求取消等待期并删除 RR 回退点 | 不在 RR 恢复第二写者,也不把旧 RR 路径重新当作生产入口 |
| 交付与复盘 | 官方备份、一致性快照、Cloudreve 哈希回读、仓库计划和脚本版本化 | 需要同时保留数据恢复点和可审计执行路径 | 不以单次 health 200 或手工命令记录代替完整验收证据 |
结论是:迁移采用“官方最新版一次性安装、单写者数据切换、公网直连 102、RR 全量退役”的架构。依据是 102、RR、MM 的现场运行态以及本页验收表;影响是后续只保留无阶段阻塞的健康观察,不再恢复 RR 回退路径。
🛠️ 工作包与依赖
| 工作包 | 前置依赖 | 完成证据 | 失败边界 |
|---|---|---|---|
| P13-0 版本冻结 | 官方 npm/GitHub 可读 | 版本、integrity、shasum、unpackedSize、Node engines、CHANGELOG | 任一漂移则停止安装 |
| P13-1 102 安装 | Node 22.23.0、目标版本明确 |
CLI、systemd、loopback 与 health | 不允许先装旧版或修改包内容 |
| P13-2 隔离恢复 | RR 有可读官方备份和一致性快照 | 计数、解密、迁移、quick_check、service |
出现双写或数据不一致即停止 |
| P13-3 切换剧本 | 102 私有入口可用,RR 可停写 | freeze、上游重写、drop-in、rollback 路径 |
写入者未停止时禁止 activate |
| P13-4 生产切换 | 维护窗口、最终快照、最终恢复 | 公网 health、模型、Combo、Responses、管理 API、SQLite、负向回归、回退与再次切换 | 任一必需链路失败即回退 RR |
| P13-5 稳定性观察 | 用户取消等待期 | 保留观察记录作为审计,但不把固定时长的 24 小时观察继续作为关闭前置 | 长期健康观察迁移为 P13-6 的独立运维能力 |
| P13-6 RR 全量退役与阶段收口 | P13-C 已删除 RR omni 物料 | RR 路径不存在、Runtime 代理指向 102、公网 health、102 health、文档与脚本一致、全套 CI 通过 | 任一当前生产链路失败或文档/脚本仍依赖 RR 回退点时不得关闭 |
📍 执行位置与阶段关系
| 位置 | 当前职责 | 禁止事项 |
|---|---|---|
| 101 | 仓库、Git、CI、验收编排、哈希和文档同步 | 不运行第二套生产 OmniRoute |
| RR | 其他 7 个业务域名的共用回源网关、Runtime 私有代理、宿主机运维 | 不再有 omni 数据、包、service、vhost 或 cutover 回退点 |
| 102 | 当前唯一生产 OmniRoute、SQLite 写者、Provider/Combo/模型权威 | 不允许第二写者;不绕过官方包内容边界 |
| MM | 唯一公网 80/443 入口,omni 直连 102 | 面板 JSON 与渲染 conf 必须同步修改,不能只改渲染文件 |
| Runtime | 通过 RR 私有代理调用 102 | 不保存第二套 Provider 路由或凭据 |
102 私有入口为 agentmeshos-omniroute-edge.socket 与 agentmeshos-omniroute-edge-guard.service。入口监听 100.64.0.4:39200,转发到 127.0.0.1:39180;raw PREROUTING guard 只放行 RR 100.64.0.1 与 MM 100.64.0.6。101 负向连接超时,RR 与 MM 正向访问返回 200。
🧪 验收与回退
| 验收面 | 结果 | 现场证据 | 影响 |
|---|---|---|---|
| 最终快照与恢复 | 通过 | RR 官方备份 omniroute-backup-agentmeshos-p13-4-20260930T231204Z;一致性快照 snapshot_20260930T231257Z_p13-4-20260930T231204Z;Cloudreve AgentMeshOS-临时/P13-4/20260930T231204Z/ |
102 最终生产数据来自切换时刻快照 |
| 102 服务 | 通过 | 3.8.51、health healthy、MainPID 存在、NRestarts=0、systemctl --failed 为 0 |
目标运行态稳定 |
| 模型目录 | 通过 | /v1/models HTTP 200,models_count=92,Boss/Worker Combo 可见 |
正式 Combo 未因迁移丢失 |
| Boss Combo | 通过 | 命中 deepseek-ai/DeepSeek-V3,精确返回 P13_4_BOSS_OK,usage 存在 |
质量优先通道可用 |
| Worker Combo | 通过 | 首次空内容后重试命中 command-a-reasoning-08-2025,精确返回 P13_4_WORKER_RETRY_OK,usage 存在 |
容量池可用;健康观察继续统计上游空响应,但不再阻塞迁移关闭 |
| Codex Responses | 通过 | /v1/responses SSE 200,出现 response.completed;真实 function_call 为 get_status,参数 {"scope":"p13-4-final"} |
Codex 工具调用子路径可用 |
| 管理 API | 通过 | combos=19、api_keys=4;Boss fill-first、Worker least-used,两者均有 responseValidation |
路由策略与权限基线一致 |
| Runtime 健康 | 通过 | {"status":"ok","version":"v0.10.3","provider_core":"omniroute","omniroute_configured":true};容器 healthy、restarts 为 0 |
Runtime 未保留第二 Provider 路由 |
| SQLite 回读 | 通过 | quick_check=ok、provider_connections=70、combos=19、api_keys=4、迁移 193;日志和 usage 已回读 |
数据与调用事实可查 |
| 负向回归 | 通过 | 未授权 /api/keys、/api/combos 为 401;错误 Token 403;API 路径穿越 403;文件路径穿越 400;错误模型 400;101 访问 102 39200 超时、39180 拒绝 |
入口与鉴权边界有效 |
| RR 宿主卫生 | 通过 | Runtime 代理 active、NRestarts=0 且目标为 102;RR omni 数据、包、service、cutover 备份和 nginx vhost 均不存在;systemctl --failed 为空 |
迁移后无重复生产写者,也没有可误用的旧回退路径 |
| 102 edge FD 与连接上限 | 通过 | FD 软上限 65536、最大连接 4096;旧态 check 因软上限 1024 失败,新态通过;修复后 too_many_after_start=0 |
避免连接累积后接受请求却无法转发 |
首次 Worker Combo 检查曾命中 claude-sonnet-4.6 但正文为空;同 Combo 重试命中 command-a-reasoning-08-2025 并返回精确文本。该事实已保留,不把单次重试成功写成上游空响应永久消失;长期观察器继续统计同类空正文、Combo 回退和 usage 写入,但它不再阻塞本次迁移关闭。
🔁 回退与再次切换
真实回退与再次切换是 P13-4 的历史验收证据,证明 RR 回退点在删除前确实可用;P13-C 删除 RR 回退点后,该流程不再作为当前运行路径。执行顺序为:
- 102 停止 socket、edge 和 OmniRoute,生成清洁快照
snapshot_20260930T232400Z_p13-4-rollback-clean。 - 清洁快照为
151302144bytes,SHA-25663bc1deeefa5efba14316a3e099b5faf494f1a2d0074d3ff5d1d9bb35a0c7b60,经 Cloudreve 传到 RR。 - RR 生成
pre-restore_20260930T233116Z后恢复清洁快照并执行rollback;RR 本地127.0.0.1:39180恢复,公网 health200,真实调用返回P13_4_ROLLBACK_OK。 - RR 再次
freeze,生成回流快照snapshot_20260930T233238Z_p13-4-return-to-102,大小150237184bytes,SHA-2564f9553f84560205bc81417f14c5381cd311f95c74bb3a8356b97ce8a8fc97655。 - 102 生成
pre-restore_20260930T233320Z后恢复回流快照并重新启动;RR 再次activate,最终回源与 Runtime 代理恢复指向 102。
Cloudreve 回读路径为 AgentMeshOS-长期/P13-4-rollback-20260930T232400Z/snapshot-storage.sqlite 与 AgentMeshOS-长期/P13-4-return-to-102-20260930T233238Z/snapshot-storage.sqlite。RR WebDAV 凭据只在受控小文件通道临时用于 102 下载,随后已从 102 删除并验证 temp_credentials_removed=true;任何凭据内容未进入仓库、日志或普通回复。
🔍 根因、修复与防复发
🧩 sqlite3 缺失导致快照语义不完整
根因:102 初始没有 sqlite3,官方 snapshot-data.sh 无法执行 VACUUM INTO,退化为复制主库和 WAL;官方 restore-data.sh 恢复时只恢复主库并删除 WAL,因此调用日志类数据不能保证完整闭环。影响:如果继续在干净节点直接部署,切换快照的完整性会依赖未验证的复制行为。
修复:102 已安装 sqlite3 3.46.1-9ubuntu0.3。负向回归快照 snapshot_20260930T233525Z_p13-4-sqlite3-regression-retry 为 150228992 bytes、无 WAL、SHA-256 b9788f0801492bb296ba3e0750d6312513c4633d9894336610b5889157ddb8b0;隔离恢复后 SHA-256、quick_check、call_logs 和 usage_history 一致。部署脚本已升为 v0.1.1,preflight() 强制要求 sqlite3,并在 usage 中说明 VACUUM INTO 依赖。
🧩 Runtime 代理曾依赖 RR 本地 OmniRoute
根因:systemd 255 在当前主机上没有按预期用 drop-in 的空 Requires= / After= 清除原 unit 依赖。复现时单独重启 Runtime 代理会把 RR 本地 3.8.50 重新拉起,破坏“RR 只保留数据回退点”的边界。
修复:原始包外 unit 已备份到 /root/.omniroute-cutover-backups/agentmeshos-omniroute-runtime-proxy.service.original,SHA-256 35a99df108bfa8c0e96e6c212ebe13cbdc4049504a7583a1a9e540e0a2f9b52b;修复后的 unit SHA-256 d387eeac4db1a0983ab90b625f40f695c46fe9a4d692bd2e866017b3a758aa68。Runtime 代理的 Requires / Wants 现在都不包含 agentmeshos-omniroute.service,RR 本地 OmniRoute 为 inactive/dead/disabled,failed unit 为 0。
当时的切换脚本已升为 v0.1.1 并完成上述修复;P13-C 随后删除该脚本和 RR 原始 unit 备份,因为 RR 本地 OmniRoute 已不存在。当前 Runtime 代理 unit 保持无本机依赖,目标固定为 100.64.0.4:39200。
🧩 edge 代理 FD 软上限导致公网超时
根因:102 的 agentmeshos-omniroute-edge.service 虽然继承了较高的硬限制,但进程实际软上限仍是 1024。长期连接累积后,systemd-socket-proxyd 的 FD 数达到 1024,journal 持续输出 Failed to accept() socket, ignoring: Too many open files;监听和 TCP 建连仍成功,但已接受的请求无法转发,因此 RR 访问 100.64.0.4:39200 超时,MM 到 RR 的公网入口也超时。
修复:agentmeshos-omniroute-edge.sh 升为 v0.1.2,生成的服务显式使用 LimitNOFILE=65536:65536,代理启动参数增加 --connections-max=4096,并增加 Restart=on-failure。check 现在会读取 LimitNOFILESoft,低于 65536 直接失败;这与健康观察器的同类门禁形成双重检查。旧态负向回归中,使用 AGENTMESHOS_OMNIROUTE_EDGE_NOFILE_LIMIT=131072 check 能准确拒绝软上限不足的节点。
修复后证据:SERVICE_SOFT_NOFILE=65536、LimitNOFILE=65536、edge FD 数降到两位或三位、服务重启后 Too many open files 计数为 0;RR→102 health 和 Runtime 代理 health 均为 200,公网 health 恢复 200。这不修改 OmniRoute 包、数据库、MM 回源或 RR 回退 unit。
🧩 分布式底座接入声明
接入结论:P13 已接入 Network、Compute、Storage、Observability 和 Nomad 状态面;Nomad 只提供既有节点状态事实,不作为迁移执行器。
| 使用层 | P13 用途 | 边界 |
|---|---|---|
| Network | MM 公网入口、102 私有入口、Tailnet/UFW/raw guard 和 RR Runtime 本机代理 | 不把 Tailnet 当业务数据面,不扩大 102 监听 |
| Compute | 102 原生 Node、OmniRoute systemd、Docker/宿主依赖 | 不建立第二调度器或兼容运行目录 |
| Storage | 102 生产库、Cloudreve P13-4 恢复材料、审计归档和哈希 | 任意时刻只允许一个 SQLite 写者;RR 不再保存 omni 库 |
| Observability | health、模型、Combo、usage、日志、SQLite、负向测试 | 不导出正文、凭据或管理会话 |
| Nomad | 只核对既有 102 Client 状态 | 不提交迁移 Job,不承担迁移控制面 |
- Adapter 归属:继续使用现有
OmniRouteAdapter和官方 CLI/API,不新增第二套路由层。 - 执行映射:101 负责仓库、CI 和证据,RR 负责其他域名入口与本机 Runtime 代理,102 负责当前生产运行。
- 数据路径:完整数据和恢复材料经 Cloudreve 公网 HTTPS;控制小文件按受控例外处理。
- 凭据路径:Provider、OAuth、API Key、Runtime Key 和
.env只在 root-only 边界流转。 - 生命周期:P13-0 至 P13-4、P13-B、P13-C 和 P13-6 已先后完成;健康观察不设置阶段阻塞等待期,P13 已归档。
- 验收证据:切换材料、公网 health、模型、Combo、Responses、SQLite、负向回归、RR 退役路径检查和 systemd 状态。
💾 数据、凭据与回退边界
| 对象 | 当前状态 | 回退或保留策略 |
|---|---|---|
| 102 生产库 | /root/.omniroute/storage.sqlite,唯一写者 |
由健康观察器和独立备份流程持续检查完整性 |
| RR omni 数据与包 | 已删除(P13-C) | 不再保留 RR 回退点;恢复以 Cloudreve P13-4 快照和 102 重装为准 |
| RR 本机 service 与 cutover 脚本 | 已删除(P13-C) | 不得恢复 RR 本地 OmniRoute 或 freeze/activate/rollback 旧脚本 |
| RR origin gateway omni vhost | 已删除(P13-C) | RR 网关继续服务其他 7 个域名,不再生成 omni 上游 |
| MM 回源 | 面板 JSON 与渲染 conf 均为 100.64.0.4:39200 |
以后修改必须同时同步面板源与渲染配置,并执行 nginx -t |
.env 与 Provider 凭据 |
102 root:root 0600 |
不进入 Git、日志、模型上下文或普通回复 |
| discovery 能力 | RR controlled-discovery inactive、timer/service disabled | 当前没有 discovery 后端;如需恢复,另立 102 部署计划 |
任意时刻只允许一个 SQLite 写者。当前该写者是 102。RR 已无 omni 活库;历史恢复材料只在 Cloudreve 长期归档和审计包中保留,不再作为可随时切回的运行数据。
🚀 P13-5 取消与 P13-6 健康观察
用户明确取消 P13-5 的等待期和 RR 数据保留期,P13-5 不再以“观察满固定时长”或“RR 回退点持续存在”为出口。P13-6 保留了一个无阶段阻塞含义的健康观察器,用来持续发现 102、公网入口或 RR 退役边界的真实退化;该观察能力在归档后仍独立运行。
🔧 自动观察机制
101 已安装 agentmeshos-omniroute-health-observation.timer,每 15 分钟执行只读观察脚本,记录写入 /srv/codex-hub-backup/agentmeshos/omniroute-health/observations/,最新记录软链接为 /srv/codex-hub-backup/agentmeshos/omniroute-health/latest.json。脚本路径为 scripts/maintenance/agentmeshos-omniroute-health-observation.py,安装入口为 scripts/maintenance/agentmeshos-omniroute-health-observation-install.sh。旧 omniroute-p13-5 timer 已停用并删除,历史观察记录保留在原目录。
新观察器首个通过记录为 20261001T022814Z.json,状态 pass、critical=0、warnings=0。记录包含 102 版本、服务、edge FD/连接上限、资源、SQLite 完整性和计数、RR omni 退役路径、RR Runtime 代理目标、failed unit 与公网 health。依据是 ExecMainStatus=0 和文件内容回读;影响是后续健康趋势可查,但不再要求等待固定观察期才能关闭 P13。
| 观察项 | 必须记录的证据 | 失败或触发条件 |
|---|---|---|
| 102 服务稳定性 | health、MainPID、NRestarts、failed unit、edge FD 软上限与当前 FD 数、资源与内存峰值 |
多次重启、OOM、SQLite 错误、FD 上限退化或健康中断 |
| 模型与 Combo | Boss/Worker 真实调用、空响应重试、Provider 故障、usage 与日志回读 | 同类空正文持续出现、Combo 权限漂移或费用异常 |
| Codex Responses | SSE、tools、function call、超时与上游中断 | response.completed 缺失或工具调用不可执行 |
| 恢复能力 | Cloudreve 的 P13-4 快照可读、102 可原生重装、恢复步骤有记录(RR 回退点已在 P13-C 退役) | 快照丢失或 102 无法重装 |
| 资源边界 | 102 根盘、内存、swap、cgroup、SQLite 大小增长 | 超过安全余量或影响其他节点服务 |
| discovery 能力 | 明确保持关闭或单独立项恢复 | 不得用旧 RR 本地数据假装新后端可用 |
| RR 退役边界 | 数据、包、service 和 cutover 备份不存在;Runtime 代理 active 且目标为 102;origin gateway 无 omni vhost | 任一 RR omni 运行残留重新出现,或 Runtime 代理重新依赖本机 unit |
P13-6 阶段出口已经满足:102 当前健康且无重复写者;MM 面板源与渲染 conf 都直连 102;RR omni 数据、包、service、回退备份和 vhost 均不存在;RR Runtime 代理仍可访问 102;公网 health 200;健康观察器 pass;文档、脚本、Git 和 CI 状态一致;discovery、媒体、语义缓存和日志正文导出明确保持关闭或另立计划。因此 P13 已转为完成归档,没有另设等待期。
⚠️ 未决项 / 需要用户决策
| 事项 | 当前事实 | 需要用户决定或后续动作 |
|---|---|---|
| RR 数据退役 | 已完成(P13-C):已删除,RR 不再有回退点 | 恢复改用 Cloudreve P13-4 快照与 102 重装 |
| P13-B 面板配置源 | 宝塔面板反代目标存储在 /www/server/proxy_project/sites/omni.yohan.fun/omni.yohan.fun.json,与渲染 conf 是两个存储 |
已同步为 100.64.0.4:39200;以后凡改面板管理的反代,必须同时改面板 JSON 与渲染 conf |
| cutover 脚本边界 | 已退役(P13-C):agentmeshos-omniroute-cutover.sh 已删除 |
公网路径回退改由 MM 侧决定,不再依赖 RR 脚本 |
| RR origin gateway omni 死配置 | 已删除(P13-C):生成脚本 v0.6.2 不再生成 omni vhost,RR 网关 omni 计数为 0 |
无;其余 7 个服务回归通过 |
| RR Runtime 私有代理 | 已决定保留:RR 本机 AI Runtime 容器在用,监听 172.30.70.1:39181、上游 100.64.0.4:39200 |
保留本地代理(比容器直连更灵活,实测两者都通) |
| discovery 能力 | RR controlled-discovery 已停用,切换后没有后端 | 保持关闭,或另立 102 discovery 部署评估 |
| 新版本可选能力 | 媒体、语义缓存、日志正文导出未启用 | 按收益、隐私、资源和回滚条件逐项评审 |
| Worker 空响应 | 首测一次命中 claude-sonnet-4.6 但正文为空,重试成功后通过 |
健康观察继续统计;若持续出现,作为 OmniRoute 运维问题处理,不再阻塞 P13 迁移关闭 |
| 101/Home Codex 可用性 | 默认 Codex 会话不由 OmniRoute 承载;切换或回退演练期间只有经 OmniRoute 的模型、MCP、搜索、图片和 Runtime 调用短暂中断 | 后续维护窗口需继续按同一边界通知,不能把默认 Codex 会话与 OmniRoute 通道混为同一可用性 |
| 持续健康观察 | 101 timer 每 15 分钟记录一次;最新实时复核为 pass |
异常按运维事件处理;若出现重复写者或 102 生产中断,按新的运维事件修复,不重新打开 P13 |