新版台大課程網那些事

更新於 發佈於 閱讀時間約 14 分鐘
raw-image
「課程網站從來都沒修好」- 這是某年台大畢業歌的徵選的歌詞。

台大課程網是每個台大學生的必經之路,還記得我剛進台大的時候就被課程網這傢伙嚇得半死,選課還要加入購物車,而且購物車就算了,這個加入購物車的過程還會跳出新視窗,實在搞不清楚這個流程是幾年前的產物。

當然,台大的系統要嚇人也不是只有課程網,除了「新版台大課程網」以外的網站都是蠻嚇人的(XD)。
台大課程網一直以來都是學生評價不佳的系統之一,儘管在校內系統排名相對較高。即便已經經過多次調整,但似乎未能解決根本性問題。

話說回來,強者我學長 Po-Hao (James) Chang (又稱 Mr. Po)跟他的幾個小夥伴在某堂課的課堂專案做了一個增強版的選課系統 -「NTU Course Neo」(下稱 Neo 團隊),一推出後就收到不少正向的回覆。後來 Neo 團隊教務處取得合作,因此新版台大課程網的計畫就開始動工了。

為了有辦法處理一整個學校 30000 多個學生的選課需求,我們在架構上做了不少的討論跟設計。

前情摘要

因為學校的考量資料安全跟個資保護的關係,因此我們只能自建機房,也就是那些美好的雲端服務都是不可以用了,那些很香的 Template、GKE 上的 Auto Scaling、Load Balancer、Anycast DNS,全部都不能用,全部都要自己從頭到尾架出來,這無非直接加大了實作難度,也增加了不少維護成本。

剛好這個我這次在這個專案中就是負責架構師的工作,對於我這個近年來只用過 Cloud Service 的人來說,實在是非常痛苦,真的好久沒有遇到需要自己架設 Database 的情境了。

還好教務處本來就有自己的機房,因此我們要做的只有購買跟安裝機器就好了。


主架構

我們的架構是在一大堆 Bare Metals 上面安裝 Proxmox Virtual Environment,並在 PVE 上開各種 VM。這個設計主要是為了方便維護,例如某台 VM 去世的時候可以不需要實體的救援,又或是直接操作 Based OS 導致某些異常,而需要通過 IPMI 救援之類的問題。

Application Layer Infrastructure

我們的兩個主服務分別是 API Server 跟 Front-end Server,這兩個服務都是建立在 Kubernetes 上的。因為 Front-end 有部分頁面有使用到 Server-side Rendering,會需要一個可以 Serving 它的地方,也就是不能單單只用 File Server。

Kubernetes

至於要用 Kubernetes 的原因,主要是為了 Horizontal scaling,由於我們上述的服務皆是 Node.js Based 的,而 Node.js 為 Single-threaded,因此 Natively 在一台 Multithreaded 的機器上是沒辦法發揮最大效能,需要藉由一些套件輔助完成,例如 PM2 Clustering。

當然,有人可能會想到 PM2 Clustering / VM-based Horizontal scaling 也很好,沒必要大費周章去弄 Kubernetes。

對於某些公司或是團隊而言,確實是成立的,但剛好有一個前提是,我們幾乎每一個 Team Member 都對 Docker / Kubernetes 有一定程度上的了解(大部分的人上過 NASA,但我是沒有,因為我沒寫 hw0⋯⋯),加上我認為 PM2 Clustering 需要考慮太多 OS Environment 的變因,還有 VM-based scaling 其實會耗費不少資源,又或是 Scaling 速度不夠快之類的問題,所以後來還是決定使用 Kubernetes。

Kubernetes on Bare metal

網路上應該有不少教學指出這件事情怎麼實作,總之大略說起來就是需要一台 Master node(預設是不能 Serving Pods),然後以 Kubeadm 把 Worker Node(也就是 VM)加到 Master node 裡面以建立 Clustering。

Kubernetes 在 Bare metal 的架構上架設還蠻麻煩的,例如上面提到要用 Kubeadm 把 Node 加在一起變成 Cluster,光這一部就經常遇到問題,我們遇過 Flannel 會自己炸開,導致加入 Cluster 之後的 Worker 的連線會莫名的 Connection refused。

而且部署需要 External IP 的服務時,還需要特別指定 NodePort,或是用 Metal LB 做 Network load balancer,例如 Load Balancer (Kong、Istio-Envoy 等等⋯⋯)就會需要。

總之,架設跟維護的體驗不像 Cloud-based 那麼的友善,整體說來真的是挺糟的。

Ingress

雖然 Kubernetes 有內建的 Ingress,但因為我們要加一些特定的需求,例如 RBAC,或是打算在 Gateway 上幹壞事,因此我嘗試了幾個 Ingress,分別是 Kong、Istio-Envoy、Trafik,後來是決定使用 Kong。

就設定與部署而言,最簡單的是 Kong,也是功能最少的,但這僅限於 Kubernetes Ingress Controller,而非典型的 Kong Gateway,這兩者之間有極大的差異,有興趣的人可以自行了解。

原本是已經確定使用 Istio-Envoy,但後面在做壓力測試的時候發現 Istio 會對每個 Pod 做 Envoy Sidecar Injection,而每一個 Injected Envoy Sidecar 會需要使用額外的資源,因此對於資源的消耗是相對有感的增加,在各種測試跟考量下就棄用了 Istio-Envoy,改用 Kong。

我自己是很喜歡 Istio,一方面是 Istio 自己提供了不少 Features,加上原本 Envoy 的 API 也可以使用,因此整個 Gateway 的設定就變得非常彈性。

話說,用過那個多套的心得是-如果你不是真的想折騰,用 NGINX Ingress Controller 就好了,該有的東西幾乎都有,要 Monitoring 也有 Grafana Integration 可以用,實在不需要搞自己。(哪天心血來潮再來寫我們怎麼做各種 Monitoring 好了⋯⋯)

Tips
在 Ingress 上綁上 Request ID 會加快 Debugging 的速度喔!

Database

由於我們每一個 Database Instance 都可以接受不少的 Connections,因此 Connection Pool 的管理就成了一個大問題。

先假設 Count of allowed connections / pods(5) 是個理想的公式,並可以套用在每個 Pod 上面。

假設 Maximum Scaling Pods = 5,Database 可以乘載的 Connections 為 1000,那每個 Pod 的 Connection 理想上應該是 200

也就是這個公式

也就是這個公式

事情總是沒有那麼美好,我們發現某些 Pod 還是會出現 Connection Pool 不夠用,但某些 Pod 卻沒有吃滿的問題,這個時候有一種解法,那就是用 Database load balancing 的工具,例如 PgBouncer

這也不是不能,但一樣要考慮到 PgBouncer 也要做 HA 的狀況,而 PgBouncer 要做 HA 又是一件非常麻煩的事情,因此在跟老師討論完之後,決定把 Ingress 上的 Load balancing algorithm 改成 Least connections,以解決這個問題。

至於詳細工作模式就不多贅述了,可以參考這篇文章 Round-robin vs Least connection 了解這兩者之間的區別。

Front-end performance tuning

前端主要的 Code 還是從 Neo 來的,由於 Neo 本身開發時間比較短,因此有不少部分不是依循著 Best Practice,更不用說有時間做 Performance tuning 了。

我們的前端是用 Next.js,因此我們主要是著重在 React 本身做優化,理論上很多部分 Webpack 都幫我們做好了,但事實是 Webpack 做的往往不夠,例如 Webpack 雖然可以幫你做 Code splitting,但這也是在有好好做 Component lazy load 的狀況下,剛好我們前端的程式碼「都」沒有做 Lazy load,因此我們花了一些時間把大多 Component 改成 Lazy load。

LRU Cache

在我們做了 LRU Cache (Custom Server)之後發現狀況並沒有改變,但還是可以提一下。

Next.js 預設是沒有 LRU Cache 的選項的,因此每一個頁面都需要 Re-render 才會出現,對於課程網而言,這個 Behavior 是不需要存在的,畢竟課程資訊不會每分每秒都在變,因此我們可以在 Front-end 的 Server 做 Cache(Browser Cache 跟 Server Cache 是不一樣的),確保不需要做不必要的 Re-rendering,省下不必要的運算資源浪費。

我們在做壓力測試的時候有發現跟 API Server 一樣在 Round-robin 狀況下會導致某個 Pod 被撐爆,導致許多 Connection Blocks,又或是直到 Timeout,這一樣是改用 Least connections 解決的。

Disabled Gzip Compression

我們把前端的 Gzip Compression 關掉了,因為我們的某一台 Gateway 會做,因此需要讓負責處理 Compression 的 Gateway 拿到 Uncompressed 的檔案。


煩躁的東西

計中 SSO

這也是所有台大學生的必經之路,當然要作為一個合格的校內系統,那需要支援 SSO 也是再合理不過的事情,但是⋯⋯

作為一個校內系統,支援 SSO 是合理的需求,而台大計中是負責提供這個服務的部門。然而,我們在整合 SSO 時遇到了一些困難。首先,計中並沒有提供具體的 SSO 串接文件,且他們支援多種認證方式,包括加密和非加密方式。這種多樣性和缺乏詳細文件說明讓整個團隊在準備上線時感到壓力重重。

一開始,我們發現計中未提供明確的 SSO 串接文件,且他們支援兩種不同的認證方式,一種是加密的,另一種是非加密的。更複雜的是,必須提供給 IDP(計中)的資料也各有不同,而且我們遇到問題時並沒有收到明確的錯誤訊息。這使得我們在進行調試時只能通過致電計中的負責人來尋求支援,幸運的是,他們非常支持我們,我們對他們的協助深表感謝。

後來我們幾乎把每個 SAML / WS-Fed 的驗證方式都做過一次,才知道到底計中用的是哪種 Protocol,因為計中有表示不能透露具體的資訊,因此大家請自己摸索。XD(註:如果你也是要串台大 SSO 的人,可以透過校內管道找到我,在確定沒問題的狀況下我可以幫你解答。更新:我已經離開課程網團隊,可以直接發 Email 或在 Facebook 找到我。

除此之外,由於 SSO 2.0 的 Callback Redirection 是使用者在前端做 POST 給我們指定的 Callback URL,也就是計中做了一個網頁,裡面放了一大堆的 Hidden Fields,並透過 Javascript 執行 Form.submit() ,因此我們只能把 Token 放在 URL 回傳給前端,這無非增加了 Token leaking 的風險。

我不確定是不是計中的 Implementation 不正確,但由於我們沒有辦法在流程上做任何改變。在 Same-origin 的狀況下,我們雖然可以直接寫 Cookie,但想到未來可能有跨平台的可能性,所以就沒有往這方面實作。

總之,我們做了一個叫做 Transition Token 的機制,也就是拿 Callback 的 Transition Token 跟我們換正式的 Access Token。


後記

其實整個台大課程網的架構從設計到完成大約也就花了一個月的時間左右,並且大多數時間都在做 Configuration Tuning 還有把環境架起來。

真的要說的話,我覺得最難的其實是跟目前現有的課程網流程串接起來,例如舊有的課程網其實都是 Web-based(Session-based)的架構,完全沒有 Token 或是 API 的概念。

在多次與負責人溝通後,他們提出「你們可以直接寫入我們的資料庫」的建議,但我個人覺得這樣的建議並不太合理。特別是在我們尚未建立良好的權限管理(RBAC)機制的情況下,這樣的做法可能會導致嚴重的問題。

因此我也為了 Integration 這件事情寫了不少 PHP Code 以在舊有的架構上開 API,這確保我們真的以 Best Practice 實作,而不會留下一大堆後續需要通靈的產物。

可能很難相信,新版課程網的 Core Function 幾乎都是在學學生寫出來的,臺大的學生還是非常 Capable 的,非常值得讚賞。以結果來說,整體還是很不錯的。但其實以某些角度來看,我還是必須說整個工作流程是真的蠻累的就是,還好臺大學生學習能力還是蠻快的,通靈的能力也是蠻精確(XD)。

最後,希望新版課程網在我們這些比較有活力的猴子離開之後還可以保有它該有的活力。


這篇文章於 2023 年 2 月初完成,而我在同年 2 月底離開了課程網團隊。雖然我深切地希望能夠實現一些願望,但最終結果可能並不如預期。這是一個令人遺憾的事實,但也許並不出乎意料。

avatar-img
5會員
4內容數
日常生活嘴砲,詐騙島經驗分享
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
楓葉國工程師 的其他內容
接續上一篇文,因為我這次回加拿大的班機經杜拜轉機的關係,因此有機會體驗到這個貴賓室。 在土航 Marhaba 貴賓室的不遠處有個 SkyTeam 天合聯盟的貴賓室,理論上這種聯盟貴賓室應該都是要飛該聯盟的航空公司才可以進入的,但剛好這家有支援 Priority Pass 的關係,加上我的 PP
由於這次回加拿大在杜拜轉機,因此有機會體驗到土耳其航空在杜拜機場合作的貴賓室(Marhaba)。雖然說是 Marhaba,但土航的區域跟一般 Priority Pass 能進入的並不是同一區,所以想說寫個文來分享一下。 這次我飛的航班是土耳其航空的 TK759 從杜拜(DXB)到伊斯坦堡(IST)
接續上一篇文,因為我這次回加拿大的班機經杜拜轉機的關係,因此有機會體驗到這個貴賓室。 在土航 Marhaba 貴賓室的不遠處有個 SkyTeam 天合聯盟的貴賓室,理論上這種聯盟貴賓室應該都是要飛該聯盟的航空公司才可以進入的,但剛好這家有支援 Priority Pass 的關係,加上我的 PP
由於這次回加拿大在杜拜轉機,因此有機會體驗到土耳其航空在杜拜機場合作的貴賓室(Marhaba)。雖然說是 Marhaba,但土航的區域跟一般 Priority Pass 能進入的並不是同一區,所以想說寫個文來分享一下。 這次我飛的航班是土耳其航空的 TK759 從杜拜(DXB)到伊斯坦堡(IST)
你可能也想看
Google News 追蹤
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
社區大學 課程名稱取為細說社大之大學社會責任,感覺就是一門不打算開成的課程。在北投社大開課時,課程內容及名稱確實讓我燒了很多腦。社區大學 課程內容大致有了方向,但課程名稱要如何取呢?最後應該給大家可以一起細細地敘說社大小故事。
今年承辦臺北市藝音樂班的招生工作。奉上級長官指示,這是我們首次嘗試使用線上報名系統。
Thumbnail
上完 2023冬季Vue作品實戰班 之後,在專題期間經過討論後,我們未使用學院提供給我們的 API ,我們選擇了使用 nodejs 並選擇 json-server 來當我們的資料庫,也就是這時開始接觸到平常我們身為使用者時看不到的世界。
Thumbnail
一位大學生分享大學課程體驗,包括必修課程、服務學習和轉系考等,以及對各個科系的看法和感受。文章篇幅較長,回顧了大學四年的教學環境和科系情況。
Thumbnail
作為國立臺灣大學聯盟的學生,跨校選課是大學生活中的重要一環。本篇分享了臺科大的《創業與行銷》課程的學習心得以及課程內容總結,內容涉及創業心態、成功企業支柱、知行合一、故事包裝、創業關鍵要素等,並結合華特.迪士尼的經典語錄,啟發讀者勇於追尋夢想、勇於創業。
Thumbnail
臺大開放式課程(NTU OCW) 自2009年開放式課程網站建立至今,十多年來已經累積了超過300門的課程,透過與均一教育平台的交流,期待透過共同合作,推出有助於豐富高中多元課程的線上課程,讓學生能更深入認識大學相關學群的課程,進而幫助他們在自我探索、選擇科系以及生涯規劃上有更多元的認識。
Thumbnail
走進台大的快閃 台大從過去到現在匯聚著知識、學術、文化、人才的學術勝地,對於我這個粗裡粗氣,連寫個考卷日期都會寫錯的學生,只能說台大就是「風聞」有這間大學,加上之後都在中部以南活躍,也連校園一步都沒踏進過。 <<請各學員我們下週上課的地點在台大森林系教室集合,記得一定要到>> 看完森林療癒課程
Thumbnail
又一個雞生蛋,蛋生雞的問題難怪我有好幾年不敢吃蛋 台灣的教育在於大學端,這個問題我在「講不完的教育」這個專題裡有提到,大學本來就是為國家培育人才的地方,但現今的大學,死的死,傷的傷,逃的逃,卻沒有一所死傷逃掉的大學主導人再檢討自己創辦的大學為什麼會傷亡這麼慘重?   一個不懂得檢討失敗原因
Thumbnail
國立臺灣大學(簡稱臺大)為臺灣第一所國立綜合大學,位於臺北市。臺大宿舍群為臺大校內學生住宿之所在,分為男生宿舍、女生宿舍、研究生宿舍及國際學生宿舍等。 臺大宿舍群建築形式多樣,有日式木造建築、紅磚洋樓、現代鋼筋混凝土建築等,反映了臺大不同時期的建築風格。臺大宿舍群不僅是學生生活起居的場所,也是臺大
Thumbnail
很開心與數位實驗高中的一年級學生呂顥天進行了深入交流,讓我們了解數位實驗高中與普通高中的差異,特別是在課程設計和自主學習的比重。顥天也分享了他在「學習策略」課程中學到的數位工具應用,以及他對生涯探索和學習歷程製作的看法。
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
社區大學 課程名稱取為細說社大之大學社會責任,感覺就是一門不打算開成的課程。在北投社大開課時,課程內容及名稱確實讓我燒了很多腦。社區大學 課程內容大致有了方向,但課程名稱要如何取呢?最後應該給大家可以一起細細地敘說社大小故事。
今年承辦臺北市藝音樂班的招生工作。奉上級長官指示,這是我們首次嘗試使用線上報名系統。
Thumbnail
上完 2023冬季Vue作品實戰班 之後,在專題期間經過討論後,我們未使用學院提供給我們的 API ,我們選擇了使用 nodejs 並選擇 json-server 來當我們的資料庫,也就是這時開始接觸到平常我們身為使用者時看不到的世界。
Thumbnail
一位大學生分享大學課程體驗,包括必修課程、服務學習和轉系考等,以及對各個科系的看法和感受。文章篇幅較長,回顧了大學四年的教學環境和科系情況。
Thumbnail
作為國立臺灣大學聯盟的學生,跨校選課是大學生活中的重要一環。本篇分享了臺科大的《創業與行銷》課程的學習心得以及課程內容總結,內容涉及創業心態、成功企業支柱、知行合一、故事包裝、創業關鍵要素等,並結合華特.迪士尼的經典語錄,啟發讀者勇於追尋夢想、勇於創業。
Thumbnail
臺大開放式課程(NTU OCW) 自2009年開放式課程網站建立至今,十多年來已經累積了超過300門的課程,透過與均一教育平台的交流,期待透過共同合作,推出有助於豐富高中多元課程的線上課程,讓學生能更深入認識大學相關學群的課程,進而幫助他們在自我探索、選擇科系以及生涯規劃上有更多元的認識。
Thumbnail
走進台大的快閃 台大從過去到現在匯聚著知識、學術、文化、人才的學術勝地,對於我這個粗裡粗氣,連寫個考卷日期都會寫錯的學生,只能說台大就是「風聞」有這間大學,加上之後都在中部以南活躍,也連校園一步都沒踏進過。 <<請各學員我們下週上課的地點在台大森林系教室集合,記得一定要到>> 看完森林療癒課程
Thumbnail
又一個雞生蛋,蛋生雞的問題難怪我有好幾年不敢吃蛋 台灣的教育在於大學端,這個問題我在「講不完的教育」這個專題裡有提到,大學本來就是為國家培育人才的地方,但現今的大學,死的死,傷的傷,逃的逃,卻沒有一所死傷逃掉的大學主導人再檢討自己創辦的大學為什麼會傷亡這麼慘重?   一個不懂得檢討失敗原因
Thumbnail
國立臺灣大學(簡稱臺大)為臺灣第一所國立綜合大學,位於臺北市。臺大宿舍群為臺大校內學生住宿之所在,分為男生宿舍、女生宿舍、研究生宿舍及國際學生宿舍等。 臺大宿舍群建築形式多樣,有日式木造建築、紅磚洋樓、現代鋼筋混凝土建築等,反映了臺大不同時期的建築風格。臺大宿舍群不僅是學生生活起居的場所,也是臺大
Thumbnail
很開心與數位實驗高中的一年級學生呂顥天進行了深入交流,讓我們了解數位實驗高中與普通高中的差異,特別是在課程設計和自主學習的比重。顥天也分享了他在「學習策略」課程中學到的數位工具應用,以及他對生涯探索和學習歷程製作的看法。