王成 陳果 孫宸 歐陽(yáng)純萍
摘 要: 通過(guò)分析Online Judge系統(tǒng)目前的數(shù)據(jù)處理需求,結(jié)合MySQL、MongoDB、Redis三個(gè)數(shù)據(jù)庫(kù)的不同特性,實(shí)現(xiàn)Online Judge系統(tǒng)多數(shù)據(jù)庫(kù)應(yīng)用。MySQL數(shù)據(jù)庫(kù)理論成熟、冗余度低、安全性高,適合處理結(jié)構(gòu)化數(shù)據(jù)和具有較高安全要求的數(shù)據(jù);MongoDB數(shù)據(jù)庫(kù)存儲(chǔ)方式靈活,適合處理非結(jié)構(gòu)數(shù)據(jù)和擴(kuò)展可能性大的數(shù)據(jù);Redis是高性能的key-value內(nèi)存數(shù)據(jù)庫(kù),適合處理熱點(diǎn)數(shù)據(jù),還可以與Celery結(jié)合,實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模式,處理并發(fā)問(wèn)題。在對(duì)Online Judge系統(tǒng)進(jìn)行多數(shù)據(jù)庫(kù)應(yīng)用之后,實(shí)驗(yàn)效果良好。
關(guān)鍵詞: MySQL; MongoDB; Redis; Online Judge; 數(shù)據(jù)庫(kù)應(yīng)用
中圖分類(lèi)號(hào):TP392 文獻(xiàn)標(biāo)志碼:A 文章編號(hào):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 引言
隨著程序設(shè)計(jì)競(jìng)賽影響力的擴(kuò)大,許多高校都自行組建在線裁判系統(tǒng)(Online Judge,簡(jiǎn)稱OJ)?,F(xiàn)在,Online Judge除了用于程序設(shè)計(jì)競(jìng)賽的訓(xùn)練和比賽之外,還用于輔助程序設(shè)計(jì)課程的實(shí)驗(yàn)[1]、在線考試系統(tǒng)判卷[2]等。程序設(shè)計(jì)競(jìng)賽規(guī)模越來(lái)越大,比賽也越來(lái)越多,加上在線裁判系統(tǒng)應(yīng)用領(lǐng)域的擴(kuò)展,Online Judge系統(tǒng)需要處理的數(shù)據(jù)量會(huì)不斷增加,數(shù)據(jù)形式也會(huì)更加豐富。
以往的Online Judge系統(tǒng)一般采用單一的關(guān)系型數(shù)據(jù)庫(kù)(SQL數(shù)據(jù)庫(kù)),例如MySQL數(shù)據(jù)庫(kù),關(guān)系型數(shù)據(jù)庫(kù)經(jīng)歷了幾十年的發(fā)展,其具有理論基礎(chǔ)完備、產(chǎn)品成熟、冗余度低、安全性高、使用方便、利于維護(hù)等優(yōu)點(diǎn)[3]。但是,由于Online Judge系統(tǒng)的迅速發(fā)展,僅使用單一的關(guān)系型數(shù)據(jù)庫(kù)勢(shì)必會(huì)面臨新的挑戰(zhàn):①數(shù)據(jù)庫(kù)高并發(fā)讀寫(xiě),程序設(shè)計(jì)競(jìng)賽時(shí)間為5個(gè)小時(shí),有的網(wǎng)絡(luò)賽時(shí)間只有2小時(shí)左右,短時(shí)間內(nèi)系統(tǒng)對(duì)數(shù)據(jù)庫(kù)的請(qǐng)求會(huì)比較集中,高并發(fā)的請(qǐng)求會(huì)使得數(shù)據(jù)庫(kù)性能下降。以Codeforces(一家為計(jì)算機(jī)編程愛(ài)好者提供在線評(píng)測(cè)系統(tǒng)的網(wǎng)站)為例,每場(chǎng)比賽將近有7000多人,而比賽時(shí)間一般為2-3小時(shí),短時(shí)間內(nèi)就會(huì)產(chǎn)生大量的請(qǐng)求;②非結(jié)構(gòu)化數(shù)據(jù)的存儲(chǔ),隨著Online Judge系統(tǒng)應(yīng)用領(lǐng)域的擴(kuò)展,其需要處理的數(shù)據(jù)不單單是結(jié)構(gòu)化數(shù)據(jù),還需要存儲(chǔ)一些非結(jié)構(gòu)化數(shù)據(jù),如文檔、圖片。③字段的擴(kuò)展,有些數(shù)據(jù)是需要根據(jù)實(shí)際情況靈活地進(jìn)行存儲(chǔ)。
針對(duì)上述問(wèn)題,本文提出一種關(guān)系型數(shù)據(jù)庫(kù)和非關(guān)系型數(shù)據(jù)庫(kù)(NoSQL數(shù)據(jù)庫(kù))相結(jié)合的多數(shù)據(jù)庫(kù)應(yīng)用方式,在Online Judge系統(tǒng)中,同時(shí)應(yīng)用MySQL、MongoDB、Redis三個(gè)數(shù)據(jù)庫(kù)[5],MySQL數(shù)據(jù)庫(kù)用來(lái)處理結(jié)構(gòu)化數(shù)據(jù),如用戶信息,MongoDB數(shù)據(jù)庫(kù)用來(lái)處理非結(jié)構(gòu)化或字段需要擴(kuò)展的數(shù)據(jù),如文件、圖片、題目輸入輸出描述,Redis用來(lái)實(shí)現(xiàn)異步隊(duì)列,存儲(chǔ)驗(yàn)證碼以及其他高頻訪問(wèn)的數(shù)據(jù)。將關(guān)系型數(shù)據(jù)庫(kù)與非關(guān)系型數(shù)據(jù)庫(kù)相結(jié)合,使Online Judge系統(tǒng)可以更加靈活地處理多種類(lèi)型的數(shù)據(jù),提高系統(tǒng)的數(shù)據(jù)處理性能,滿足其在不同領(lǐng)域的擴(kuò)展。
1 數(shù)據(jù)庫(kù)整體架構(gòu)
Online Judge數(shù)據(jù)來(lái)源有:用戶信息數(shù)據(jù)、題目描述數(shù)據(jù)、提交記錄數(shù)據(jù)、比賽信息數(shù)據(jù)、緩存和異步隊(duì)列。不同的數(shù)據(jù)來(lái)源數(shù)據(jù)格式不同,可以分為結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù),其中用戶信息主要為用戶id、用戶名、郵箱、密碼等,比賽信息主要為比賽Id、時(shí)間、題目編號(hào)等,提交記錄主要為提交Id、提交的代碼、提交的結(jié)果等,這些數(shù)據(jù)為結(jié)構(gòu)化數(shù)據(jù),適合使用MySQL存儲(chǔ);題目描述中包含的圖片、文件等,這些數(shù)據(jù)為非結(jié)構(gòu)化數(shù)據(jù),適合使用MongoDB存儲(chǔ)。Redis緩存主要涉及用戶身份的認(rèn)證信息、Session等一些熱點(diǎn)數(shù)據(jù),異步隊(duì)列用于注冊(cè)時(shí)驗(yàn)證碼的發(fā)送,題目的提交等系統(tǒng)后臺(tái)隊(duì)列。系統(tǒng)存儲(chǔ)的整體架構(gòu)如圖1所示。
2 數(shù)據(jù)庫(kù)核心設(shè)計(jì)
2.1 MySQL數(shù)據(jù)庫(kù)的應(yīng)用
MySQL數(shù)據(jù)庫(kù)數(shù)據(jù)模型簡(jiǎn)單,關(guān)系和實(shí)體都是用二維表表示,同時(shí),MySQL數(shù)據(jù)庫(kù)安全性高,對(duì)于系統(tǒng)中用戶信息、題目描述、提交記錄,這些結(jié)構(gòu)化且需要較高安全性考慮的數(shù)據(jù),適合使用MySQL數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)。Online Judge系統(tǒng)對(duì)于MySQL數(shù)據(jù)庫(kù)的應(yīng)用比較成熟,本文就不作過(guò)多的描述了。
2.2 MongoDB數(shù)據(jù)庫(kù)的應(yīng)用
MongoDB[7]是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),由C++語(yǔ)言編寫(xiě),旨在為Web應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案。它支持的數(shù)據(jù)結(jié)構(gòu)非常松散,是類(lèi)似json的bson格式,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類(lèi)型。與關(guān)系型數(shù)據(jù)庫(kù)相比,MongoDB獲取數(shù)據(jù)更加快捷,內(nèi)置GridFS,支持大容量存取,第三方支持豐富。
在Online Judge系統(tǒng)中,利用MongoDB數(shù)據(jù)庫(kù)靈活的存儲(chǔ)方式,彌補(bǔ)MySQL數(shù)據(jù)庫(kù)在處理這部分?jǐn)?shù)據(jù)時(shí)的不足。
對(duì)于用戶提交數(shù)據(jù),一般為字符串形式,在系統(tǒng)的應(yīng)用領(lǐng)域擴(kuò)展之后,會(huì)以文件的形式提交。另外,如果Online Judge應(yīng)用于在線考試系統(tǒng),那么題目的結(jié)構(gòu)不再固定,意味著用戶提交的答案也會(huì)相應(yīng)變化,這就需要系統(tǒng)在處理用戶提交時(shí),有一個(gè)良好的擴(kuò)展性。對(duì)于系統(tǒng)中的題目,有些是文件形式,有些是字符串形式,有些甚至還可能包含圖片,題干中輸入輸出描述的數(shù)量也會(huì)有所不同。這些數(shù)據(jù)使用MySQL數(shù)據(jù)庫(kù)處理時(shí)就顯得力不從心,而用MongoDB數(shù)據(jù)庫(kù)處理上述數(shù)據(jù)就相對(duì)靈活了。
MongoDB數(shù)據(jù)庫(kù)除了用于處理上述數(shù)據(jù)外,還有一個(gè)作用:用來(lái)存儲(chǔ)系統(tǒng)日志。服務(wù)器在日常運(yùn)維過(guò)程中,會(huì)產(chǎn)生大量的日志信息,如用戶行為、錯(cuò)誤、警告等,日志通常是以文件形式存儲(chǔ),這種形式的日志需要到相應(yīng)的服務(wù)器上才能查看,不夠方便,并且這種形式的日志也不利于做分析。與其相比,使用MongoDB數(shù)據(jù)庫(kù)存儲(chǔ)日志有以下幾個(gè)優(yōu)點(diǎn):
⑴ 更加適合遠(yuǎn)程訪問(wèn);
⑵ 可以固定collection的大小,MongoDB會(huì)自動(dòng)復(fù)用空間,減少人工對(duì)日志的管理;
⑶ 存儲(chǔ)靈活,隨時(shí)可以添加需要的字段;
⑷ 可以自定義日志結(jié)構(gòu),建立索引,分析日志更方便、高效。
以Python的日志模塊為例,其有四個(gè)基本組成部分:記錄器(Logger)、處理器(Handler)、格式化器(Formatter)、過(guò)濾器(Filter)。其中,處理器(Handler)主要作用就是把日志信息發(fā)送到相應(yīng)的位置。使用MongoDB數(shù)據(jù)庫(kù)存儲(chǔ)日志時(shí),通過(guò)安裝插件Python log4mongo,為Python logging模塊提供一個(gè)MongoDB的Handler,然后對(duì)Handler進(jìn)行相應(yīng)的配置,常用的配置參數(shù)有host、port、database_name、collection等,再使用logging模塊中的addHandler()函數(shù)添加處理器,最后調(diào)用debug()、info()、warn()、error()等方法記錄日志信息。
2.3 Redis實(shí)現(xiàn)緩存
Redis[8]是一個(gè)開(kāi)源的使用ANSI C語(yǔ)言編寫(xiě)、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫(kù),并提供多種語(yǔ)言的API。其作為一個(gè)高性能的key-value數(shù)據(jù)庫(kù),很大程度彌補(bǔ)了memcached這類(lèi)key/value存儲(chǔ)的不足,在部分場(chǎng)合可以對(duì)關(guān)系數(shù)據(jù)庫(kù)起到很好的補(bǔ)充作用。
在Online Judge系統(tǒng)中,用Redis存儲(chǔ)高頻訪問(wèn)的熱點(diǎn)數(shù)據(jù),優(yōu)化數(shù)據(jù)庫(kù)響應(yīng)性能,包括驗(yàn)證碼、Token信息、Session信息、比賽過(guò)程的題目信息,非比賽期間高頻訪問(wèn)的題目,登錄頻繁的用戶信息。在存儲(chǔ)數(shù)據(jù)時(shí)使用key-value類(lèi)型,本文是調(diào)用cache的set()、get()方法。另外,Redis會(huì)周期性地把更新的數(shù)據(jù)寫(xiě)入磁盤(pán)或者把修改操作寫(xiě)入追加的記錄文件。Redis的這一可持久化特性對(duì)于緩存中的數(shù)據(jù)起到了很好的保護(hù)作用,避免系統(tǒng)異常中斷,而造成緩存中數(shù)據(jù)全部丟失。
2.4 Redis與Celery結(jié)合,實(shí)現(xiàn)異步隊(duì)列
在Online Judge中,將Redis與Celery結(jié)合實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模式,處理系統(tǒng)的并發(fā)問(wèn)題。Celery是一個(gè)分布式任務(wù)調(diào)度模塊,其架構(gòu)由消息中間件(Broker)、任務(wù)執(zhí)行單元(Worker)、任務(wù)結(jié)果存儲(chǔ)(Result Backend)三部分組成,Celery本身不提供消息服務(wù),需要使用第三方提供的消息中間件,本文使用Redis數(shù)據(jù)庫(kù)充當(dāng)消息中間件,Online Judge的Web應(yīng)用充當(dāng)生產(chǎn)者,Celery Worker充當(dāng)消費(fèi)者,進(jìn)行并發(fā)處理(圖2)。
為減少用戶等待系統(tǒng)響應(yīng)的時(shí)間,提高用戶體驗(yàn)感,通常會(huì)先給用戶的操作一個(gè)響應(yīng),告知用戶系統(tǒng)正在執(zhí)行請(qǐng)求,然后把任務(wù)加入到Celery的隊(duì)列中,系統(tǒng)再完成用戶的請(qǐng)求。比如用戶在注冊(cè)賬號(hào)時(shí),先給用戶返回一個(gè)“驗(yàn)證碼正在發(fā)送”的響應(yīng),然后把發(fā)送郵件的任務(wù)加入隊(duì)列,提高系統(tǒng)實(shí)時(shí)性。實(shí)現(xiàn)該功能時(shí),需要在相應(yīng)的App下創(chuàng)建tasks.py文件。對(duì)于tasks.py中的任務(wù),在方法上加上“@app.task”裝飾,然后在視圖views.py中,通過(guò)delay()方法調(diào)用tasks.py中的任務(wù)即可。
除此之外,還可以利用Celery+Redis完成定時(shí)任務(wù),比如系統(tǒng)題目的更新,清理系統(tǒng)緩存,給系統(tǒng)管理員發(fā)送日志等。
3 實(shí)驗(yàn)
本文提出的多數(shù)據(jù)庫(kù)應(yīng)用模式,實(shí)驗(yàn)過(guò)程中使用的是Django框架,并安裝第三方插件:pymysql、mongoengine、pymongo、django-redis,實(shí)現(xiàn)對(duì)MySQL、MongoDB、Redis數(shù)據(jù)庫(kù)的應(yīng)用。實(shí)驗(yàn)表明,系統(tǒng)能夠處理多種類(lèi)型的數(shù)據(jù),實(shí)現(xiàn)了Online Judge數(shù)據(jù)處理的可擴(kuò)展性,該模式結(jié)構(gòu)靈活,后期可維護(hù)性高,提高了系統(tǒng)性能。為了更加直觀地顯示實(shí)驗(yàn)效果,截取了系統(tǒng)的部分界面(圖3)。
4 結(jié)束語(yǔ)
本文根據(jù)MySQL、MongoDB、Redis三個(gè)數(shù)據(jù)庫(kù)所具有的獨(dú)特優(yōu)勢(shì),將它們應(yīng)用于Online Judge系統(tǒng)中,增加了系統(tǒng)在其他領(lǐng)域的擴(kuò)展,滿足了系統(tǒng)處理不同數(shù)據(jù)類(lèi)型的需要,也提高了系統(tǒng)的性能。
未來(lái)將進(jìn)一步研究系統(tǒng)的業(yè)務(wù)需求,改進(jìn)數(shù)據(jù)庫(kù)之間結(jié)合的模式,更加充分地利用數(shù)據(jù)庫(kù)特性,提高系統(tǒng)數(shù)據(jù)處理能力。
參考文獻(xiàn)(References):
[1] 廖雪花,厲蘭潔,唐思娩.基于Online Judge的C語(yǔ)言程序設(shè)計(jì)實(shí)驗(yàn)課教學(xué)改革研究[J].計(jì)算機(jī)教育,2016.6:130-132
[2] 周志鋒,童凌,王浩茂,李海燕.基于自動(dòng)組卷與判卷的在線考試系統(tǒng)設(shè)計(jì)[J].軟件導(dǎo)刊,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] 余穎,李曉昀,歐陽(yáng)純萍.一種SSH框架的在線程序自動(dòng)評(píng)判系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].南華大學(xué)學(xué)報(bào)(自然科學(xué)版),2012.26(4):65-68
[5] 朱亞興,余愛(ài)民,王夷.基于Redis+MySQL+MongoDB存儲(chǔ)架構(gòu)應(yīng)用[J].微型機(jī)與應(yīng)用,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數(shù)據(jù)庫(kù)特性分析[J].物聯(lián)網(wǎng)技術(shù),2015.5(3):105-106
[9] Celery.Celery: Distributed Task Queue[EB/OL]. http://www.celeryproject.org