refactor(判题机): 换成 go-judge,空闲内存从几百 MB 降到 16 MB

原来的 JudgeServer 按核数起 gunicorn worker、每份提交再按核数开进程池,空闲内存跟着核数走
(2 核 52MB、16 核 305MB)。换成 go-judge 后空闲 16MB,同一批提交判题中 80–100MB(原来约 370MB)。

go-judge 只管在沙箱里跑命令,编译、逐点运行、比对输出、定状态码搬到 judge/sandbox.ts,
口径逐条照搬 JudgeServer,出参形状不变。拿生产库真实提交新旧逐点对比:C 2000 份 1989 一致、
C++ 891 份 890 一致、Python 2000 份全一致;不一致的是 system("pause")(现在不再判运行时错误)、
未定义行为、endl 死循环打印(运行时错误变运行超时),见 docker/judge/README.md。

- 判题容器改成 privileged(go-judge 要自己建 cgroup),镜像 oj2-judge-3
- 心跳改由 worker 每 5 秒问判题机 /version 代记,删掉 /api/judge-server/heartbeat
- 前端统一用 stripJudgePath 去掉判题机工作目录(新的 /w/ 和旧的 /judger/run/)
- 提交前编译检查只编译不运行

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-26 15:03:57 +08:00
1 parent 8427475337
commit 37e971b6b4
30 files changed
+881 -592

No files matched your search

+8 -18
View File
@@ -87,33 +87,21 @@ services:
retries: 10
oj-judge:
# 自己构建的判题沙箱(上游 JudgeServer 1.6.1 + 新工具链,见 docker/judge/)。
# 上游停更在 2024-04,registry 上的 1.6.1 == latest,没有新版可拉。
# 自己构建的判题沙箱(go-judge + gcc / python,见 docker/judge/)。
# ⚠️ 这个 tag 不在任何 registry 上:本机 docker/judge/build.sh 构建,
# 服务器/机房用 docker load 装。镜像不在本地时 compose 会去 pull 然后报找不到。
image: oj2-judge-2
image: oj2-judge-3
container_name: oj-judge
restart: always
read_only: true
cap_drop:
- SETPCAP
- MKNOD
- NET_BIND_SERVICE
- SYS_CHROOT
- SETFCAP
- FSETID
# go-judge 要自己建 namespace 和 cgroup 来关学生程序,只能给特权,理由见 docker/judge/README.md
privileged: true
# go-judge 的文件存储(编译产物、程序输出)放这里,见 docker/judge/Dockerfile 的 -dir
tmpfs:
- /tmp
volumes:
- ${DATA_DIR:-../data}/backend/test_case:/test_case:ro
# 判题机的运行状态目录,默认跟着 DATA_DIR 走
- ${JUDGE_STATE_DIR:-${DATA_DIR:-../data}/judge_server}/log:/log
- ${JUDGE_STATE_DIR:-${DATA_DIR:-../data}/judge_server}/run:/judger
environment:
SERVICE_URL: http://oj-judge:8080
# 心跳路径跟着新后端改了:judge_server_heartbeat/ → judge-server/heartbeat
BACKEND_URL: http://oj-api:3000/api/judge-server/heartbeat
TOKEN: ${OJ2_JUDGE_TOKEN:?请在 docker/.env 里设置 OJ2_JUDGE_TOKEN}
ES_AUTH_TOKEN: ${OJ2_JUDGE_TOKEN:?请在 docker/.env 里设置 OJ2_JUDGE_TOKEN}
# 同一时刻最多六份在编译(正式判题 2、试运行 2、提交前编译检查 2),g++ 编一份 iostream
# 峰值约 70MB、bits/stdc++.h 约 195MB,再加学生程序本身。512m 不够撑满,超了是容器里
# 随机杀进程、学生看到系统错误
@@ -144,6 +132,8 @@ services:
REDIS_URL: redis://:${REDIS_PASSWORD:?请在 docker/.env 里设置 REDIS_PASSWORD}@oj-redis:6379
JUDGE_SERVER_URL: http://oj-judge:8080
JUDGE_SERVER_TOKEN: ${OJ2_JUDGE_TOKEN:?}
# 后台「判题机列表」里这一台的名字(worker 替判题机记心跳,见 judge/heartbeat.ts)
JUDGE_SERVER_NAME: 服务器
JUDGE_CONCURRENCY: ${JUDGE_CONCURRENCY:-2}
TRIAL_CONCURRENCY: ${TRIAL_CONCURRENCY:-2}
AI_KEY: ${AI_KEY:-}