龍騰文化|愛玩課線上教學平台

愛玩課是一套課堂互動教學及課後作業教學管理系統,讓師生在課堂上即時問答,活化課堂氣氛,課後派發作業複習知識,所有的學習過程皆能匯出學習歷程,並提供完整教學內容讓龍騰教師暢行使用。
Cover
  • 課堂即時問答

  • 課後作業考試測驗

  • 彙整完整龍騰教學資料庫

  • 自建教學包進行上課

  • 學習歷程全紀錄

  • 支機掃描就能使用

  • 多題型設定互動

  • 塗鴉畫畫看獨特互動功能

  • 官方公告設置

龍騰愛玩課是一個可以讓老師在課堂上與學生即時互動的平台,學生可以藉由手機或平板登入到遊戲室,在遊戲室內搶答老師事前製作的各種問題,如選擇、問答、繪圖等。國外類似的平台有 Quizizz, Kahoot, NearPod 等網站,已經存在許久,這算是台灣少見的即時互動類型的教育網站。

當初接到龍騰尋求委託想要製作這種互動問答式網站時,就知道並不是以一般形式的網站技術可以完成的。類似這種即時互動遊戲室,一般來說都要以 WebSocket 技術來製作,才有辦法達到雙向互動的功能。

市面上常見的WebSocket通常是以Node.js的 Socket.io之類的套件編寫伺服器端,因為即時互動需要快速的反應與長連結,以傳統PHP技術是做不到的。即便少數如ReactPHP可以做到Async異步執行,在效能上還是會有不少瓶頸。

還好近年來,PHP的Swoole擴充套件已經越來越成熟,在我們踏入的時候,v4版協程化技術已經可以用在生產環境了,所以我們主要是以協程的方式編寫愛玩課的互動伺服器。原本確實考慮以Node.js編寫,但後續考量到長期維護下,能統一讓 php工程師維護後端,技術管理上會比較穩定,最後決定嘗試將Swoole用在正式運作環境上面,後續也確實能夠運作得不錯。

龍騰愛玩課資訊

網站主要目的是讓老師可以建立自己的互動遊戲或作業,根據教科書的書籍來編排章節進度,「即課互動」可以用在課堂即時互動搶答,「作業」則定時自動分派到學生帳號內,線上作答。

目前網站運作狀態,考量到前一兩年還算實驗階段,目前僅製作單體伺服器。在專案接洽的早期其實已經規劃好分散式架構,但後來考量到維護成本與早期使用者數量的問題,決定先採單機架構,慢慢驗證網站的營運成承載。

Swoole 主要用在遊戲室的執行環境,而網站本體的課程編輯、上稿,依然採用傳統LAMP技術。不過為了優良的使用者體驗,我們製作了非常流暢的拖拉介面與即時儲存編輯系統,不用頻繁的按儲存按鈕,就可以保留編輯資料。

我們如何使用Swoole

之所以使用Swoole,是因為即時互動的伺服器需要以下幾種特性:

  • WebSocket 長連接
  • 雙向互動
  • 伺服器要能即時推播訊息
  • 用戶端傳輸訊息不用重複握手,增加效率
  • 當有 上百/上千 人同時使用時,Database/Filesystem/IO等不能阻塞應用

雖然最後只採用了單體架構,但如果異步做的好,服務承載量還是可以很高的,畢竟遊戲室畫面全部都交給Vue.js做Client-Side-Rendering(CSR),伺服器不用大量處理View與字串,效能耗損沒有一般高承載網站來得大。

Swoole提供兩種運作模式,分別是進程模式與協程模式,進程模式每次打開的Task都會是獨立進程,依賴於process之間的管理機制互相溝通訊息。而協程模式全部運作在一個進程上,多個任務間的記憶體交流比較容易。我們目前是採用協程模式,所以可以更快速的開發,並在多次的任務間共享遊戲室狀態。

推播功能

另外,伺服器主動推播,有賴於Sub/Pub機制,這部份是交給Redis執行,遊戲室每次啟動後,會把 MySQL 內暫存的遊戲狀態(是一個大JSON)載入到Redis內,然後每個使用者進入遊戲室,啟動WebSocket連接後,他的連線任務就會監聽這個狀態記錄。(當時差一點跑去研究MySQL的Pub/Sub,真的有這種方案,是用bin log來做的)

只要老師按下「下一章節」的按鈕,就會更改這個狀態內的章節編號,Redis一旦偵測到內容有改變,就會立即發佈更新通知給主機上所有監聽的任務,該任務再自行發給對應的玩家 Connect ID,於是玩家的瀏覽器會收到最新的遊戲狀態或指令任務。我們再搭配Vue.js的狀態自動監測機制,就可以在狀態變更後,自動控制HTML轉往下一個章節。

以上是簡單的描述整個遊戲狀態更新運作過程,當然實際上還會更複雜,例如有些個資與解答資料在伺服器運作完之後,要先剃除掉才可以發佈給玩家瀏覽器。也有些老師才應該收到的訊號,學生不應該收到之類的。

圖為老師的控制介面,可以決定題目的跳轉與開始作答
而學生的作答介面則只能做答,看不到其他人的資訊

跨任務溝通與遊戲室處理

在協程模式下,每個使用者對伺服器發起的連結,都是同一個進程,記憶體共享比較方便(當然一個程式沒寫好就所有人一起炸)。Swoole的Channel, Table, Timer 機制,可以讓我們有效的共享其他任務所產生的資源。例如Timer機制,可以設定N秒後作答時間結束,一旦時間結束就會自動通知遊戲室內的所有玩家結束這個回合。

但網站上同時會有非常多個遊戲室在玩遊戲,每個玩家又會有自己的Connect ID,所以可以用 Table功能來共享遊戲室ID,當遊戲室啟動後,會分配一個新的遊戲室ID存在記憶體中,所有加入的玩家Connect ID都會註冊在這個遊戲室ID下面,當有新的訊息要發送時,就會根據遊戲室 ID發送給遊戲室下面的所有玩家Connect ID,這樣就能做到一次有多個遊戲室同時進行活動。

如果有心研究這個機制設計的話,可以看看 Socket.IO 的 Rooms 設計。

長時間運作與還原機制

由於Swoole是開一個進程在背景運作,很容易因為崩潰造成所有玩家不能進行遊戲(正常來說不應該寫出一個會崩潰的程式)。保險起見我們都會加裝forever.js來偵測進程運作,一旦崩潰就自動重啟。

另外,Log機制非常重要,建議一定要從程式編寫的一開始,就替所有流程、錯誤、資料庫與IO等等做好Log機制,不然炸掉時發生什麼事情都無法追溯。我們為了能有效除錯,每次的DB Query,Timer與Channel跨任務分享記憶體時的協程編號,全部都會做記錄。

遊戲室運作中的Log

其他技術

Session

Session不能直接用Native的session_tart,所以要改成自己編寫Handler去存取session file,能用Database管理session會更好。

DB Pool

可以善用Channel的阻塞功能編寫Connection pool。我們是自己寫的,不過現在中國的很多框架都有現成的可以用。

簡單結尾

這篇一部小心寫的太長了,實際上整個系統中的Swoole運用技巧還有非常多細節,沒辦法短時間一一介紹,也許之後有空再寫第二篇。整體來說,Swoole不是一般PHP工程師可以掌握的技術,因為跟以前傳統的同步邊程差異太大了。一不小心就會讓A老師去操控到B老師的遊戲室。

另外,在應用層裡面,記憶體控管與DI binding也會是一門挑戰,哪些class在初始化時就要bind進Container中,哪些則是在Task的Runtime才bind,並且結束後要確認銷燬,都是需要規劃清楚的。由於Process會長時間運作,就算PHP有自動回收機制,但許多 Array cache 或記憶體共享沒有處理好就會造成 Memory Leak。

這個專案早在2018年就開工了,當時Swoole的討論度還沒有現在這麼熱烈,很多重要系統如Session, DB Pool, Rooms, Pub/Sub也還沒有工具能用,所以我們得要自己編寫。現在要踏入的話,應該已經有不少框架可以快速開發了。

總而言之,Swoole畢竟可以達到傳統PHP所沒有的特點,語法也不用再重新學習,還是有非常高的導入價值。

 

龍騰愛玩課/線上教學平台

學生都愛的玩課教育,課堂教學數位化

教育與學習輕鬆上手

 

 

 

課堂的即時問答,老師建立互動題組,直接在課堂上與學生互動

增加學習的樂趣,激發學生主動學習

 

 

老師能自由創建專屬課程並上傳教學資源,讓教案理念一目瞭然

 

 

建置課後作業讓學生重點複習,題型自由變化,學習成效加倍

 

 


強大後台管理系統

基礎各式資源編輯及會員管理外,能支援報表匯出功能,可分析課程使用狀況與學生學習成效

 

Simular

如果您喜歡我們的作品

歡迎與我們聯絡取得服務說明