王成 陳果 孫宸 歐陽純萍
摘 要: 通過分析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