Files
DCTS/docs/architecture.md
T
fmq d16b3d3cdc feat(all): 数据库模块化拆分与版本化迁移、任务引擎命名体系收敛、物理输出校验加固与用户配置接通
- server/db: 拆 4929 行 db.rs 单体为 db/ 目录,migrations.rs 引入 PRAGMA user_version
    版本化迁移运行器(M1~M13)
  - 任务引擎 Phase 6/7b/7c 改名收敛:EngineStageConfig→PhaseConfig、StagePolicy→ResumePolicy、
    Converged→Completed、删除 task_type 列、success_method 拆 tlusty_/synspec_ 双列、
    新增 tlusty_status/synspec_status 半失败阶段守卫
  - 科学正确性加固:conv_check 任意行 NaN/Inf/溢出判无效(0 行容忍)、新增 spec_is_valid
    校验 SYNSPEC 脏谱、itek_history 逐次迭代全量保真、fmt_abn powf 溢出饱和
  - 用户配置真正接通:tlusty_chain/tlusty_input 由死字段经 调度器→TaskSpec→executor→runner
    透传生效;config 加载期 validate + deny_unknown_fields + 解析失败记 warn
  - 调度修复:H1 活锁(pending_strategies 跳过已失败策略)、种子查找错误不再静默降级冷启动
  - dashboard: 阶段配置面板 tlusty_stage/synspec_stage、"已完成"标签、迭代诊断展示
  - docs: 新增 database_refactor_design.md,同步 database/api/PIPELINE/workflow_detail
2026-08-06 20:51:21 +08:00

154 lines
9.8 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.
# DCTS 系统架构 (System Architecture)
> 介绍 DCTS (Distributed Computing TLUSTY/SYNSPEC) 的整体设计架构、Master-Worker 拓扑结构、任务生命周期流转及容错机制。
---
## 1. 架构拓扑 (Topology)
DCTS 采用**中心化控制、分布式离散执行 (Master-Worker)** 的拓扑设计:
```mermaid
flowchart TB
subgraph Master Node ["Master 服务端 (server)"]
API["Axum HTTP REST API"]
DB[(主数据库 dcts.db)]
MQ[(任务队列 dcts_queue.db)]
Scheduler["Grid Scheduler 网格调度器"]
SeedsStorage["本地种子库 seeds/*.7"]
API <--> DB
API <--> MQ
Scheduler --> MQ
Scheduler --> DB
end
subgraph Compute Nodes ["分布式计算节点集群 (node)"]
Worker1["Worker 节点 1 (Node Daemon)"]
Worker2["Worker 节点 2 (Node Daemon)"]
WorkerN["Worker 节点 N (Node Daemon)"]
end
Worker1 -- "1. 心跳/抢占任务 (Claim)" --> API
Worker1 -- "2. 下载种子/基础数据" --> API
Worker1 -- "3. 汇报结果/上传 .7 大气" --> API
Worker2 -- "免凭据注册申请 / 审批后心跳" --> API
WorkerN -- "免凭据注册申请 / 审批后心跳" --> API
API --> SeedsStorage
```
---
## 2. 核心组件职责
### 2.1 Master 服务端 (`server` & Web `dashboard`)
- **工作流与多任务隔离**:支持多工作流并发隔离运行(`grid_points``task_queue` 增加 `workflow_name` 复合唯一索引),调度与重置操作严格隔离在单工作流作用域内。支持旧版 SQLite 数据库启动时无缝平滑迁移。
- **安全中间件与 RBAC**:基于角色访问控制 (Admin / Node / Public) 划分 API 权限,内嵌 Bearer Token 校验、**滑动窗口(sliding window)限流中间件**与 CORS 跨域控制,防御侧信道攻击与暴力破解。
- **节点凭据生命周期管理**:支持 Worker 节点注册申请、管理员审批授权、Token 重新颁发(旧 token 失效)与节点停用/启用全生命周期管理。
- **任务调度与分配**:调度器将 pending 网格点推入 `mq` 队列;Worker 以 **pull 抢占式** 领用任务(详见 [§5 任务调度模型](#5-任务调度模型-task-scheduling))。
- **状态维护与心跳监测**:后台离线检测线程定期标记超时未心跳的节点为 `offline`,并能将僵挂在超时节点上的任务自动回收到队列中(Requeue)。
- **ESM 模块化 Web 看板**:前端采用 ESM 模块解耦设计(`state.js`, `api.js`, `components/`),支持节点凭据管理、工作流控制与全局 Toast 通知。
### 2.2 Worker 计算节点 (`node`)
- **身份标识**`DCTS_NODE_ID` 未指定或为空时,自动生成基于随机 UUID 的节点 ID(`node-<uuid>`)。Worker 是计算服务,每个物理设备部署一个 node 进程(多 slot 并行由 `DCTS_MAX_SLOTS` 控制),无需在同一设备运行多副本。
- **环境自适应预热 (Bootstrap)**:启动时核对本地 `./runtime` 运行依赖,缺失时自动向 Master 拉取可执行文件与二进制数据。
- **任务抢占与执行 (Claim & Execute)**:根据并发配置轮询抢占任务,调用 `common` 启动子进程链(tlusty / synspec)。
- **种子检索与回传 (Seed Sync)**:计算成功后将收敛的大气结构文件(`.7`)与状态 JSON 汇报回服务端。
---
## 3. 任务生命周期 (Task Lifecycle)
网格计算点从创建到完成的状态流转如下图所示:
```mermaid
stateDiagram-v2
[*] --> Pending : 工作流注册生成网格点
Pending --> Queued : 调度器推入 mq 队列
Queued --> Running : Worker 成功 Claim 抢占
state Running {
[*] --> ExecutingChain
ExecutingChain --> ColdStartChain : 默认冷启动 (lte->nc->nl)
ColdStartChain --> Synspec : 物理收敛
ColdStartChain --> SeedStepChain : 冷启动发散且有可邻近种子
SeedStepChain --> Synspec : 热启动收敛
}
Running --> Converged : 计算成功 & 上传 .7 产物
Running --> Pending : Worker 心跳超时/掉线 (Requeue, 直接回 Pending 等待重新派发)
Running --> Failed : 无可邻近种子回退 / 彻底发散
Converged --> [*]
Failed --> [*]
```
> 状态值与 [`GridPointStatus`](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/common/src/models.rs#L237) 一一对应:
> `pending` → `queued` → `running` → `completed` / `failed``completed` 由 7c 改名自 `converged`,旧值仍作兼容别名解析)。
> Requeue 把 `running` 直接重置回 `pending`(不经过 `queued`),由调度器下一轮重新推入队列。
---
## 4. 容错与高可用设计 (Fault Tolerance)
1. **分布式无状态 Worker & 上报阶梯退避**:Worker 节点不保存持久运行控制状态,异常宕机不会损坏主数据集。计算结果向 Master 上报时,具备多达 8 次指数阶梯容灾回退(最大间隔 60 秒,覆盖超 2 分钟断断连长窗),稳健保障长时间高密物理算单不受瞬时组网闪断或服务端短时上线切换干预。
2. **零文件扫描与连接并发缩流**:底层任务分批取配、排队清洗与邻接优化(Seed-Stepping)全链线依赖常驻内存的 SQlite 主从精算并调优收敛连接池配置(主库=8,队列=4 减免本地排他写冲突并发挂断);去除了历史残存的高损及同步阻塞磁盘遍历 API,在确保零卡死响应的前提下提升查询搜索效力。
3. **任务超时与流控平稳保护 (Stale & Requeue)**:服务端后台定期向已超时死挂的 `Running` (默认 >1800 秒)作业予以强退回转为 `Pending`;此外当操作维护员发起暂停或终止工作流行为时,将仅平滑洗退待调 `Queued` 项,悉心保育在途已投的 Worker 数值演算完整出计算归表,防假命题竞合。
4. **策略链回退与种子匹配**:若某点当前策略失败,服务端弹出策略链首项(`trigger_strategy_fallback`),下一顺位为 `seed_step` 时在全局种子库中按**有向 CNO 距离**(富方向重罚 4×、贫方向 1×,非对称)匹配最近邻收敛 `.7` 大气作为热启动种子;无种子则保持 pending 待种子出现后自愈。失败现场经**白名单归档**(`result_dir`)保留科学产物,沙盒则在任务结算后清理(详见 `tlusty_result_artifacts.md` / `design.md`)。
---
## 5. 任务调度模型 (Task Scheduling)
### 5.1 Pull 抢占式模型(非服务端负载分发)
DCTS 的任务分发是 **Worker 主动拉取(pull** 模型,**不是**服务端按节点负载推派(push):
- **调度器**[`schedule_pending_tasks`](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/server/src/scheduler.rs#L153))只负责把 `pending` 网格点推入 `mq` 队列(`push_task`),不参与"分给哪个 node"的决策。
- **Worker**[领用主循环](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/node/src/worker.rs#L275))只要 `active_slots < max_slots`,就持续向服务端发起 `claim` 请求抢任务。
- **服务端** [`pop_task`](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/mq/src/sqlite_queue.rs#L145) 的出队决策**只看任务自身属性**,不看谁来领用:谁先抢到写锁、谁就拿到队首任务。
出队排序(难度优先 → 同难度先进先出):
```sql
SELECT task_id, payload FROM task_queue
WHERE status = 'pending'
ORDER BY wave ASC, created_at ASC
LIMIT 1
```
### 5.2 为什么不做服务端负载分发
关键观察:**Worker 满载后会主动停止领用**([worker.rs](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/node/src/worker.rs#L280-L281)):
```rust
let active = self.active_slots.load(Ordering::Acquire);
if (active as usize) < self.effective_max_slots.load(Ordering::Acquire) {
match self.claim_task().await { /* 抢任务 */ }
} else {
sleep(Duration::from_secs(2)).await; // 满载:不 claim,等槽位释放
}
```
> `effective_max_slots` = `min(admin_max_slots, physical_max_slots)`,管理员配额经心跳响应下发、动态生效(见 `dynamic_cpu_slots_design.md`)。
由此分两种工况:
| 工况 | 条件 | 是否会扎堆 | 负载分发是否需要 |
|------|------|-----------|-----------------|
| **稳态** | 任务数 ≥ 所有 node 总槽位 | 否——各 node 抢满 `max_slots` 即停止 claim,空出槽位者再去抢,**天然均衡** | 不需要 |
| **稀疏态** | 任务数 < 总槽位(如调试用 2 个点) | 是——最快的 node 连续抢光少量任务 | 收益极小,省的仅是几个任务的串行墙钟时间 |
稳态(网格规模任务,如 sdB_cno 的 432 点)是实际生产场景,该场景下 pull 模型已自动达成负载均衡。稀疏态的扎堆是固有现象且代价可忽略(任务跑完即结束)。
引入服务端负载分发的**代价**反而更高:破坏 FIFO 可预测性、带来心跳负载数据滞后导致的退让抖动、增加队首饥饿风险。综合权衡,**当前 pull 模型是刻意选择,无需改为服务端负载分发**。
> **稀疏态调试建议**:若调试时确实希望任务分散到多个 node 观察,最省事的做法是把各 node 的 `DCTS_MAX_SLOTS` 设为 `1`——每个 node 抢 1 个即满载停止,自然分散,零代码改动、零风险。
### 5.3 出队优先级语义(wave + FIFO
- **`wave ASC`(难度优先)**:网格点按 CNO 丰度之和(`cno_sum`)升序分组,低丰度(低难度、更易收敛)的点先出队。设计意图是"先易后难"——先跑出收敛点作为种子库,后续高难度点可借热启动种子收敛。
- **`created_at ASC`(同难度 FIFO**:同一 `wave` 内严格按推入队列的时间先后出队。
- **跨工作流公平**:出队不按 `workflow_name` 分组,多个并发工作流的低难度点会先于任何工作流的高难度点出队,避免某工作流在高难度 wave 上饿死其他工作流的低难度点。