王成 陈果 孙宸 欧阳纯萍
摘 要: 通过分析Online Judge系统目前的数据处理需求,结合MySQL、MongoDB、Redis三個数据库的不同特性,实现Online Judge系统多数据库应用。MySQL数据库理论成熟、冗余度低、安全性高,适合处理结构化数据和具有较高安全要求的数据;MongoDB数据库存储方式灵活,适合处理非结构数据和扩展可能性大的数据;Redis是高性能的key-value内存数据库,适合处理热点数据,还可以与Celery结合,实现生产者-消费者模式,处理并发问题。在对Online Judge系统进行多数据库应用之后,实验效果良好。
关键词: MySQL; MongoDB; Redis; Online Judge; 数据库应用
中图分类号:TP392 文献标志码:A 文章编号:1006-8228(2018)09-24-04
Abstract: By analyzing the current data processing requirements of Online Judge system and combining the different characteristics of MySQL, MongoDB and Redis database, the multiple database application of the Online Judge system is realized. MySQL database has mature theory, low-redundancy and high-security. Therefore, It is suitable for processing data that are structured or with higher safety requirement. The storage mode of MongoDB is flexible, so it is suitable for processing data that are unstructured or with high extending possibility. Redis is a high-performance key-value in-memory database. It is fit for processing hot spot data and can be combined with Celery to implement a producer-consumer model, handling concurrency issues. The Online Judge system works well after being optimized with the application of multi-database.
Key words: MySQL; MongoDB; Redis; Online Judge; database application
0 引言
随着程序设计竞赛影响力的扩大,许多高校都自行组建在线裁判系统(Online Judge,简称OJ)。现在,Online Judge除了用于程序设计竞赛的训练和比赛之外,还用于辅助程序设计课程的实验[1]、在线考试系统判卷[2]等。程序设计竞赛规模越来越大,比赛也越来越多,加上在线裁判系统应用领域的扩展,Online Judge系统需要处理的数据量会不断增加,数据形式也会更加丰富。
以往的Online Judge系统一般采用单一的关系型数据库(SQL数据库),例如MySQL数据库,关系型数据库经历了几十年的发展,其具有理论基础完备、产品成熟、冗余度低、安全性高、使用方便、利于维护等优点[3]。但是,由于Online Judge系统的迅速发展,仅使用单一的关系型数据库势必会面临新的挑战:①数据库高并发读写,程序设计竞赛时间为5个小时,有的网络赛时间只有2小时左右,短时间内系统对数据库的请求会比较集中,高并发的请求会使得数据库性能下降。以Codeforces(一家为计算机编程爱好者提供在线评测系统的网站)为例,每场比赛将近有7000多人,而比赛时间一般为2-3小时,短时间内就会产生大量的请求;②非结构化数据的存储,随着Online Judge系统应用领域的扩展,其需要处理的数据不单单是结构化数据,还需要存储一些非结构化数据,如文档、图片。③字段的扩展,有些数据是需要根据实际情况灵活地进行存储。
针对上述问题,本文提出一种关系型数据库和非关系型数据库(NoSQL数据库)相结合的多数据库应用方式,在Online Judge系统中,同时应用MySQL、MongoDB、Redis三个数据库[5],MySQL数据库用来处理结构化数据,如用户信息,MongoDB数据库用来处理非结构化或字段需要扩展的数据,如文件、图片、题目输入输出描述,Redis用来实现异步队列,存储验证码以及其他高频访问的数据。将关系型数据库与非关系型数据库相结合,使Online Judge系统可以更加灵活地处理多种类型的数据,提高系统的数据处理性能,满足其在不同领域的扩展。
1 数据库整体架构
Online Judge数据来源有:用户信息数据、题目描述数据、提交记录数据、比赛信息数据、缓存和异步队列。不同的数据来源数据格式不同,可以分为结构化数据和非结构化数据,其中用户信息主要为用户id、用户名、邮箱、密码等,比赛信息主要为比赛Id、时间、题目编号等,提交记录主要为提交Id、提交的代码、提交的结果等,这些数据为结构化数据,适合使用MySQL存储;题目描述中包含的图片、文件等,这些数据为非结构化数据,适合使用MongoDB存储。Redis缓存主要涉及用户身份的认证信息、Session等一些热点数据,异步队列用于注册时验证码的发送,题目的提交等系统后台队列。系统存储的整体架构如图1所示。
2 数据库核心设计
2.1 MySQL数据库的应用
MySQL数据库数据模型简单,关系和实体都是用二维表表示,同时,MySQL数据库安全性高,对于系统中用户信息、题目描述、提交记录,这些结构化且需要较高安全性考虑的数据,适合使用MySQL数据库来存储。Online Judge系统对于MySQL数据库的应用比较成熟,本文就不作过多的描述了。
2.2 MongoDB数据库的应用
MongoDB[7]是一个基于分布式文件存储的数据库,由C++语言编写,旨在为Web应用提供可扩展的高性能数据存储解决方案。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。与关系型数据库相比,MongoDB获取数据更加快捷,内置GridFS,支持大容量存取,第三方支持丰富。
在Online Judge系统中,利用MongoDB数据库灵活的存储方式,弥补MySQL数据库在处理这部分数据时的不足。
对于用户提交数据,一般为字符串形式,在系统的应用领域扩展之后,会以文件的形式提交。另外,如果Online Judge应用于在线考试系统,那么题目的结构不再固定,意味着用户提交的答案也会相应变化,这就需要系统在处理用户提交时,有一个良好的扩展性。对于系统中的题目,有些是文件形式,有些是字符串形式,有些甚至还可能包含图片,题干中输入输出描述的数量也会有所不同。这些数据使用MySQL数据库处理时就显得力不从心,而用MongoDB数据库处理上述数据就相对灵活了。
MongoDB数据库除了用于处理上述数据外,还有一个作用:用来存储系统日志。服务器在日常运维过程中,会产生大量的日志信息,如用户行为、错误、警告等,日志通常是以文件形式存储,这种形式的日志需要到相应的服务器上才能查看,不够方便,并且这种形式的日志也不利于做分析。与其相比,使用MongoDB数据库存储日志有以下几个优点:
⑴ 更加适合远程访问;
⑵ 可以固定collection的大小,MongoDB会自动复用空间,减少人工对日志的管理;
⑶ 存储灵活,随时可以添加需要的字段;
⑷ 可以自定义日志结构,建立索引,分析日志更方便、高效。
以Python的日志模塊为例,其有四个基本组成部分:记录器(Logger)、处理器(Handler)、格式化器(Formatter)、过滤器(Filter)。其中,处理器(Handler)主要作用就是把日志信息发送到相应的位置。使用MongoDB数据库存储日志时,通过安装插件Python log4mongo,为Python logging模块提供一个MongoDB的Handler,然后对Handler进行相应的配置,常用的配置参数有host、port、database_name、collection等,再使用logging模块中的addHandler()函数添加处理器,最后调用debug()、info()、warn()、error()等方法记录日志信息。
2.3 Redis实现缓存
Redis[8]是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。其作为一个高性能的key-value数据库,很大程度弥补了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。
在Online Judge系统中,用Redis存储高频访问的热点数据,优化数据库响应性能,包括验证码、Token信息、Session信息、比赛过程的题目信息,非比赛期间高频访问的题目,登录频繁的用户信息。在存储数据时使用key-value类型,本文是调用cache的set()、get()方法。另外,Redis会周期性地把更新的数据写入磁盘或者把修改操作写入追加的记录文件。Redis的这一可持久化特性对于缓存中的数据起到了很好的保护作用,避免系统异常中断,而造成缓存中数据全部丢失。
2.4 Redis与Celery结合,实现异步队列
在Online Judge中,将Redis与Celery结合实现生产者-消费者模式,处理系统的并发问题。Celery是一个分布式任务调度模块,其架构由消息中间件(Broker)、任务执行单元(Worker)、任务结果存储(Result Backend)三部分组成,Celery本身不提供消息服务,需要使用第三方提供的消息中间件,本文使用Redis数据库充当消息中间件,Online Judge的Web应用充当生产者,Celery Worker充当消费者,进行并发处理(图2)。
为减少用户等待系统响应的时间,提高用户体验感,通常会先给用户的操作一个响应,告知用户系统正在执行请求,然后把任务加入到Celery的队列中,系统再完成用户的请求。比如用户在注册账号时,先给用户返回一个“验证码正在发送”的响应,然后把发送邮件的任务加入队列,提高系统实时性。实现该功能时,需要在相应的App下创建tasks.py文件。对于tasks.py中的任务,在方法上加上“@app.task”装饰,然后在视图views.py中,通过delay()方法调用tasks.py中的任务即可。
除此之外,还可以利用Celery+Redis完成定时任务,比如系统题目的更新,清理系统缓存,给系统管理员发送日志等。
3 实验
本文提出的多数据库应用模式,实验过程中使用的是Django框架,并安装第三方插件:pymysql、mongoengine、pymongo、django-redis,实现对MySQL、MongoDB、Redis数据库的应用。实验表明,系统能够处理多种类型的数据,实现了Online Judge数据处理的可扩展性,该模式结构灵活,后期可维护性高,提高了系统性能。为了更加直观地显示实验效果,截取了系统的部分界面(图3)。
4 结束语
本文根据MySQL、MongoDB、Redis三个数据库所具有的独特优势,将它们应用于Online Judge系统中,增加了系统在其他领域的扩展,满足了系统处理不同数据类型的需要,也提高了系统的性能。
未来将进一步研究系统的业务需求,改进数据库之间结合的模式,更加充分地利用数据库特性,提高系统数据处理能力。
参考文献(References):
[1] 廖雪花,厉兰洁,唐思娩.基于Online Judge的C语言程序设计实验课教学改革研究[J].计算机教育,2016.6:130-132
[2] 周志锋,童凌,王浩茂,李海燕.基于自动组卷与判卷的在线考试系统设计[J].软件导刊,2017.16(6):66-69
[3] ?gnes Vathy-Fogarassy,Tamás Hugyák. Uniform data access platform for SQL and NoSQL database systems[J]. Information Systems,2017.69.
[4] 余穎,李晓昀,欧阳纯萍.一种SSH框架的在线程序自动评判系统的设计与实现[J].南华大学学报(自然科学版),2012.26(4):65-68
[5] 朱亚兴,余爱民,王夷.基于Redis+MySQL+MongoDB存储架构应用[J].微型机与应用,2014,33(13):3-5,9
[6] Django. Django makes it easier to build better Web appsmore quickly and with less code[EB/OL]. https://www.djangoproject.com/
[7] MongoEngine.MongoEngineUserDocumentation[EB/OL].http://docs.mongoengine.org
[8] 马豫星.Redis数据库特性分析[J].物联网技术,2015.5(3):105-106
[9] Celery.Celery: Distributed Task Queue[EB/OL]. http://www.celeryproject.org