- 权限最小化
- Web 服务器是较为可信的
- Web 服务器可以访问所有重要资源
- Web 服务器不能直接处理用户上传的文件,而应该交给调度机
- 调度机在中间
- 调度机不能访问主数据库,但是可以随意访问 s3
- 评测机是不可信环境
- 评测机只能访问传给它的 URL 里的文件
- 评测机执行外部命令必须经过沙箱
- Web 服务器是较为可信的
- 评测并行化
- 评测任务细分
- 每次只评测一个最小单元而不是一整道题
- 评测可中断
- 防止长时间评测任务 (e.g. 火车票) 无法打断造成资源浪费
- 合理使用数据服务
- 文件存 s3,数据存 SQL,临时数据存 Redis
- 大文件直接传 (Signed) URL
- 管理员上传/下载题目 zip 不经过 web,直接传 s3
- 代码也存在 s3 上面,以后可以让用户把代码直接传到 s3,不经过 Web
- Use case: 提答题
graph TD
subgraph Web
WS[Web server]
end
subgraph Scheduler
SC[scheduler2 server]
end
subgraph Runner 1
J1[judger2 instance 1]
end
subgraph Runner 2
J2[judger2 instance 2]
end
subgraph Data Services
MY[(MariaDB)]
R0[(Web Redis)]
R1[(Judger Redis)]
S3[(S3 Storage)]
end
SC --- S3
J1 --- S3
J2 --- S3
User --- WS
User --- S3
WS --- S3
WS --- MY
WS --- R0
SC --- R1
J1 --- R1
J2 --- R1
WS --- SC
- Web 模块: 处理所有用户操作, 并交给对应模块 (参见 Web 文档);
- Scheduler 模块: 规划评测相关事务 (参见 Scheduler 文档);
- Judger 模块: 执行评测任务 (参见 Judger 文档);
- Redis: 用于辅助各模块间的通信, 充当缓存数据库 (参见 Redis 文档);
- S3: 用于存储各模块间的数据, 充当文件服务器 (参见 S3 文档);
sequenceDiagram
participant Admin
participant User
participant S3
participant Web
participant Scheduler
participant Redis
participant Judger1
participant Judger2
break Initialization
Judger1 ->> Redis: Listen for tasks.
Judger2 ->> Redis: Listen for tasks.
end
break Data upload
Admin ->> Web: Gimme zip upload URL for 1001.
Web ->> Admin: OK, https://acm.sjtu.edu.cn/oj-problems/1001.zip?signature=xxx
Admin -> S3: PUT /oj-problems/1001.zip?signature=xxx
Admin ->> Web: Let's update judge plan for 1001.
Web ->> Scheduler: Update judge plan for 1001.
Scheduler -> S3: GET /oj-problems/1001.zip
Scheduler -> S3: PUT /oj-problems/plan/1001.json
Scheduler -> S3: PUT /oj-problems/1001/1.in
Scheduler -> S3: PUT /oj-problems/1001/1.ans
Scheduler ->> Web: OK.
Web ->> Admin: OK.
end
break Submit code
User ->> Web: Submit code for 1001.
Web -> S3: PUT /oj-submissions/1926.code
Web ->> Scheduler: Schedule submission 1926.
Scheduler -> S3: GET /oj-problems/plan/1001.json
Scheduler ->> Redis: Put task 84d1d91d.
Scheduler ->> Redis: Listen task 84d1d91d.
Scheduler ->> Web: Scheduled.
Web ->> User: OK.
end
break Judge
Redis ->> Judger1: Task 84d1d91d.
Judger1 -> S3: GET /oj-submissions/1926.code
break If abort
User ->> Web: Abort 1926.
Web ->> Scheduler: Abort 1926.
Scheduler ->> Redis: Abort 84d1d91d.
Redis ->> Judger1: Abort 84d1d91d.
end
Judger1 -> S3: PUT /oj-artifacts/1926/a.out
Judger1 ->> Redis: Task 84d1d91d done.
User ->> Web: What's the status of 1926?
Judger1 ->> Redis: Listen for tasks.
Web ->> Scheduler: What's the status of 1926?
Scheduler ->> Web: It's compiling.
Redis ->> Scheduler: Task 84d1d91d done.
Scheduler ->> Redis: Put task 1c1e11d0.
Scheduler ->> Redis: Listen task 1c1e11d0.
Redis ->> Judger2: Task 1c1e11d0.
Judger2 -> S3: GET /oj-artifacts/1926/a.out
Judger2 -> S3: GET /oj-problems/1001/1.in
Judger2 -> S3: GET /oj-problems/1001/1.ans
Web ->> User: It's compiling.
User -> S3: GET /oj-submissions/1926.code?signature=xxx
Judger2 ->> Redis: Task 1c1e11d0 done.
Judger2 ->> Redis: Listen for tasks.
Redis ->> Scheduler: Task 1c1e11d0 done.
Scheduler -> S3: DELETE /oj-artifacts/1926/a.out
Scheduler ->> Web: 1926 done.
end
break Query result
User ->> Web: What's the status of 1926?
Web ->> User: It's accepted.
User -> S3: GET /oj-submissions/1926.code?signature=xxx
end
- Web server
- s3
- s3 需要可以通过内外网两个接口访问
- 外网接口的用途
- 查看代码
- 上传/下载题目 zip
- 上传/查看图床图片
调度机和评测机都有两个和配置相关的文件, 分别是
{scheduler,runner}.yml
和 config.py
. yml
文件是不纳入
git 版本管理的, 是每台调度机/评测机独有的配置, 更改网络结构时,
从设计上来说应该只更改 yml
文件即可, 不用更改代码; 而 py
文件的作用是读入 yml
文件, 以及记录业务逻辑上的常量 (如
heartbeat 间隔时间、任务超时时间等) 等每台调度/评测机相同的参数,
或者应该纳入版本控制的参数, 但不应记录密钥、密码、access key
等敏感内容.
- Asyncio 指南: judger & scheduler 异步编程指南
- sandbox 文档: judger 沙箱