1-概述:开源在线代码执行系统
1-概述:开源在线代码执行系统

1-概述:开源在线代码执行系统

Judge0 是一款健壮、可扩展且开源的在线代码执行系统,旨在为人类和 AI 提供安全、快速的代码执行服务。自 2016 年 8 月创立以来,Judge0 已被广泛应用于竞赛编程平台、AI 代码生成、教育评估系统等多种场景。

系统定位与核心价值

Judge0 的核心使命是将复杂的代码执行能力简化封装,使开发者能够轻松地将在线代码执行功能集成到各类应用中。通过简洁的 HTTP JSON API,使用者无需深入理解底层沙箱机制,即可实现代码编译、执行、结果回收的完整流程。

作为开源项目,Judge0 提供两种版本:Judge0 CE(社区版) 托管于 GitHub master 分支,Judge0 Extra CE 则包含更多语言支持,位于 extra 分支。此外,用户也可选择使用 RapidAPI 托管服务或直接联系官方获取 SaaS 版本。

技术架构概览

Judge0 采用现代化的模块化架构设计,由多个协同工作的组件构成。以下架构图展示了系统的整体运行流程:

flowchart TB
    subgraph Client["客户端"]
        A[用户应用]
    end

    subgraph Gateway["Rails API 网关"]
        B[SubmissionsController]
        C[路由层]
    end

    subgraph Data["数据层"]
        D[(PostgreSQL<br/>数据库)]
        E[(Redis<br/>任务队列)]
    end

    subgraph Workers["Worker 工作节点"]
        F[IsolateJob]
        G[Isolate 沙箱]
    end

    A -->|HTTP JSON| C
    C --> B
    B -->|写入| D
    B -->|入队| E
    E -->|拾取任务| F
    F -->|执行| G
    G -->|更新结果| D
    D -->|读取结果| B
    B -->|返回| A

核心组件解析

Rails API 服务器 是系统的入口点,负责接收客户端请求、管理会话、处理认证授权,并将代码提交任务分发至消息队列。配置文件 judge0.conf 提供了 70 余项可调参数,涵盖服务器行为、认证授权、Redis 连接等各个方面。

Worker 工作节点 运行独立的 Ruby on Rails 进程,通过 Resque 任务队列系统从 Redis 获取待执行的提交任务。每个 Worker 调用 IsolateJob 执行实际的代码编译与运行操作,利用 Linux 的 isolate 工具实现进程级别的资源隔离与限制。

PostgreSQL 数据库 持久化存储所有提交记录,包括源代码、语言标识、输入数据、执行结果、运行时间、内存占用等完整信息。

Redis 消息队列 实现任务的异步分发与负载均衡,支持配置多个并行 Worker 以提升吞吐量。

Sources: README.md Sources: docker-compose.yml Sources: judge0.conf

代码执行流程详解

当用户提交一段代码进行执行时,Judge0 内部经历以下标准流程:

sequenceDiagram
    participant Client as 客户端应用
    participant API as Rails API
    participant Redis as Redis 队列
    participant Worker as Worker 进程
    participant Sandbox as Isolate 沙箱

    Client->>API: POST /submissions<br/>(source_code, language_id, stdin)
    API->>API: 验证请求参数
    API->>API: 生成唯一 token
    API->>PostgreSQL: 创建提交记录
    PostgreSQL-->>API: 提交 ID
    API->>Redis: 入队 IsolateJob
    Redis-->>API: 入队成功
    API-->>Client: 返回 token (202)

    Worker->>Redis: 获取下一个任务
    Worker->>PostgreSQL: 更新状态为 "处理中"
    Worker->>Sandbox: 初始化沙箱目录
    alt 编译型语言
        Worker->>Sandbox: 执行编译命令
        alt 编译成功
            Worker->>Sandbox: 执行程序
        else 编译失败
            Worker->>Worker: 标记为 CE 状态
        end
    else 解释型语言
        Worker->>Sandbox: 直接执行
    end

    Sandbox-->>Worker: stdout, stderr, metadata
    Worker->>PostgreSQL: 更新执行结果
    Worker->>Redis: 触发回调(可选)
    Client->>API: GET /submissions/:token
    API->>PostgreSQL: 查询结果
    API-->>Client: 执行结果 (stdout, status, time, memory)
  1. 请求接收与验证:API 控制器解析 Base64 编码的源代码,验证语言 ID 是否有效,检查资源限制参数是否符合配置范围。
  2. 任务入队:通过 IsolateRunner.perform_later 方法将任务推送至 Redis 队列,同时更新数据库状态为”排队中”。
  3. 异步执行:Worker 进程从队列获取任务,调用 IsolateJob#perform 方法执行实际代码。在沙箱目录中创建源文件、输入文件,执行编译(如需要)和运行操作。
  4. 结果收集:读取 isolate 工具生成的元数据文件,提取运行时间、内存占用、退出码等信息,与标准输出/错误一起存入数据库。
  5. 回调通知:若提交时指定了 callback_url,系统会发送 HTTP POST 请求通知结果。

Sources: isolate_runner.rb Sources: isolate_job.rb Sources: submissions_controller.rb

支持的编程语言

Judge0 对编程语言的支持极为丰富,涵盖主流编译型语言、解释型语言以及脚本语言。当前活跃配置包含 47 种编程语言,包括历史存档的语言版本总计超过 90 种。

主要语言分类

分类 语言示例 数量
编译型语言 C/C++ (GCC/Clang 多版本)、Java、Kotlin、Go、Rust 15+
脚本语言 Python (2/3)、Ruby、Perl、PHP、Bash 8+
函数式语言 Haskell、Scala、Clojure、Elixir、Erlang 8+
学术语言 Fortran、Pascal、COBOL、Prolog、Lua 8+
平台语言 C# (Mono/.NET)、F#、Swift、Objective-C、OCaml 6+
特殊用途 Assembly (NASM)、SQL (SQLite)、Plain Text、Executable 4+

每种语言在数据库中存储其唯一标识 ID、名称、源文件扩展名、编译命令模板(可选)和运行命令。这些配置存储于 db/languages/active.rb 和 db/languages/archived.rb 中。

# 语言配置示例
{
  id: 71,
  name: "Python (3.8.1)",
  is_archived: false,
  source_file: "script.py",
  compile_cmd: nil,  # 解释型语言无需编译
  run_cmd: "/usr/local/python-3.8.1/bin/python3 script.py"
}

Sources: language.rb Sources: db/languages/active.rb

状态码体系

Judge0 定义了完整的执行状态枚举,用于精确描述代码执行的结果。每个状态具有唯一的数字 ID 和描述性名称。

ID 状态名称 含义说明
1 In Queue 任务已入队,等待 Worker 处理
2 Processing 正在执行编译或运行
3 Accepted 执行成功,输出正确
4 Wrong Answer 输出与预期不符
5 Time Limit Exceeded 超出时间限制
6 Compilation Error 编译阶段失败
7-12 Runtime Error 运行时错误(信号类型不同)
13 Internal Error 沙箱内部错误
14 Exec Format Error 可执行文件格式错误

运行时错误根据接收到的 Unix 信号进一步细分:SIGSEGV(段错误)、SIGXFSZ(文件大小超限)、SIGFPE(浮点异常)、SIGABRT(异常中止)等。

Sources: status.rb

API 接口概览

Judge0 提供简洁直观的 RESTful API,所有数据传输支持 Base64 编码以处理二进制内容。

核心端点

方法 路径 功能说明
POST /submissions 创建新的代码提交
GET /submissions/:token 查询单个提交结果
POST /submissions/batch 批量创建提交(最多 20 个)
GET /submissions/batch 批量查询提交结果
DELETE /submissions/:token 删除已完成提交
GET /languages 获取支持的语言列表
GET /statuses 获取状态码定义
GET /system_info 获取系统信息

创建提交时可通过 wait=true 参数同步等待执行结果,否则返回 202 状态码和 token,客户端随后轮询查询结果。

# 同步执行示例(等待结果)
curl -X POST "https://ce.judge0.com/submissions?wait=true" \
  -H "Content-Type: application/json" \
  -d '{
    "language_id": 71,
    "source_code": "print(input())",
    "stdin": "Hello"
  }'

# 异步执行示例
curl -X POST "https://ce.judge0.com/submissions" \
  -H "Content-Type: application/json" \
  -d '{
    "language_id": 71,
    "source_code": "aGVsbG8=",  # Base64 编码
    "stdin": "SGVsbG8="
  }'

Sources: routes.rb Sources: docs/api/docs.md

安全隔离机制

代码执行的隔离安全性是 Judge0 的核心设计考量。系统采用多层防护策略确保不受信任的代码无法危害系统环境。

进程级隔离:基于 isolate 工具实现,利用 Linux cgroups(控制组)限制进程的 CPU 时间、内存占用、文件系统访问等资源。默认配置下,单个执行任务的内存限制为 128MB,CPU 时间限制为 5 秒。

文件系统限制:用户代码仅能在沙箱目录内操作,/etc 目录以 noexec 方式挂载,防止执行任意二进制文件。额外的压缩包文件需通过 unzip 解压后使用,且文件大小和解压后总大小均受限制。

环境变量控制:仅允许预设的环境变量传入沙箱,包括 HOME、PATH、LANG 等必要变量,JUDGE0_* 系列变量用于传递元信息。

# isolate 命令参数示例
isolate --cg -s -b #{box_id} \
  -M #{metadata_file} \
  -t 5 \              # CPU 时间限制 5 秒
  -m 128000 \         # 内存限制 128MB
  -k 64000 \          # 栈大小限制 64KB
  -p 60 \             # 最多 60 个进程/线程
  -d /etc:noexec      # 禁止执行 /etc 下的程序

Sources: isolate_job.rb Sources: judge0.conf

配置管理

Judge0 通过 judge0.conf 文件集中管理所有配置选项,支持环境变量覆盖。配置文件按功能划分为多个逻辑段落。

服务器配置

# 遥测开关(默认开启)
JUDGE0_TELEMETRY_ENABLE=true

# 维护模式
MAINTENANCE_MODE=false
MAINTENANCE_MESSAGE="系统维护中"

# 同步等待结果开关
ENABLE_WAIT_RESULT=true

# 编译器选项开关
ENABLE_COMPILER_OPTIONS=true
ALLOWED_LANGUAGES_FOR_COMPILER_OPTIONS="C C++ Java"

# 提交删除开关
ENABLE_SUBMISSION_DELETE=false

# 批量提交配置
ENABLE_BATCHED_SUBMISSIONS=true
MAX_SUBMISSION_BATCH_SIZE=20

# 回调配置
ENABLE_CALLBACKS=true
CALLBACKS_MAX_TRIES=3
CALLBACKS_TIMEOUT=5

Worker 配置

# 轮询间隔(秒)
INTERVAL=0.1

# 并行 Worker 数量(默认 2 * CPU 核心数)
COUNT=

# 队列最大容量
MAX_QUEUE_SIZE=100

资源限制配置

# CPU 时间限制(秒)
CPU_TIME_LIMIT=5
MAX_CPU_TIME_LIMIT=15

# 内存限制(KB)
MEMORY_LIMIT=128000
MAX_MEMORY_LIMIT=512000

# 栈大小限制(KB)
STACK_LIMIT=64000
MAX_STACK_LIMIT=128000

# 进程/线程数限制
MAX_PROCESSES_AND_OR_THREADS=60

Sources: config.rb Sources: judge0.conf

部署架构

Docker Compose 是推荐的部署方式,系统由四个核心服务组成:

services:
  server:
    image: judge0/judge0:latest
    ports:
      - "2358:2358"
    privileged: true

  worker:
    image: judge0/judge0:latest
    command: ["./scripts/workers"]
    privileged: true

  db:
    image: postgres:16.2

  redis:
    image: redis:7.2.4

Server 服务:运行 Rails 应用,监听 HTTP 请求,暴露 2358 端口。

Worker 服务:执行 scripts/workers 脚本,启动 Resque scheduler 和多个 Worker 进程处理任务队列。

DB 服务:PostgreSQL 16.2 实例,存储所有持久化数据。

Redis 服务:Redis 7.2.4 实例,作为 Resque 的后端队列存储。

Sources: docker-compose.yml Sources: scripts/workers

学习路径建议

对于初次接触 Judge0 的开发者,建议按以下顺序深入学习:

  1. 快速启动:Docker Compose 部署指南 — 首先通过 Docker Compose 快速搭建本地开发环境,亲身体验系统运行。
  2. 提交(Submission)核心概念 — 深入理解提交模型的数据结构与字段含义。
  3. 编程语言与状态枚举 — 掌握语言配置机制和状态流转逻辑。
  4. 系统架构设计 — 全面理解各组件的交互关系与设计考量。
  5. SubmissionsController 控制器 — 深入学习 API 控制器的请求处理流程。
  6. IsolateJob 沙箱执行任务 — 理解代码在沙箱中的执行细节。

相关条目

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注