从零到一:Hydro OJ 的完整搭建与深度部署指南
1. 为什么选择Hydro OJ在线判题系统Online Judge简称OJ是编程竞赛和算法训练中不可或缺的工具。作为一个开源的OJ系统Hydro OJ凭借其现代化的架构、丰富的功能和活跃的社区支持成为了许多开发者和教育机构的首选。我自己在搭建过程中发现相比传统OJHydro OJ的Docker部署方式让安装过程变得异常简单而且它的插件系统允许我们灵活扩展功能。Hydro OJ最吸引我的地方在于它的高性能评测系统。实测下来它能够稳定处理大量并发提交这对于组织编程比赛特别重要。记得第一次用它举办校内比赛时50名学生同时提交代码系统运行依然流畅这让我对它的稳定性印象深刻。2. 环境准备与基础安装2.1 硬件与系统要求在开始之前我们需要确保服务器满足基本要求。我建议使用至少2核CPU、4GB内存的云服务器或本地机器。操作系统方面Ubuntu 20.04/22.04 LTS是最佳选择这也是我实测最稳定的环境。如果你像我一样喜欢尝鲜也可以尝试在CentOS 7上部署不过需要额外处理一些依赖问题。# 检查系统版本 lsb_release -a # 更新系统包 sudo apt update sudo apt upgrade -y2.2 Docker环境配置Hydro OJ官方推荐使用Docker部署这确实是最省事的方式。我在不同环境中测试过发现Docker能完美解决依赖问题。首先安装Docker和Docker Compose# 安装Docker curl -fsSL https://get.docker.com | sh # 安装Docker Compose sudo curl -L https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose安装完成后记得将当前用户加入docker组这样就不需要每次都加sudo了sudo usermod -aG docker $USER newgrp docker3. 部署Hydro OJ核心服务3.1 获取部署文件Hydro OJ的官方仓库提供了完整的部署配置。我习惯在/opt目录下创建工作区mkdir -p /opt/hydro cd /opt/hydro git clone https://github.com/hydro-dev/Hydro.git cd Hydro这里有个小技巧如果你在国内可以使用Gitee镜像仓库加速克隆git clone https://gitee.com/hydro-dev/Hydro.git3.2 配置docker-compose.yml部署的核心是docker-compose.yml文件。我通常会根据服务器配置调整几个关键参数version: 3 services: mongodb: image: mongo:5 volumes: - ./data/db:/data/db restart: always hydro: image: hydrooj/hydro ports: - 8888:80 volumes: - ./data/file:/file - ./data/static:/static environment: - MONGO_URImongodb://mongodb:27017/hydro depends_on: - mongodb restart: always对于生产环境我建议增加以下配置设置时区TZAsia/Shanghai限制资源使用mem_limit: 2g启用HTTPS修改端口映射为443:4433.3 启动服务配置完成后一键启动所有服务docker-compose up -d第一次启动可能需要几分钟时间初始化数据库。你可以用以下命令查看日志docker-compose logs -f当看到Hydro started的日志信息时就说明服务已经就绪了。在浏览器访问http://你的服务器IP:8888就能看到Hydro OJ的登录界面了。4. 系统配置与优化4.1 管理员账户设置首次访问需要创建管理员账户。这里有个容易踩的坑密码强度要求较高建议使用大小写字母数字特殊字符的组合。创建后立即进入后台修改默认密码是个好习惯。在后台面板我通常会做这些基础配置修改站点名称和描述设置时区为Asia/Shanghai配置SMTP邮件服务用于发送验证码和通知开启用户注册验证防止垃圾账号4.2 评测机配置Hydro OJ支持分布式评测机这是它的亮点之一。我建议至少配置2台评测机以保证稳定性docker run -d \ --name hydro-judge \ --network hydro_default \ -e JUDGE_SECRETyour_judge_secret_key \ -e SYSTEM_TOKENyour_system_token \ -e PARALLEL_TASKS4 \ hydrooj/hydro-judge关键参数说明PARALLEL_TASKS根据CPU核心数设置一般设为CPU核心数×2JUDGE_SECRET和SYSTEM_TOKEN需要与后台配置一致内存限制对于C等高内存消耗语言建议每个任务预留512MB内存4.3 性能优化技巧经过多次部署实践我总结了几个提升性能的技巧启用Redis缓存在docker-compose.yml中添加redis服务配置Nginx反向代理减少Docker直接暴露端口定期清理旧提交设置自动任务清理30天前的提交记录启用Gzip压缩减少静态资源传输量对于高并发场景这个Nginx配置很有效server { listen 80; server_name your.domain.com; location / { proxy_pass http://localhost:8888; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 启用WebSocket支持 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; } # 静态文件缓存 location /static/ { expires 30d; add_header Cache-Control public; } }5. 日常维护与问题排查5.1 数据备份策略我吃过没备份的亏现在严格执行3-2-1备份原则每天备份MongoDB数据库每周完整备份整个/data目录备份存储在不同设备上这是我在用的MongoDB备份脚本#!/bin/bash BACKUP_DIR/backup/hydro DATE$(date %Y%m%d) docker exec hydro_mongodb_1 mongodump \ --out /tmp/backup \ --gzip docker cp hydro_mongodb_1:/tmp/backup $BACKUP_DIR/$DATE docker exec hydro_mongodb_1 rm -rf /tmp/backup # 保留最近7天备份 find $BACKUP_DIR -type d -mtime 7 | xargs rm -rf5.2 常见问题解决在运维过程中我遇到过几个典型问题问题1评测机不工作检查步骤确认评测机容器正常运行检查JUDGE_SECRET是否匹配查看评测机日志docker logs hydro-judge问题2提交队列堆积解决方法增加评测机数量调整优先级设置限制用户提交频率问题3数据库性能下降优化方案创建适当的索引定期执行db.repairDatabase()考虑分片集群部署5.3 监控与日志完善的监控能提前发现问题。我使用PrometheusGrafana监控系统状态主要关注服务器负载数据库连接数评测队列长度各语言评测用时对于日志管理建议配置logrotate防止日志文件过大/var/lib/docker/containers/*/*.log { daily rotate 7 compress delaycompress missingok copytruncate }6. 高级功能与扩展6.1 插件系统Hydro OJ的插件系统非常强大。我安装了几个实用插件比赛榜单冻结Freeze功能代码相似度检测外部用户系统对接安装插件很简单docker exec -it hydro_hydro_1 bash cd ~/.hydro npm install hydrooj/freeze然后重启服务即可生效。6.2 自定义评测对于特殊题目需求可以编写自定义checker。我做过一个图像处理题的评测脚本import sys from PIL import Image from imagehash import average_hash def main(): std Image.open(std.png) usr Image.open(usr.png) std_hash average_hash(std) usr_hash average_hash(usr) diff std_hash - usr_hash if diff 5: print(100) # 完全匹配 elif diff 15: print(80) # 部分匹配 else: print(0) # 不匹配 if __name__ __main__: main()6.3 多语言支持虽然Hydro OJ默认支持主流编程语言但添加新语言也很方便。比如添加Rust支持在评测机容器中安装Rust编译器修改judge.yaml配置文件设置合适的编译选项和资源限制- name: rust compile: rustc -O -o {target} {source} execute: {target} time: 1000 memory: 256 files: *.rs7. 生产环境部署建议经过多次实战我总结出几个生产环境部署的关键点安全加固定期更新Docker镜像限制数据库外部访问启用HTTPS加密配置防火墙规则高可用方案使用负载均衡部署多个Hydro实例配置MongoDB副本集分离评测机服务灾备方案准备备用服务器制定故障转移流程定期演练恢复过程这是我使用的Lets Encrypt HTTPS配置示例docker run -it --rm \ -p 80:80 -p 443:443 \ -v /etc/letsencrypt:/etc/letsencrypt \ certbot/certbot certonly \ --standalone \ -d your.domain.com \ --email youremail.com \ --agree-tos \ --non-interactive然后修改docker-compose.yml中的端口映射ports: - 443:443 environment: - HTTPStrue最后保持系统更新很重要。我设置了一个每周自动更新任务的cron job0 3 * * 1 docker-compose pull docker-compose up -d