關於在線答題系統設計的一些想法

業務場景

  • 100道不定項選擇題,不同考生的題目順序不一樣
  • 200位考生在規定時間同時開始和結束答題
  • 考試開始後可以查看題目列表,不一定要按照順序作答,已作答的題目可以修改,最終分數以交卷時的分數爲準
  • 在考場後臺的辦公室中可以實時刷新分數的排行榜
  • 考試環境爲學校的機房,網絡環境爲局域網
  • 考試題目爲文學類知識競賽,考生准考證號和身份證號分別作爲用戶名和密碼

需求分析

1、爲了避免相互抄襲,不同考生的題目順序需要不一樣,這裏需要打亂題目的順序。
2、考試開始作答的時間可能不同,但是都要在統一的時間截止答題,這就要求考生的機器需要統一時間,能夠在考試結束後自動提交。
3、在考試過程中要能夠查看分數排行版,這裏可以在考生每回答或者更新題目的時候都去刷新排行榜,或者在管理段定時刷新的時候再去計算所有考試的分數和排行榜情況。
4、考試環境爲本地局域網,考試過程中有監考老師進行巡邏,並且考試羣體大多不具備計算機知識,這裏可以基本排除考生進行抓包後主動調用接口的場景。


設計思路

打亂題目順序

1、使用mysql的隨機排序方法,ORDER BY RAND(准考證號)
2、在用戶首次登錄時,可以使用php的shuffle($arr)函數將題目順序打亂後返回,並將打亂後的數組順序再次存儲到數據庫中。
##統一時間交卷
交卷時間是確定的,我們要以服務器時間爲準,用戶機器上的時間不可靠。用戶的每次請求的返回中,我們都給返回給用戶一個交卷的截止時間,前端的js就基於該截止時間顯示考試的剩餘時間。在後端我們需要記錄每個考生的交卷時間,在截止時間到達後不能再提交。
由於考試開始和結束時間都是一樣的,所以這時候的併發了會比較大,我們可以讓用戶隨機延遲5s以內,通過閱讀考場規則或者增加loading圖的方式可以優化交互體驗。



數據都存儲在本地

考慮到用戶都是不具備計算機知識的,網絡是局域網絡,且現場有監考老師的存在,可以基本排除有用戶會抓包或模擬請求的可能。
在用戶登錄後,查詢題目列表時也把題目的答案返回給用戶,這裏可以將答案做一個簡單的加密。在用戶答題後可以根據答案計算用戶當前的得分,只更新用戶的得分,用戶後臺的顯示。在用戶交卷時再將本地數據全部上傳到接口,這樣最多在用戶交卷時會有卡頓,在用戶答題過程中還是非常流暢的。

這個場景比較特殊,存在很大的安全隱患,除非接口性能實在不能滿足,最好還是不要使用。

基於Mysql的系統設計

生成隨機題目

SELECT title,option1,option2,option3,option4 FROM questions ORDER BY RNAD('准考證號')
在用戶登錄後,將題目一次性取出,如果擔心用戶不小心關閉了瀏覽器或者電腦斷電的話,cookie只能存放4k的數據,並且會隨着請求發送,增加請求耗時,可以將數據存儲到localStorage中。
用戶作答或修改答案時都會調用接口,所以即使用戶關閉了瀏覽器,再次打開重新登錄的話,也是能夠保存之前的答題記錄的,只需要重新拉取一份題目列表就可以了。

記錄用戶答題結果

key questionId answer time
按照這種格式記錄用戶每道題目最後一次更新的答案,並記錄用戶的最後一次更新時間。
爲了後期覆盤,我們需要記錄用戶的登錄、退出、交卷、答題和修改的操作日誌,爲了不影響接口的響應時間,我們可以將日誌序列還之後添加到List裏面,也可以使用redis或者RambbitMQ的消息隊列來異步記錄日誌。

排行榜的刷新

1、在用戶作答或者更新題目的時候計算用戶的分數的話會影響答題接口的響應時間。
2、當管理端刷新排行榜時計算所有用戶的分數,需要讀取200*200條答題記錄,計算分數並更新到數據庫,然後進行排序後輸出,短時間進行大量的數據操作會對數據庫產品一定的壓力,進而影響考試插入答題記錄的速度。
3、我們可以採用swoole、redis或者RambbitMQ的消息隊列,將第一種方案的接口請求立即返回,然後通過異步任務計算該考生的分數,並更新到數據庫中。管理端的排行榜直接讀取數據庫中的成績表,排序後顯示。這裏的消息隊列和日誌一樣,即使消息丟失了也不會有什麼大的影響。

交卷操作

在用戶交卷時,我們可以直接調用php方法進行考生成績的同步計算,爲了避免同一時間很多考生同時調用接口,可以隨機等待3s,然後再調用交卷接口。

基於Redis的系統設計

生成隨機題目

記錄用戶答題結果

排行版的刷新

交卷操作

日誌記錄

壓力測試

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章