SDUTOnlineJudge系统解析(二)

2016-12-4 arvin 技术文章

关于评测机的实现,首先告诉大家SDUT的实现已经开源,项目地址https://github.com/ma6174/acmjudger

这是SDUT 10级学长实现的,具体原理可以看https://github.com/ma6174/acmjudger/blob/master/README.md

下面讲解在使用过程中发现问题,修复并改进后SDUT现在用的版本,项目地址https://github.com/Arvintian/acmjudger

改后的版本大概主要修了一bug,改了一不好的地方。

因为也是我们摸索实现的,所以就很依赖python的线程了,下面的讲解不考虑python的GIL。还有其实因为评测过程实际是大量的数据库和评测数据文件的IO,python解释器在线程上也是有优化的,相关python线程争论的讲解,大家可以百度或Google~

注意,请先认真阅读SDUT学长的讲解

改进的版本修的一个bug是关数据链接的,学长少了一个try,catch,已经修复就不讨论了。

下面讲一个重要的增加点,是web程序和评测机之间用redis做判题队列,评测机评测取代码不再从mysql中取,评测机不再监控mysql而是redis(因为redis的特性也不用我们去监控,没任务redis会自动阻塞我们获取任务)。换从哪拿任务也不复杂,把原来监控mysql的线程换成监控redis的不就行了,我们知道redis当队列使是任务拿一个没一个,重判功能怎么实现?所以我们选择折中(而且比赛重判相比正常提交是特殊情况),保留监控mysql线程通过配置可以调整扫描mysql的间隔时间,重判任务还从mysql中获取,不需要重判可以把扫描mysql间隔时间配的无限长(目前我的策略是对外开放的oj时间配的比较长,内部考试用的间隔是5分钟,考试重判会在5分钟内响应)。下面看图分析,这里把redis做的队列称为任务队列,把评测机内部python queue对象队列称为调度队列。

点击查看原图

这样总的流程就是用户提交,web程序投递任务到redis同时持久化写入mysql,评测机从redis中获取任务,放入调度队列,然后n个judge线程中的一个进行评测,最后把结果写回mysql,若有重判需求可以通过web程序操作mysql标记重判任务,然后扫描mysql的线程便会把这些任务重新放回调度队列进行重新评测。

这样其实系统重要的组件完全可以做分布了,web程序(php,nginx),redis,mysql,评测机,都可以开一个或多个并放到不同的机器上运行。

目前我们用两台机器仅把mysql数据库单独拿了出去部署对外开放,日提交量大概10000左右(top一下cpu使用率还不到1),在另外单台16G内存的服务器上部署所有服务同时支持500+同学考试还是很轻松的。

SDUTOnlineJudge系统就是这样了,谢谢大家支持!

标签: OnlineJudge

发表评论:

Powered by emlog