青岛OJ系统Docker部署与性能优化指南
1. 青岛OJ系统概述与安装准备
青岛OJ(QingdaoU/OnlineJudge)是一款开源的在线判题系统,广泛应用于高校程序设计教学和竞赛训练。作为ACM/ICPC竞赛的官方推荐系统之一,它以Docker容器化部署为特色,大大降低了传统OJ系统的部署复杂度。我在实际部署过程中发现,相比传统需要手动配置Nginx、MySQL、Redis等组件的方案,青岛OJ的容器化方案让部署时间从原来的半天缩短到30分钟以内。
1.1 系统架构解析
青岛OJ采用微服务架构设计,主要包含以下核心组件:
- JudgeServer:负责代码编译执行的沙盒环境,采用Seccomp安全机制隔离
- WebServer:基于Django的后端服务,提供RESTful API
- MySQL:存储用户数据和题目信息
- Redis:缓存判题结果和会话信息
- Nginx:处理前端静态资源和负载均衡
这种架构设计使得各组件可以独立扩展,特别是在举办大型比赛时,可以单独增加JudgeServer实例来应对高并发判题需求。我在学校组织的编程新生赛中实测,单台4核8G服务器配合3个JudgeServer容器,可以轻松应对200人同时提交代码的压力。
1.2 环境准备要点
Linux环境配置(推荐方案)
对于生产环境,强烈建议使用Ubuntu 20.04/22.04 LTS系统。以下是经过优化的依赖安装命令:
# 更新软件源并安装基础工具 sudo apt-get update && sudo apt-get install -y \ vim python3-pip curl git \ ca-certificates gnupg lsb-release # 配置Docker官方GPG密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 添加稳定版仓库 echo "deb [arch=$(dpkg --print-architecture) \ signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \ https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装Docker引擎 sudo apt-get update && sudo apt-get install -y \ docker-ce docker-ce-cli containerd.io # 验证安装 sudo docker run --rm hello-world注意:如果服务器位于国内,建议使用阿里云镜像源加速下载。我在杭州区域的实测显示,使用镜像源能使Docker镜像拉取速度从50KB/s提升到8MB/s。
Windows环境限制
虽然官方文档提供了Windows安装方案,但在实际测试中发现以下问题:
- 文件共享权限问题导致JudgeServer无法正常读写临时文件
- 路径转换问题使得部分测试用例无法加载
- 性能损耗高达30%-40%
建议仅在个人测试时使用Windows Docker Desktop方案,正式环境务必使用Linux服务器。我曾尝试在Windows Subsystem for Linux (WSL2) 中部署,虽然能解决部分兼容性问题,但仍不建议用于生产环境。
2. 详细安装流程与配置优化
2.1 克隆仓库与目录结构解析
执行以下命令获取部署文件:
git clone -b 2.0 https://gitee.com/QingdaoU/OnlineJudgeDeploy.git \ && cd OnlineJudgeDeploy关键目录说明:
data/:包含MySQL数据卷、测试用例和日志文件backup/:数据库备份脚本默认位置docker-compose.yml:定义所有服务的编排配置
建议在安装前修改docker-compose.yml中的以下参数:
services: oj-redis: image: redis:6.2-alpine # 增加内存限制防止OOM deploy: resources: limits: memory: 512M oj-mysql: environment: # 修改默认字符集避免中文乱码 - MYSQL_CHARSET=utf8mb4 - MYSQL_COLLATION=utf8mb4_unicode_ci2.2 容器启动与健康检查
启动命令及其背后原理:
# -d参数表示后台运行,--compatibility选项确保资源限制生效 docker-compose up -d --compatibility监控启动状态的正确方式:
watch -n 2 'docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"'健康状态解读:
healthy:容器通过健康检查starting:正在初始化(JudgeServer可能需要较长时间)unhealthy:需要查看日志排查问题
常见启动问题处理:
- 端口冲突:修改
docker-compose.yml中的端口映射,例如将80:80改为8080:80 - 磁盘空间不足:JudgeServer需要至少2GB临时空间,通过
df -h检查/var/lib/docker所在分区 - 镜像拉取失败:尝试手动拉取
docker pull registry.cn-shanghai.aliyuncs.com/onlinejudge/judge_server
2.3 管理员账户安全配置
首次登录后应立即:
- 修改默认管理员密码(root/rootroot)
- 开启HTTPS(Let's Encrypt证书可通过修改
web/nginx.conf配置) - 设置IP访问限制(在
web/onlinejudge/settings.py中添加ALLOWED_HOSTS)
后台关键安全设置路径:
- 系统配置 > 判题机Token
- 用户管理 > 管理员权限分配
- 系统日志 > 登录审计
3. 生产环境调优经验
3.1 性能优化参数
在docker-compose.yml中添加以下JudgeServer调优参数:
oj-judge-server: environment: - JUDGE_MAX_RUNNING=20 # 根据CPU核心数调整 - JUDGE_MAX_QUEUE_SIZE=100 - JUDGE_STRICT_MODE=false # 比赛时设为true deploy: resources: limits: cpus: '4' memory: 4GMySQL优化建议:
-- 在phpMyAdmin或MySQL客户端中执行 SET GLOBAL innodb_buffer_pool_size = 2*1024*1024*1024; SET GLOBAL max_connections = 200;3.2 高可用方案
通过Docker Swarm实现多节点部署:
- 初始化Swarm集群:
docker swarm init --advertise-addr <管理节点IP> - 部署服务栈:
docker stack deploy -c docker-compose.yml oj - 扩展JudgeServer:
docker service scale oj_judge-server=3
负载均衡配置示例(Nginx片段):
upstream judges { server judge1:8080; server judge2:8080; server judge3:8080; keepalive 32; } location /judge/ { proxy_pass http://judges; proxy_http_version 1.1; proxy_set_header Connection ""; }3.3 备份与迁移策略
数据库每日备份方案:
# 创建备份脚本/backup/backup.sh #!/bin/bash docker exec oj-mysql sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /backup/oj-$(date +%Y%m%d).sql find /backup -name "oj-*.sql" -mtime +7 -delete添加定时任务:
(crontab -l ; echo "0 3 * * * /bin/bash /backup/backup.sh") | crontab -迁移到新服务器的步骤:
- 备份原数据库和
data/test_case目录 - 在新服务器安装相同版本Docker
- 复制整个OnlineJudgeDeploy目录
- 恢复数据库:
docker exec -i oj-mysql mysql -uroot -p$MYSQL_ROOT_PASSWORD < backup.sql
4. 常见问题排查指南
4.1 判题异常处理
案例1:编译错误但本地正常现象:提交的C++代码在本地g++编译通过,但OJ返回CE 排查步骤:
- 查看具体错误信息:
docker logs oj-judge-server --tail 100 - 对比JudgeServer的编译器版本:
docker exec oj-judge-server g++ --version - 检查编译选项差异:
cat data/judge_server/run/config.json
案例2:时间超出限制解决方法:
- 确认题目时间限制设置合理
- 检查服务器负载:
docker stats - 在
docker-compose.yml中增加JudgeServer的CPU配额
4.2 性能监控方案
推荐使用cAdvisor+Prometheus+Grafana监控栈:
# 在docker-compose.yml中添加 monitor: image: google/cadvisor:v0.47.0 ports: - "8088:8080" volumes: - /:/rootfs:ro - /var/run:/var/run:rw - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro关键监控指标:
- JudgeServer队列长度
- MySQL查询响应时间
- Redis内存使用率
- 容器CPU/内存占用
4.3 升级注意事项
从2.0升级到2.1的实操经验:
- 停止服务:
docker-compose down - 备份数据库和测试用例
- 获取新版本:
git fetch origin 2.1 && git checkout 2.1 - 比较
docker-compose.yml差异,合并自定义配置 - 重建服务:
docker-compose up -d --build
升级后必检项:
- 判题沙盒权限是否正常
- 所有测试用例是否可读
- 管理员账户是否保留