Judge0 1.13.1 介绍与选型指南

Judge0 1.13.1 介绍与选型指南:REST 代码执行引擎定位、Rails+PostgreSQL+Redis+isolate 四层架构、47 种语言与同步/异步/批量/回调提交、与 Piston/OnlineJudge/HUSTOJ/CodeBox 逐维对比、适用边界(isolate 不是逃逸防护),含最小可用部署与 curl 实测回显。

Judge0Judge0代码评测REST APIRubyPostgreSQL2026/10/27

Judge0 1.13.1 介绍与选型指南

目标:把 Judge0 1.13.1 这套开源自托管在线代码执行系统讲清楚,帮助你在「引入一个在线判题 / 代码运行服务」这件事上做出选型判断。本文说明它的定位、四层架构(Rails API + PostgreSQL + Redis 队列 + isolate 隔离执行)、核心特性与 API 形态,给出可复制的最小可用验证过程,并把 Judge0 与 Piston、QingdaoU OnlineJudge、HUSTOJ、CodeBox 放在同一张表里逐维对比,最后明确它「能干什么、不能干什么」——尤其是不要把 isolate 当成抵御恶意代码逃逸的安全边界。文中版本信息、仓库活跃度与快速开始回显分别采自 2026-10-27 的 GitHub API 查询与本地 1.13.1 实例实测。

一、环境信息

本篇的实证环境如下,读者复现时替换为自己的取值即可:

项目值
操作系统Ubuntu 22.04.5 LTS(x86_64)
实测版本Judge0 CE 1.13.1(GitHub Release v1.13.1,2024-04-18 发布)
运行时Ruby 2.7.0 + Rails 5.0.x + Puma 4.3.5 + Resque 2.0
数据库PostgreSQL 16.2(官方编排给出的配套版本)
队列Redis 7.2.4
隔离执行isolate(IOI 官方沙箱,随镜像编译)
服务端口2358(容器内),本文实测映射到宿主机 8138
许可证GPL-3.0

💡 说明:Judge0 的版本号长期停留在 1.13.x(1.13.0 为 2021-03-10,1.13.1 为 2024-04-18),仓库 2026-10-18 仍有提交,但没有新的 release 发布。选型时要把「功能版本停滞」与「仓库仍在维护」这两件事分开看,详见第六章。

二、软件概述

2.1 定位:不是 OJ 网站,而是 OJ 背后的执行引擎

Judge0 是一个在线代码执行系统(online code execution system),对外只暴露 REST API:你提交「源码 + 语言 ID + stdin」,它返回「stdout/stderr + 退出状态 + 耗时 + 内存」。它不提供题库、比赛、排行榜、用户体系,这些属于上层 OJ 的职责。

这一定位决定了它的两个典型用法:

  • 作为判题后端:上层 OJ/教学平台/面试系统自己管题目与用户,把「跑一次代码」这件事委托给 Judge0;
  • 作为代码运行沙箱服务:在线 IDE、文档站的可运行示例、AI Agent 的代码执行工具,直接调用 /submissions 拿运行结果。

2.2 版本与发行版

发行版说明当前版本发布形态
Judge0 CE社区版,本专栏对象,功能完整、开源免费1.13.1GitHub Release v1.13.1 + Docker Hub judge0/judge0:1.13.1
Judge0 Extra CE社区增强版,额外包含更多语言与部分商业版特性1.13.1GitHub Release v1.13.1-extra
Judge0 商业版官方托管的 SaaS/私有部署授权以官网为准需购买,本文不涉及

两个 CE 版本的代码同源,-extra 额外打包了一批语言运行时与编译器。本文全部实测基于 1.13.1(非 extra)。

2.3 项目活跃度(2026-10-27 实查)

指标值取数口径
GitHub 仓库judge0/judge0API /repos/judge0/judge0
Star / Fork4492 / 944同上
未关闭 Issue200同上
最近一次代码推送2026-10-18pushed_at
最近一次 Release2024-04-18(1.13.1)/releases
许可证GPL-3.0license.spdx_id

解读:代码在动、发版不动。近两年半的提交以文档、依赖修补、CI 为主,功能面基本冻结。对内部平台这是可接受的稳定状态;对需要长期跟进安全补丁的对外服务,就要评估自行维护分支的成本,且 GPL-3.0 意味着二次分发有开源义务。

三、核心架构

3.1 四层组件与数据流

Judge0 是标准的「Web 层 + 关系库 + 消息队列 + 执行器」结构,四层各司其职:

层组件职责关键点
接入层Rails 5 API(Puma)接收 HTTP、参数校验、写库、返回结果单进程多线程,RAILS_MAX_THREADS 控制并发
存储层PostgreSQL存 submission 全量记录、语言表、状态表submission 是唯一事实来源,队列只存「待办 ID」
队列层Redis + Resque存放待执行任务、worker 心跳与队列长度提交先落库再入队,服务重启不丢任务
执行层Resque worker + isolate取任务、在隔离环境里编译运行、回写状态每个 worker 串行执行一个 submission

一次异步提交的完整链路:

client ──POST /submissions──▶ Rails API
                               │ 1. 校验语言/参数,写入 submissions 表(status=1 In Queue)
                               │ 2. Resque.enqueue(submission_id) ──▶ Redis 队列
                               ▼
                        Resque worker ──▶ 取出 submission_id
                               │ 3. 从 PostgreSQL 读源码,准备 isolate 沙箱目录
                               │ 4. isolate 内编译(编译型语言)+ 运行,采集 stdout/stderr/耗时/内存
                               │ 5. 回写 submissions 表(status=3/4/5/6/7…)
                               ▼
client ──GET /submissions/{token}──▶ 读到最终状态;或第 5 步后由服务端回调 webhook

💡 技术拓展:在线代码执行系统的隔离手段不止一种,选型时这是最该看的一列——

隔离机制代表实现特点取舍
isolate(cgroup + namespace + seccomp)Judge0、Codeforces 系轻量、启动毫秒级、按提交限 CPU/内存/进程数依赖宿主机内核特性,需特权/委派 cgroup
Linux 容器(LXC/Docker)Piston生态成熟、镜像即语言包每提交起停开销大,隔离粒度受容器配置影响
gVisor / Kata商业多租户执行平台用户态内核或轻量 VM,隔离强资源开销大,语言运行时兼容性要逐个验证
整机/VM 池部分竞赛平台最强隔离成本高、调度复杂

Judge0 采用 isolate:单次提交在一个受限的进程组里编译运行,CPU/内存/进程/文件大小全部由 cgroup 与 rlimit 约束,启动开销低,适合高并发短任务;代价是必须让执行进程拥有足够的宿主权限(官方编排直接给 privileged: true)。

3.2 为什么必须 privileged(以及它意味着什么)

isolate 要创建 cgroup、挂载 namespace、设置 rlimit,普通容器权限不足时会直接报错。官方 docker-compose.yml 里 server 与 workers 两个服务都写了 privileged: true,这不是偷懒,而是 isolate 的工作前提。

对选型的含义很直接:Judge0 的执行节点等于「把你的内核能力交给它」。所以正确做法是把执行节点放在独立的内网主机/独立 VM,只让 API 层对外,绝不能让执行节点直接暴露公网,也不能与业务数据同机混跑。

3.3 提交状态机

Judge0 用数字状态码表达一次提交的生命周期,GET /statuses 返回全量:

ID状态含义
1In Queue已入库,等待 worker
2Processingworker 正在编译/运行
3Accepted正常退出(退出码 0)
4Wrong Answer仅当配置了 expected_output 比对时出现
5Time Limit Exceeded超 CPU/墙钟限制
6Compilation Error编译失败
7Runtime Error (SIGSEGV)段错误
8Runtime Error (SIGXFSZ)超出文件大小限制
9Runtime Error (SIGFPE)算术异常
10Runtime Error (SIGABRT)abort
11Runtime Error (NZEC)非零退出码
12Runtime Error (Other)其他信号
13Internal ErrorJudge0 自身异常
14Exec Format Error可执行格式错误

前端/上层平台只需把 1、2 当作「进行中」,3 当作通过,其余按失败分类展示即可。

四、功能特性

4.1 语言支持

GET /languages 返回当前实例可用语言清单,每条含 id(提交时用的数字)、name、version、source_file、compile_cmd、run_cmd 等字段。社区版镜像预置了主流语言(C/C++、Java、Python、Go、Rust、Node.js、PHP、Ruby、C#、Kotlin、Swift、SQL 等),实测语言条目数量见第五章快速开始的 /languages 回显。

新增语言不需要改 Judge0 代码:在 languages 表插入记录并保证执行节点里有对应运行时即可,这也是它常被用作「通用代码运行服务」的原因。

4.2 提交方式:同步、异步、批量、回调

同一套 /submissions 端点通过参数切换四种取结果方式,覆盖不同集成场景:

方式用法适用场景代价
异步POST /submissions 拿 token,再轮询 GET /submissions/{token}默认方式,客户端可自由控制节奏需要自己实现轮询
同步POST /submissions?wait=true交互式运行、简单脚本请求会被占住直到出结果,受 ENABLE_WAIT_RESULT 开关约束
批量POST /submissions/batch + GET /submissions/batch?tokens=...一次跑多语言/多用例单批上限 MAX_SUBMISSION_BATCH_SIZE(默认 20)
回调提交时带 callback_url无公网轮询能力的服务端目标地址必须可达,有重试与超时(默认 3 次 / 5 秒)

4.3 资源限制与限流

限制分两层:

  • 单次执行限制:CPU_TIME_LIMIT(默认 5s)、WALL_TIME_LIMIT(默认 10s)、MEMORY_LIMIT(默认 128000KB)、STACK_LIMIT(默认 64000KB)、MAX_PROCESSES_AND_OR_THREADS(默认 60)、MAX_FILE_SIZE(默认 1024KB)。客户端可在 MAX_* 上限内按次放宽。
  • 服务容量限制:MAX_QUEUE_SIZE(默认 100,队列满时新提交被拒绝)、COUNT(worker 数,默认 2×CPU 核数)、INTERVAL(轮询间隔,默认 0.1s)、RAILS_MAX_THREADS(API 线程数)。

⚠️ 注意:Judge0 自身没有内建「按 IP/按用户的 QPS 限流」。AUTHN_TOKEN 只解决「谁能调用」,不解决「调用多少次」。对外服务必须在前面加 Nginx/网关限流,并配合 MAX_QUEUE_SIZE 保护执行节点。

4.4 鉴权与访问控制

  • AUTHN_HEADER + AUTHN_TOKEN:请求头或查询参数携带,默认头名 X-Auth-Token,令牌为空即关闭鉴权;
  • ALLOW_ORIGIN / DISALLOW_ORIGIN / ALLOW_IP / DISALLOW_IP:CORS 与来源 IP 白名单;
  • AUTHZ_HEADER + AUTHZ_TOKEN:保护删除提交等高危操作(默认关闭)。

4.5 其他能力

  • 额外文件:additional_files(zip/tar 的 base64),可给提交预置数据文件,解压总量受 MAX_EXTRACT_SIZE(默认 10MB)约束;
  • 编译选项与命令行参数:compiler_options、command_line_arguments,可用开关或语言白名单收紧;
  • 提交缓存:SUBMISSION_CACHE_DURATION(默认 1s)内相同请求直接复用结果,抵御重复提交;
  • 维护模式:MAINTENANCE_MODE 打开后拒绝新建/删除提交,适合升级窗口;
  • 可观测性:/system_info 给出队列长度、worker 数、各状态提交数;/workers 给出每个 worker 的心跳与作业。

五、快速开始

验证一套 Judge0 是否可用,最短路径是「起服务 → 查版本 → 查语言 → 提交一段 hello world」。以下命令与回显来自本机 1.13.1 实例(宿主机端口 8138),逐条可复现。

5.1 起一套最小服务

Judge0 官方只提供一种开箱方式:用 docker-compose.yml 编排四个服务(server、workers、db、redis),镜像 judge0/judge0:1.13.1,数据库 postgres:16.2,队列 redis:7.2.4。server 与 workers 都必须 privileged: true,否则 isolate 无法工作。

services:
  server:
    image: judge0/judge0:1.13.1
    volumes:
      - ./judge0.conf:/judge0.conf:ro
    ports:
      - "8138:2358"
    privileged: true
    restart: always
  workers:
    image: judge0/judge0:1.13.1
    command: ["./scripts/workers"]
    volumes:
      - ./judge0.conf:/judge0.conf:ro
    privileged: true
    restart: always
  db:
    image: postgres:16.2
    env_file: judge0.conf
    volumes:
      - ./data:/var/lib/postgresql/data
    restart: always
  redis:
    image: redis:7.2.4
    command: ["bash", "-c", 'docker-entrypoint.sh --appendonly no --requirepass "$$REDIS_PASSWORD"']
    env_file: judge0.conf
    restart: always

judge0.conf 至少要给出 REDIS_PASSWORD、POSTGRES_DB、POSTGRES_USER、POSTGRES_PASSWORD 四项,其余按默认值即可。启动后四个服务的状态:

docker compose ps
NAME                          IMAGE                  COMMAND                  SERVICE   STATUS          PORTS
judge0-1131-stack-db-1        postgres:16.2          "docker-entrypoint.s…"   db        Up 30 seconds   5432/tcp
judge0-1131-stack-redis-1     redis:7.2.4            "docker-entrypoint.s…"   redis     Up 30 seconds   6379/tcp
judge0-1131-stack-server-1    judge0/judge0:1.13.1   "/api/docker-entrypo…"   server    Up 30 seconds   0.0.0.0:8138->2358/tcp
judge0-1131-stack-workers-1   judge0/judge0:1.13.1   "/api/docker-entrypo…"   workers   Up 30 seconds   2358/tcp

四个服务全部 Up 且 API 端口可达,才算起服务成功;db、redis 没有映射宿主端口属正常现象,它们只在编排内网中被 server/workers 访问。

5.2 查版本与语言清单

curl -s http://127.0.0.1:8138/about
{"version":"1.13.1","homepage":"https://judge0.com","source_code":"https://github.com/judge0/judge0","maintainer":"Herman Zvonimir Došilović \u003chermanz.dosilovic@gmail.com\u003e"}

/about 是探活与版本核对的最轻量端点。接着看当前实例的语言总量与几个常用条目:

curl -s http://127.0.0.1:8138/languages | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d))"
curl -s http://127.0.0.1:8138/languages | python3 -c "import sys,json; d=json.load(sys.stdin); print([(x['id'],x['name']) for x in d if x['id'] in (54,62,71,76)])"
47
[(76, 'C++ (Clang 7.0.1)'), (54, 'C++ (GCC 9.2.0)'), (62, 'Java (OpenJDK 13.0.1)'), (71, 'Python (3.8.1)')]

本地 1.13.1 实例实测 47 种语言(社区版镜像的默认语言表)。提交时要传的是这里的 id(如 Python 3.8.1 为 71),不是语言名字。

5.3 提交第一段代码

wait=true 让服务端等到执行结束再返回,一条 curl 就能看到完整结果:

curl -s -X POST 'http://127.0.0.1:8138/submissions?base64_encoded=false&wait=true' \
  -H 'Content-Type: application/json' \
  -d '{"source_code":"print(\"hello judge0\")","language_id":71}'
{"stdout":"hello judge0\n","time":"0.01","memory":7908,"stderr":null,"token":"42078485-070b-45ac-a764-903bbb2f4906","compile_output":null,"message":null,"status":{"id":3,"description":"Accepted"}}

status.id=3 即 Accepted;time 单位为秒、memory 单位为 KB。拿到 token 后还可以随时用 GET /submissions/{token} 复查这次提交,这也是异步方式的取结果路径。

⚠️ 注意:如果你的宿主机是 cgroup v2(Ubuntu 22.04+ 默认),1.13.1 镜像内置的 isolate 1.8.1 不支持 v2,默认参数提交会返回 Internal Error 与 No such file or directory @ rb_sysopen - /box/script.py。本文实测环境即属此情况,处理办法是不让 worker 走 --cg:把 app/jobs/isolate_job.rb 里 @cgroups 的取值改为空字符串,或在每次提交时显式传 enable_per_process_and_thread_time_limit、enable_per_process_and_thread_memory_limit 两个 true。判断依据:docker exec <worker> isolate --cg -b 1 --init 报 Failed to create control group /sys/fs/cgroup/memory/box-1/: No such file or directory。

六、适用场景与限制

6.1 适用场景

场景为什么合适
高校/培训机构 OJ 判题后端语言覆盖全、状态码体系标准化、批量提交适合多测试点
在线 IDE / 文档站「运行示例」wait=true 一次请求拿到结果,集成成本极低
面试/笔试平台的代码题评测支持 compiler options、additional files、回调
AI Agent 的代码执行工具REST 接口易封装,/system_info 可做容量观测
多租户 SaaS 的「运行代码」功能资源限制细到进程/文件/内存,可配队列上限

6.2 不适用与明确边界

  • 不要把它当题库/OJ 网站:没有题目、比赛、排名、用户体系,这些要自己实现或选 OnlineJudge/HUSTOJ。
  • 不要把 isolate 当作「抵御恶意代码逃逸」的安全边界:isolate 约束的是资源(CPU/内存/进程/文件/网络),它假设运行环境本身可信。执行节点以 privileged 运行,一旦语言运行时或内核存在提权漏洞,逃逸后果是宿主机级别。
    • 正确姿势:执行节点独立内网主机/VM、只跑 Judge0、不存业务数据、不挂敏感目录、按需关闭 ENABLE_NETWORK、定期打内核与运行时补丁;
    • 面向不可信公网用户时,应叠加外层 VM/gVisor/Kata 或独立物理机隔离,而不是只依赖 isolate。
  • 不要期待高频发版:1.13.1 之后无新 release,新语言/新运行时需要自己往 languages 表加并保证执行节点有对应环境。
  • 不要用它做长任务:默认墙钟上限 10s,且 worker 串行执行,长任务会堵塞队列。

6.3 容量估算的粗略口径

单 worker 同一时刻只跑一个提交,吞吐 ≈ worker 数 / 平均单次执行耗时。以默认 COUNT = 2×CPU 估算,6 核机器约 12 个 worker;若平均每次编译+运行 1.5s,理论吞吐约 8 次/秒,实际还要扣除编译开销与队列轮询延迟。/system_info 的队列长度是判断要不要加 worker 的直接依据。

七、同类选型对比

7.1 五个项目同表对比(2026-10-27 实查)

维度Judge0 1.13.1PistonQingdaoU OnlineJudgeHUSTOJCodeBox
定位通用代码执行 API通用代码执行 API完整 OJ 网站(题库/比赛/用户)完整 OJ 网站(ACM/NOIP 训练)云端/桌面 IDE(非判题)
技术栈Ruby 2.7 + Rails 5 + PostgreSQL + RedisNode.jsVue + Django + PostgreSQL + DockerPHP + C++ judge + MySQLNode.js
隔离机制isolate(cgroup/namespace/seccomp)LXC 容器自研 judger(容器/沙箱)自研 judge_client(rlimit/ptrace)无判题能力
语言扩展改 languages 表 + 装运行时安装运行时包(piston 包管理)需改 judger 配置改 db_info/编译脚本不适用
对外接口REST,同步/异步/批量/回调REST,同步为主REST(判题以外还有站务 API)以 Web 为主,API 有限无判题 API
许可GPL-3.0MITMITGPL-2.0Apache-2.0
社区规模(Star/Fork)4492 / 9442838 / 4736553 / 15393816 / 8324150 / 574
最近推送2026-10-182026-07-312024-10-232026-10-272023-10-17
最近发版2024-04-18(1.13.1)以运行时包版本为准以镜像 tag 为准持续滚动—

💡 技术拓展:这四个「能跑代码」的项目其实分属两类——执行引擎(Judge0、Piston)只提供「提交源码→拿结果」的 API;OJ 网站(OnlineJudge、HUSTOJ)自带题库/比赛/排名,判题只是内部模块。CodeBox 是 IDE,跑代码靠宿主环境,不构成判题服务。选型第一步是分清你要的是「引擎」还是「整站」。

7.2 关键差异解读

  • 接口成熟度:Judge0 是四者中 API 语义最完整的(同步等待、批量、回调、状态码表、/system_info 容量观测),适合被其他系统集成;Piston 的 API 更简洁,同步为主。
  • 隔离实现:Judge0 用 isolate(进程级),Piston 用 LXC(容器级),两者都需要宿主特权;容器级隔离在「语言环境隔离」上更彻底,进程级在启动开销上更优。
  • 语言维护成本:Piston 把每种语言做成可安装的运行时包,升级语言版本最省事;Judge0 需要自己维护 languages 表与执行节点运行时。
  • 整站能力:需要「注册用户、出题、比赛、榜单」就直接选 OnlineJudge 或 HUSTOJ,用 Judge0 从零搭这些上层功能不划算。
  • 许可差异:Judge0 是 GPL-3.0,对外分发二次开发版本有开源义务;Piston/OnlineJudge 是 MIT,商业集成更宽松。

7.3 选型建议

你的需求建议
已有业务系统,只要「跑代码」能力Judge0(要回调/批量/容量观测)或 Piston(要更轻、MIT)
要一个能直接开课的 OJ 网站QingdaoU OnlineJudge(现代化前端、Docker 部署)或 HUSTOJ(老牌、资料多)
要在网页里写代码并运行(IDE 形态)CodeBox 类 IDE + 后端接 Judge0/Piston,不要让 IDE 直接在宿主机执行
面向不可信公网多租户任何单层 isolate/容器方案都不够,需外层 VM/gVisor 隔离 + 严格限流

八、参考链接