OJ在线判题系统项目笔记

项目介绍

在线评测编程题目代码的系统,出题人预先设置题目的输入样例和输出样例,根据用户提交代码,进行编译代码,运行代码,判断代码执行结果是否正确。

后端服务

网关服务

接收前端请求,转发到对应的服务

用户服务

用户注册、用户登录、用户退出

题目服务

题目浏览,在线做题,题目提交、提交记录

判题服务

判题服务获取调用题目服务获取题目信息,测试用例,调用代码沙箱编译运行代码并对比结果

代码沙箱

编译运行代码,返回执行结果、运行时间、运行内存

公共模块

数据模型、统一异常处理、全局响应封装、工具类

judgeCase:判题用例,包括输入用例和输出用例

judgeInfo:判题信息,包括程序执行信息,运行时间,运行内存

judgeContext:判题上下文,包括题目信息,编程语言,输出用例,输出结果,判题信息

微服务架构优点

微服务架构是一种软件架构风格,把大而全的单体应用拆分为多个职责单一的模块,每个服务单元独立部署,运行和维护。服务单元之间通过网络通信进行交互,从而实现完整系统的功能。微服务架构可以提高系统的灵活性,可维护性,可扩展性,容错性。

本项目中,使用微服务架构将较重的服务(判题服务和代码沙箱)和核心服务(用户服务和题目服务)进行分离解耦,即使判题服务因为代码沙箱压力过大而阻塞,也不会影响核心业务运行。

用户服务

普通用户

注册、登录、获取登录用户、注销、修改个人信息

管理员

增删改 根据id获取用户(包装类) 分页获取用户(包装类)

题目服务

管理员

增删改、根据id获取题目、分页获取题目

普通用户

分页获取题目(包装类)、根据id获取题目(包装类)、分页获取题目提交列表、根据id获取提交题目详情

提交题目(限流器)

题目提交流程

向题目提交表记录题目id,用户id,编程语言和用户代码,设置判题状态为待判题。通过消息队列将questionSubmit对象传递给判题服务

限流器

// 1、 声明一个限流器
RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);

// 2、 设置速率,5秒中产生3个令牌
rateLimiter.trySetRate(RateType.OVERALL, 3, 5, RateIntervalUnit.SECONDS);

// 3、试图获取一个令牌,获取到返回true
rateLimiter.tryAcquire(1)

RateType.OVERALL:所有实例共享令牌

RateType.PER_CLIENT�:单实例令牌数

redission分布式限流采用令牌桶思想和固定时间窗口,trySetRate方法设置桶的大小,利用redis key过期机制达到时间窗口目的,控制固定时间窗口内允许通过的请求量。

判题服务

判题模块作用

查询题目提交和题目信息,调用代码沙箱,把代码和输入用例交给代码沙箱去执行,收集输出结果并执行判题逻辑

判题流程

通过消息队列获得questionSubmit对象,获取题目信息,判断题目是否存在。存在提交数加1。获取用户代码,编程语言,输入用例,输出用例。更新判题状态为判题中,调用代码沙箱,获取程序运行结果,设置判题上下文对象,采用策略模式,调用不同判题方法进行判题(主要是比较不同语言的时间和内存是否超出限制以及输出用例和代码沙箱程序执行结果是否一致)设置判题状态(判题成功/判题失败)和通过数

多种代码沙箱

定义通用代码沙箱调用接口,提供多种代码沙箱的实现类

实例代码沙箱:跑通业务流程

远程代码沙箱:自主实现的代码编译、执行的沙箱接口

三方代码沙箱:开源的代码沙箱服务 judge0的代码沙箱

远程和三方代码沙箱通过http调用

沙箱类型配置化:application.yml中动态配置沙箱类型

沙箱实例工厂化:读取配置,适用工厂模式,创建对应的代码沙箱实现类

沙箱调用代理化:使用代理模式,在调用代码沙箱前后进行统一的日志操作

代码沙箱

实现方式

Java原生代码沙箱和Docker代码沙箱

实现思路

用户代码保存为文件

编译代码,得到class文件

String compileCmd = "javac -encoding utf-8 Main.java";
Process compileProcess = Runtime.getRuntime().exec(comoileCmd);
int exitCode = compileProcess.waitFor()
if(exitCode==0){
    逐行读取输出;
}else{
    逐行读取正常输出;
    逐行读取异常输出;
}

执行java代码

String runCmd = "java Main.java"+inputArgs;
Process runProcess = Runtime.getRuntime().exec(runCmd);

收集整理输出结果

执行结果、执行时间、执行内存

文件清理,释放空间

错误处理,提升程序健壮性

异常情况

执行超时

占用内存

读文件

写文件

运行其他程序

执行高危操作

安全控制

超时控制

创建守护线程,超时自动中断Process

限制资源分配

java -Xmx256M

限制最大占用堆空间256M

限制代码–黑白名单

public static final List<String> balckList = Arrays.asList("Files","exec");

限制权限

Java安全管理器

public class DefaultSecurityManager extends SecurityManager{
    public void checkPermission(Permission perm) {
        throw new RuntimeException("权限异常"+perm.toString());
    }

    public void checkRead(String file) {
        throw new RuntimeException("Read权限异常"+file);
    }

    public void checkWrite(String file) {
        throw new RuntimeException("Write权限异常"+file);
    }

    public void checkExec(String file) {
        throw new RuntimeException("Exec权限异常"+file);
    }

    public void checkConnect(String host,int port) {
        throw new RuntimeException("Connect权限异常"+host+":"+port);
    }
    
}

执行Java代码时

java -Dfile.encoding=UTF-8 -Djava.security.manager=DefaultSecurityManager -cp . Main

运行环境隔离

Java原生代码沙箱

通过Process.exec执行命令行操作来执行代码,并通过Process对象的流来获取输出结果,不够安全

Docker代码沙箱

创建隔离的Java容器并且通过exec命令在容器内执行Java代码和获取输出,更加安全。

用户代码保存为文件

编译为.class文件

拉取镜像、创建容器、运行容器,执行代码,得到输出结果

创建一个交互容器,创建容器时,指定文件路径,把本地文件同步到容器中

创建容器时,进行内存限制,网络限制,读写限制

设计模式

工厂模式

代理模式

策略模式

模版方法模式

BNUEP Offline Judge 北京师范大学珠海分校离线评测系统是在具备题目测试数据的情况下,能无联网自动评测ACM/ICPC模式的源代码评测系统(即本地测试工具、评测机)。它主要有以下功能(所有的功能都无需联网,在本机即可实现): *评测核心功能: 基本具备Online Judge的判题核心功能,如编译代码、内存限定,时间限定,获取代码长度等; *支持多种语言: 1.0 Beta2版本支持C/C++、Pascal、C#、JAVA; *出题模式 可以在有标准输入数据和标准程序的情况下,由系统产生标准输出数据,并可批量保存,同时自动命名标准输出数据的后缀; *文本高亮对比 在判题后,可以直接在本系统中将自己的程序输出和标准输出进行高亮的文本差异对比,操作类似于一些文本对比软件,在一定程度上可以较方便地发现WA代码的出错细节; *支持不限时执行代码 这个功能可以在一定程度上检测TLE代码的算法是否正确的,当然,不能是跑一天都没跑出来的程序; *打包与加密测试数据 使用加密后的数据可以正常判题,但不显示标准输出。这个功能是为了弥补放出去给别人评测的测试数据是明文的缺陷。加密之后评测方就看不到测试数据。这样就既可以实现离线评测,又可以实现Online Judge上的对测试数据屏蔽; ACM-ICPC简介: ACM国际大学生程序设计竞赛(简称ACM-ICPC)是由国际计算机界具有悠久历史的权威性组织ACM学会(Association for Computing Machinery)主办,是世界上公认的规模最大、水平最高、参与人数最多的大学生程序设计竞赛,其宗旨是使大学生能通过计算机充分展示自己分析问题和解决问题的能力。 ACM-ICPC的每一道题,都具备题目、需求描述、输入格式描述、输出格式描述、样例输入和样例输出共六大信息,有些题目还有一定的提示。此外,裁判还额外存储了关于该题的一组或多组对选手屏蔽的标准输入和标准输出数据,这些测试数据已经经过验证符合题意要求。当用户提交一道题目的源码之后,裁判会将该源码放入评测系统中编译运行,并使用标准输入作为用户程序的输入,然后获取用户程序的输出,接着,将用户程序输出和标准输出比较,最后返回给用户一个评判结果。评判结果包括:Accepted(测试通过)、Compile Error(编译失败)、Memory Limit Exceed(内存超出限制)、Presentation Error(格式错误)、Runtime Error(运行时错误,可能是数组越界,改写只读的内存,除零,栈或堆溢出等错误)、Time Limit Exceed(时间超出限制)、Wrong Answer(答案错误)等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天不coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值