一、需求分析
1、項(xiàng)目背景
由于選課時(shí)間集中, 在同一時(shí)間進(jìn)入系統(tǒng)搶占有限的資源, 導(dǎo)致系統(tǒng)服務(wù)響應(yīng)速度明顯下降, 嚴(yán)重時(shí)甚至?xí)斐煞?wù)器崩潰。這種問(wèn)題在目前實(shí)行學(xué)分制的國(guó)內(nèi)高校中普遍存在。當(dāng)系統(tǒng)軟件不具備高并發(fā)性時(shí),就無(wú)法順暢承接超大流量,當(dāng)請(qǐng)求過(guò)多,系統(tǒng)就會(huì)直接崩潰。
2、項(xiàng)目目標(biāo)
本小組致力于針對(duì)原有選課系統(tǒng)的缺點(diǎn),利用高并發(fā)技術(shù)的方法論以及設(shè)計(jì)原則,結(jié)合業(yè)務(wù)本身進(jìn)行架構(gòu)設(shè)計(jì),以應(yīng)對(duì)系統(tǒng)面臨的流量沖擊。從網(wǎng)絡(luò)、架構(gòu)、數(shù)據(jù)庫(kù)等多方面進(jìn)行系統(tǒng)優(yōu)化,從而降低系統(tǒng)的響應(yīng)時(shí)間,提高系統(tǒng)吞吐量,為學(xué)生提供一個(gè)高可用的選課系統(tǒng),以達(dá)到系統(tǒng)能夠在高并發(fā)下平穩(wěn)處理大流量且自身依然運(yùn)行良好的目的,讓學(xué)生不再受系統(tǒng)崩潰所困擾。
二、系統(tǒng)功能分析
1、多角色劃分
- **普通用戶(學(xué)生):**登錄注銷、查看全校課程、查看方案內(nèi)課程以及推薦班選課,選課退課、查看選課退課日志、查看課表
- **普通管理員:**學(xué)院、系、專業(yè)、班級(jí)管理,學(xué)生管理、課程管理、通知管理、選課輪次管理、課程緊急設(shè)置
- **超級(jí)管理員:**進(jìn)行系統(tǒng)設(shè)置,查看系統(tǒng)日志,對(duì)普通管理員用戶進(jìn)行設(shè)置
2、模塊功能詳述
-
選課模塊
- **登錄注銷:**學(xué)生可以通過(guò)學(xué)號(hào)和密碼登入系統(tǒng),登錄后會(huì)保持一天的登入狀態(tài),登錄憑證過(guò)期后再進(jìn)行操作則會(huì)重新跳轉(zhuǎn)至登錄頁(yè)面。也可以通過(guò)注銷功能退出當(dāng)前用戶的登錄
- **查看全校課程:**學(xué)生進(jìn)入選課系統(tǒng)后可以查看與搜索全校開(kāi)設(shè)的課程班??梢酝ㄟ^(guò)是否必修、是否通識(shí)課、課程學(xué)分等條件進(jìn)行課程篩選,也可以進(jìn)行課程搜索。同時(shí)會(huì)根據(jù)學(xué)生已選課程顯示課程是否出現(xiàn)時(shí)間沖突
- **查看方案內(nèi)課程:**學(xué)生可以查看自己所在班級(jí)的方案內(nèi)課程,以及當(dāng)前學(xué)期的推薦班選課。學(xué)生同樣可以通過(guò)各種條件進(jìn)行篩選和搜索,方便查找目的課程
- **選課退課:**學(xué)生可以對(duì)顯示的課程進(jìn)行選課,該操作會(huì)判斷學(xué)生學(xué)分是否足夠、課程是否沖突、是否已完成先修課程的學(xué)習(xí)以及課程容量充足等一系列條件。對(duì)于通識(shí)課程,如果當(dāng)前處于第一輪次選課,則會(huì)允許選擇人數(shù)超過(guò)課程容量,后臺(tái)會(huì)在之后篩選
- **選課日志查詢:**學(xué)生可以查看當(dāng)前學(xué)期自己已經(jīng)選擇的課程,會(huì)分為通識(shí)選修課以及其他課程。同時(shí)也可以查看當(dāng)前學(xué)期的退選日志,推選日志包括自己退選和系統(tǒng)退選
-
管理模塊
- **選課輪次管理:**新增選課輪次、查看選課輪次、刪除選課輪次
- **班級(jí)管理:**院系專業(yè)、班級(jí)和方案內(nèi)課程的增刪改查
- **課程管理:**課程依賴、課程以及課程班的增刪改查
- **緊急設(shè)置:**新增課程僅開(kāi)放給某個(gè)班級(jí)、年級(jí)
- **通知管理:**發(fā)布點(diǎn)對(duì)點(diǎn)通知以及群體公告
- **查看系統(tǒng)日志:**查看前臺(tái)學(xué)生的操作日志以及后臺(tái)管理員的操作日志,可以通過(guò)學(xué)號(hào)、管理員編號(hào)以及是否請(qǐng)求異常和請(qǐng)求時(shí)間進(jìn)行篩選
- **修改系統(tǒng)設(shè)置:**新增和刪除用戶黑名單、設(shè)置IP地址攔截、修改用戶每分鐘的請(qǐng)求次數(shù)限制
- **管理普通管理員:**可以新增管理員和刪除管理員,允許修改管理員的信息和將普通管理員提權(quán)為超級(jí)管理員
三、系統(tǒng)架構(gòu)
1、技術(shù)選型
- 前端
- Vue3 + Vue-Router + Vuex
- Node.js + JavaScript + ElementUI
- Axios + WebSocket
- 后端
- Maven + SpringBoot
- MySQL + ShradingJDBC + Druid + Redis:數(shù)據(jù)庫(kù)及數(shù)據(jù)庫(kù)中間件
- RabbitMQ: 消息隊(duì)列
- 運(yùn)維
- 阿里云服務(wù)器 * 3,域名 * 1
- Docker
- Nginx
2、系統(tǒng)分析
選課系統(tǒng)的特點(diǎn)
1.業(yè)務(wù)特點(diǎn):在選課開(kāi)始之前,流量一直是很平穩(wěn)的狀態(tài);當(dāng)選課剛剛開(kāi)始時(shí),系統(tǒng)流量呈直線突增;在選課活動(dòng)開(kāi)始一段時(shí)間或結(jié)束之后,流量又會(huì)急速下落。
2.技術(shù)特點(diǎn):
- 瞬時(shí)并發(fā)量高。因?yàn)檎n程容量限制的特性,決定了一旦開(kāi)始“搶課”,熱門(mén)的課程就會(huì)出現(xiàn)流量洪峰。
- 并發(fā)讀寫(xiě)。讀比寫(xiě)要多,屬于多讀寫(xiě)少的場(chǎng)景。課程查詢頁(yè)訪問(wèn)大,但是真正選課成功的不多,即查詢的流量要遠(yuǎn)大于扣減容量的流量。
對(duì)以上系統(tǒng)特點(diǎn)進(jìn)行分析,得到以下設(shè)計(jì)原則:
- 數(shù)據(jù)應(yīng)盡量少
- 用戶請(qǐng)求時(shí)發(fā)送請(qǐng)求所傳輸?shù)臄?shù)據(jù)和服務(wù)端響應(yīng)請(qǐng)求所傳輸?shù)臄?shù)據(jù)應(yīng)該盡可能的少,消息體太大在網(wǎng)絡(luò)中傳輸會(huì)影響效率。此外數(shù)據(jù)再服務(wù)端的各種解析,如JSON序列化與反序列化等操作都會(huì)消耗CPU資源,所以減少傳輸?shù)臄?shù)據(jù)可以提高CPU使用率
- 避免單節(jié)點(diǎn)
- 單節(jié)點(diǎn)系統(tǒng)意味著而系統(tǒng)的不穩(wěn)定性較高,可能會(huì)出現(xiàn)不可用的情況。設(shè)計(jì)時(shí)必須保證系統(tǒng)的高可用
- 利用負(fù)載均衡分散流量
3、架構(gòu)設(shè)計(jì)
系統(tǒng)基于Spring、SpringMVC、Mybatis框架,采用MVC開(kāi)發(fā)模式,將系統(tǒng)分為模型層、視圖層、控制層三層。模型層Model主要負(fù)責(zé)處理業(yè)務(wù)邏輯以及數(shù)據(jù)庫(kù)的交互,視圖層View主要負(fù)責(zé)顯示數(shù)據(jù)和提交數(shù)據(jù),控制層Controller主要是用作輔助捕獲請(qǐng)求并控制請(qǐng)求轉(zhuǎn)發(fā)。
- SpringMVC:作為View層的實(shí)現(xiàn)者,接收用戶的請(qǐng)求。SpringMVC的Controller作為整個(gè)應(yīng)用的控制器,完成用戶請(qǐng)求的轉(zhuǎn)發(fā)及用戶的響應(yīng)。
- MyBatis:作為Model層的實(shí)現(xiàn)者,主要負(fù)責(zé)對(duì)數(shù)據(jù)庫(kù)的增刪改查。
- Spring:作為依賴注入和控制反轉(zhuǎn)的框架,主要用于控制Bean的注入和管理Bean的生命周期。
同時(shí)從業(yè)務(wù)邏輯上來(lái)看,系統(tǒng)按照三層架構(gòu)進(jìn)行軟件包的歸類,分為控制層Controller、業(yè)務(wù)層Service和持久層Dao,讓架構(gòu)更加清晰。
- Controller層負(fù)責(zé)具體業(yè)務(wù)模塊流程的控制,在此層面要調(diào)用Service層的接口來(lái)控制業(yè)務(wù)流程,控制的配置也同樣是在Spring的配置文件里面進(jìn)行,針對(duì)具體的業(yè)務(wù)流程,會(huì)有不同的控制器,我們具體的設(shè)計(jì)過(guò)程中可以將流程進(jìn)行抽象歸納,設(shè)計(jì)出可以重復(fù)利用的子單元流程模塊,這樣不僅可以使程序結(jié)構(gòu)變得清晰,和大大減少了代碼量。
- Service層主要設(shè)計(jì)業(yè)務(wù)模塊的邏輯應(yīng)用設(shè)計(jì)。首先設(shè)計(jì)接口,再設(shè)計(jì)其實(shí)現(xiàn)類。接著再在Spring的配置文件中配置其實(shí)現(xiàn)的關(guān)聯(lián)。這樣我們就可以在應(yīng)用中調(diào)用Service接口來(lái)進(jìn)行業(yè)務(wù)處理。Service層的業(yè)務(wù)實(shí)現(xiàn),具體要調(diào)用到已定義的DAO層接口。封裝Service層的業(yè)務(wù)邏輯有利于通用的業(yè)務(wù)邏輯的獨(dú)立性和重復(fù)利用性,程序顯得非常簡(jiǎn)潔。
- DAO層的設(shè)計(jì)首先是設(shè)計(jì)DAO的接口。然后在Spring的配置文件中定義此接口的實(shí)現(xiàn)類。然后就可以在模塊中調(diào)用此接口來(lái)進(jìn)行數(shù)據(jù)業(yè)務(wù)的處理,而不用關(guān)心此接口的具體實(shí)現(xiàn)類是哪個(gè)類,顯示結(jié)構(gòu)非常清晰。DAO層的數(shù)據(jù)源配置,以及有關(guān)數(shù)據(jù)庫(kù)連接的參數(shù)都是在Spring的配置文件中進(jìn)行配置。
包結(jié)構(gòu)大致如下:
problem-provider
|--annotation # 自定義注解
|--aop # 切面類 —— SpringAOP的應(yīng)用
|--common # 通用類
| |--config # 配置類
| |--constant # 常量類
| |--enums # 枚舉類
| |--util # 工具類
|--controller # 控制層 —— Controller層的體現(xiàn)
|--dto # 數(shù)據(jù)傳輸對(duì)象
|--entity # 實(shí)體類 —— MyBatis中實(shí)體類的定義
|--event # 事件 —— 觀察者設(shè)計(jì)模式
|--filter # 過(guò)濾器 —— SpringMVC實(shí)現(xiàn)請(qǐng)求的攔截過(guò)濾
|--handle # 處理器
|--listener # 監(jiān)聽(tīng)器
|--mapper # 持久層 —— dao層的體現(xiàn)
|--service # 業(yè)務(wù)層 —— 接口設(shè)計(jì)思想體現(xiàn)
| |--impl # 實(shí)現(xiàn)類 —— Service層的體現(xiàn)
同時(shí)本系統(tǒng)通過(guò)SpringBoot對(duì)SSM進(jìn)行整合,約定大于配置,避免了定義大量配置文件的繁瑣,也一定程度的解決版本依賴沖突等問(wèn)題。只需要在資源目錄下配置application.yml文件配置數(shù)據(jù)庫(kù),redis,rabbitmq等服務(wù)的連接信息以及mapper文件即可。
4、系統(tǒng)演變
- 第一階段——單體應(yīng)用架構(gòu):只需要一個(gè)應(yīng)用,將所有功能代碼部署在一起
- 項(xiàng)目模塊之間緊密耦合,單點(diǎn)容錯(cuò)率低
- 無(wú)法對(duì)不同模塊進(jìn)行針對(duì)性優(yōu)化和水平擴(kuò)展
- 第二階段——垂直應(yīng)用架構(gòu):將原來(lái)的一個(gè)應(yīng)用拆成選課系統(tǒng)與后臺(tái)管理分開(kāi)
- 系統(tǒng)拆分實(shí)現(xiàn)了流量分擔(dān),優(yōu)化了并發(fā)問(wèn)題,可以針對(duì)不同模塊進(jìn)行優(yōu)化和水平擴(kuò)展
- 如選課系統(tǒng)訪問(wèn)量增大則可以之提升其對(duì)應(yīng)節(jié)點(diǎn),而無(wú)需將性能提升浪費(fèi)在后臺(tái)管理上
- 第三階段——集群部署
- 選課系統(tǒng)典型的初始架構(gòu)為“瀏覽器——單WEB服務(wù)器——單數(shù)據(jù)庫(kù)”模式
- 隨著用戶并發(fā)訪問(wèn)量的增加,通常 WEB服務(wù)器首先出現(xiàn)服務(wù)瓶頸,因此首先要著手對(duì)WEB站點(diǎn)層進(jìn)行水平擴(kuò)展
水平擴(kuò)展有多種方式,由于DNS不會(huì)感知到具體WEB站點(diǎn)的可用性,當(dāng)某個(gè)WEB站點(diǎn)服務(wù)故障(如網(wǎng)絡(luò)中斷、系統(tǒng)崩潰等),用戶對(duì)這個(gè)站點(diǎn)的訪問(wèn)將失敗,故不通過(guò)DNS進(jìn)行水平擴(kuò)展。
考慮到Nginx是一個(gè)高性能的 HTTP 和反向代理服務(wù)器,反向代理可以實(shí)現(xiàn)隱藏服務(wù)器的內(nèi)部結(jié)構(gòu),集成防火墻來(lái)防御外界DDOS攻擊,通過(guò)負(fù)載均衡分配流量到不同服務(wù)器上等功能。此外Nginx支持對(duì)故障 WEB 站點(diǎn)的探測(cè)感知,能夠把流量引導(dǎo)到非故障的WEB站點(diǎn),同時(shí)也沒(méi)有DNS 負(fù)載均衡模式下暴露過(guò)多IP、擴(kuò)容非實(shí)時(shí)等問(wèn)題。
為避免反向代理層的單點(diǎn)故障風(fēng)險(xiǎn),采用兩臺(tái) Nginx 組成一個(gè)集群,分別部署 Keepalived,設(shè)置成相同的虛 IP,實(shí)現(xiàn) Nginx 負(fù)載均衡服務(wù)的高可用。當(dāng)一臺(tái) Nginx 掛了, Keepalived 能夠探測(cè)到并將流量自動(dòng)遷移到另一臺(tái) Nginx 上。該方案解決了反向代理層的高可用問(wèn)題,但是 Nginx 集群的資源利用率下降到 50%(一主一備)。對(duì)于院校選課活動(dòng),每秒的HTTP請(qǐng)求峰值一般在 10 萬(wàn)以下,該架構(gòu)的 WEB 站點(diǎn)響應(yīng)能力應(yīng)能滿足要求,最多再適當(dāng)提高 Nginx 服務(wù)器的配置應(yīng)能解決問(wèn)題。故系統(tǒng)最終決定采用基于Nginx集群反向代理的方式對(duì)WEB站點(diǎn)層進(jìn)行水平擴(kuò)展。
四、數(shù)據(jù)庫(kù)設(shè)計(jì)
1、概念結(jié)構(gòu)設(shè)計(jì)
班級(jí)相關(guān)實(shí)體
學(xué)生相關(guān)實(shí)體
課程相關(guān)實(shí)體
系統(tǒng)相關(guān)實(shí)體
實(shí)體聯(lián)系圖
2、邏輯結(jié)構(gòu)設(shè)計(jì)
- 班級(jí)(班級(jí)編號(hào),班級(jí)所在學(xué)院名,班級(jí)所在系名,班級(jí)所在專業(yè)名,班級(jí)對(duì)應(yīng)年份,班級(jí)序號(hào),班級(jí)名稱,畢業(yè)所需學(xué)分)
- 學(xué)院 (學(xué)院編號(hào),學(xué)院名稱)
- 系(系編號(hào),學(xué)院編號(hào),系名)
- 專業(yè)(專業(yè)編號(hào),系編號(hào),專業(yè)名稱)
- 學(xué)生(學(xué)生學(xué)號(hào),班級(jí)編號(hào),姓名,性別,郵箱,電話號(hào)碼,密碼,狀態(tài))
- 學(xué)生選課(選課記錄號(hào),學(xué)生學(xué)號(hào),課程班編號(hào),選擇學(xué)期,課程學(xué)分)
- 學(xué)生學(xué)分(學(xué)分記錄號(hào),學(xué)生學(xué)號(hào),學(xué)期,最高主修學(xué)分,已選主修學(xué)分)
- 方案內(nèi)選課(方案內(nèi)選課記錄號(hào),班級(jí)編號(hào),課程編號(hào),推薦選課時(shí)間,是否必修)
- 選課輪次(選課輪次記錄號(hào),輪次所在學(xué)期,學(xué)期內(nèi)輪次序號(hào),開(kāi)始時(shí)間,結(jié)束時(shí)間,提示信息)
- 課程(課程編號(hào),課程名,所在校區(qū),排課單位,課程類別,通識(shí)課類型,課程學(xué)分,開(kāi)課班級(jí)數(shù)量)
- 課程班(課程班編號(hào),課程編號(hào),是否慕課,授課語(yǔ)言,選擇人數(shù),課程容量,授課教師,考試類型,考試時(shí)間)
- 課程時(shí)間地點(diǎn)( 課程時(shí)間地點(diǎn)記錄號(hào),課程班編號(hào),授課持續(xù)時(shí)間,每周星期幾上課,第幾節(jié)課上課,上課地點(diǎn))
- 課程依賴(課程依賴記錄號(hào),課程編號(hào),先修課程編號(hào))
- 課程應(yīng)急設(shè)置( 課程應(yīng)急設(shè)置記錄號(hào),課程編號(hào),禁選班級(jí)編號(hào),禁選年級(jí))
- 系統(tǒng)管理員(管理員編號(hào),管理員名稱,類型,密碼,手機(jī)號(hào)碼,上次登錄時(shí)間)
- 系統(tǒng)通知(通知編號(hào),接收對(duì)象編號(hào),消息體)
- 系統(tǒng)日志(日志編號(hào),學(xué)生學(xué)號(hào)/管理員編號(hào),請(qǐng)求類型,請(qǐng)求IP,請(qǐng)求接口,請(qǐng)求體,響應(yīng)體,請(qǐng)求時(shí)間)
實(shí)體間關(guān)系分析
- a:
- 一個(gè)院包含多個(gè)系
- 一個(gè)系包含多個(gè)專業(yè)
- 一個(gè)專業(yè)包含多個(gè)班
- 一個(gè)班包含多個(gè)學(xué)生
- 一個(gè)班擁有一個(gè)方案內(nèi)選課
- b:
- 一個(gè)學(xué)生屬于一個(gè)班
- 一個(gè)學(xué)生擁有多個(gè)學(xué)期的學(xué)分
- 一個(gè)學(xué)生擁有多個(gè)學(xué)期的選課
- c:
- 一門(mén)課有多個(gè)課程班
- 一門(mén)課有多門(mén)先修課
- 一門(mén)課有多個(gè)開(kāi)課的時(shí)間和地點(diǎn)
- 一門(mén)課可以設(shè)置多個(gè)應(yīng)急條件
- d:
- 一個(gè)學(xué)期可以有多個(gè)選課輪次
- 一個(gè)學(xué)期可以選擇多個(gè)課程班
- 一個(gè)學(xué)期每個(gè)班級(jí)有一個(gè)推薦班選課
- e:
- 一個(gè)用戶可以收到多個(gè)消息與通知
- 學(xué)生的每次請(qǐng)求都會(huì)被記錄在日志表
- 管理員每次請(qǐng)求都會(huì)被記錄在日志表
3、物理結(jié)構(gòu)設(shè)計(jì)
字段規(guī)定:
- 小數(shù)類型使用decimal、禁止使用float和double類型,時(shí)間采用date_time類型
- 絕大多數(shù)表必備三個(gè)字段:id、create_time以及update_time,部分表的數(shù)據(jù)采用邏輯刪除
SQL語(yǔ)句:
- 禁止使用存儲(chǔ)過(guò)程,存儲(chǔ)過(guò)程難以調(diào)試和擴(kuò)展,且沒(méi)有移植性
- 不得使用外鍵(影響插入速度)和級(jí)聯(lián)(更新強(qiáng)阻塞,存在更新風(fēng)暴風(fēng)險(xiǎn)),一切外鍵概念在應(yīng)用層解決
安全性問(wèn)題:
- ORM映射時(shí)參數(shù)使用#{}而非${},以防止SQL注入問(wèn)題
- 用戶密碼先加鹽處理后再進(jìn)行MD5加密存儲(chǔ),以提高密碼復(fù)雜程度和防御彩虹表攻擊
使用DataGrip數(shù)據(jù)庫(kù)設(shè)計(jì)工具,根據(jù)上述實(shí)體屬性以及聯(lián)系進(jìn)行數(shù)據(jù)庫(kù)以及表的創(chuàng)建。
以下為學(xué)生表創(chuàng)建示例:
對(duì)應(yīng)建表語(yǔ)句如下
create table scc_choose_round
(
id int not null
primary key,
semester int null,
round_no tinyint null,
start_time datetime null,
end_time datetime null,
tips varchar(255) null,
create_time datetime null,
update_time datetime null
)
comment '選課輪次表';
create table scc_class
(
id int not null
primary key,
college_name varchar(20) null,
department_name varchar(20) null,
subject_name varchar(20) null,
year smallint null,
class_no tinyint null,
class_name varchar(20) null,
graduation_credits smallint null,
create_time datetime null,
update_time datetime null
)
comment '班級(jí)表';
create table scc_class_course
(
id bigint not null
primary key,
class_id int null,
course_id int null,
commended_time int null,
is_must tinyint null,
is_deleted tinyint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '方案內(nèi)課程表';
create table scc_college
(
id smallint not null
primary key,
college_name varchar(20) null
)
comment '學(xué)院表';
create table scc_course
(
id char(10) not null
primary key,
course_name varchar(30) null,
campus varchar(20) null,
college varchar(20) null,
type varchar(20) null,
general_type varchar(20) null,
credit decimal(10, 1) null,
class_num tinyint null,
create_time datetime null,
update_time datetime null
)
comment '課程表';
create table scc_course_class
(
id bigint not null
primary key,
course_id char(10) null,
is_mooc tinyint null,
language varchar(20) null,
choosing_num int null,
capacity int null,
teacher varchar(100) null,
exam_type varchar(20) null,
exam_time varchar(50) null,
is_deleted tinyint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '課程班表';
create table scc_course_dependence
(
id bigint not null
primary key,
course_id int null,
pre_course_id int null,
is_deleted tinyint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '課程依賴表';
create table scc_course_emergency
(
id bigint not null
primary key,
course_id char(10) null,
only_to_class int null,
only_to_grade int null,
is_deleted tinyint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '課程緊急設(shè)置表';
create table scc_course_timeplace
(
id bigint not null
primary key,
course_class_id bigint null,
duration_time varchar(20) null,
week_day tinyint null,
day_no varchar(20) null,
place varchar(50) null,
is_deleted tinyint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '課程時(shí)間地點(diǎn)表';
create table scc_department
(
id smallint not null
primary key,
college_id smallint null,
department_name varchar(20) null
)
comment '系表';
create table scc_student
(
id bigint not null
primary key,
name varchar(50) null,
gender tinyint null,
class_id int null,
email varchar(100) null,
phone char(11) null,
id_card char(18) null,
password char(32) null,
salt char(32) null,
status tinyint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '學(xué)生表';
create table scc_student_course
(
id bigint not null
primary key,
student_id int null,
course_class_id bigint null,
semester int null,
credits decimal null,
is_deleted tinyint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '學(xué)生選課表';
create table scc_student_credits
(
id bigint not null
primary key,
student_id bigint null,
semester int null,
max_subject_credit decimal(10, 1) null,
choose_subject_credit decimal(10, 1) null,
create_time datetime null,
update_time datetime null
)
comment '學(xué)生學(xué)分表';
create table scc_subject
(
id smallint not null
primary key,
department_id smallint null,
subject_name varchar(20) null
)
comment '專業(yè)表';
create table scc_sys_backend_log
(
id bigint not null
primary key,
type tinyint null,
request_ip varchar(255) null,
manager_id int null,
request_api varchar(255) null,
request_body text null,
response_body text null,
create_time datetime null
)
comment '后臺(tái)日志表';
create table scc_sys_frontend_log
(
id bigint not null
primary key,
type tinyint null,
request_ip varchar(255) null,
student_id int null,
request_api varchar(255) null,
request_body text null,
response_body text null,
create_time datetime null
)
comment '前臺(tái)日志表';
create table scc_sys_manager
(
id int not null
primary key,
manager_name varchar(20) null,
type smallint null,
password char(32) null,
salt char(32) null,
mobile_phone varchar(20) null,
last_login datetime null,
is_deleted tinyint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '系統(tǒng)管理員表';
create table scc_sys_notice
(
id bigint not null
primary key,
student_id bigint null,
message varchar(255) null,
status smallint default 0 null,
create_time datetime null,
update_time datetime null
)
comment '系統(tǒng)通知表';
五、系統(tǒng)優(yōu)化
經(jīng)過(guò)前面的設(shè)計(jì),WEB 站點(diǎn)層的高性能、高可用都得到了一定的保證,但此時(shí)數(shù)據(jù)庫(kù)IO操作很可能成為了瓶頸。 數(shù)據(jù)層同樣需要進(jìn)行改進(jìn),數(shù)據(jù)層庫(kù)架構(gòu)優(yōu)化的目的同樣是實(shí)現(xiàn)高性能、高可用。
優(yōu)化方案:
- 能預(yù)熱的數(shù)據(jù)提前預(yù)熱,利用緩存抗住“讀”壓力
- 池化技術(shù)
- 實(shí)現(xiàn)數(shù)據(jù)庫(kù)的讀寫(xiě)分離
- 使用NoSQL,消息隊(duì)列(及搜索引擎技術(shù)[todo])
1、緩存
**問(wèn)題:**當(dāng)請(qǐng)求的QPS達(dá)到一定的水平后,系統(tǒng)將面臨性能降低(并發(fā)越大查詢速率越低)以及并發(fā)下降(當(dāng)請(qǐng)求數(shù)超過(guò)正常單機(jī)數(shù)據(jù)庫(kù)所能抗住的QPS時(shí),數(shù)據(jù)庫(kù)將會(huì)卡頓甚至宕機(jī))。
優(yōu)化方案:引入緩存
使用緩存方案可以提高訪問(wèn)性能、降低網(wǎng)絡(luò)擁堵,減輕服務(wù)負(fù)載等。緩存讀寫(xiě)性能高,且預(yù)熱快。將要被請(qǐng)求的數(shù)據(jù)放入緩存中,請(qǐng)求將先在緩存中獲取數(shù)據(jù)(單級(jí)緩存可承載的并發(fā)量可能是MySQL的幾十倍)。
引入緩存數(shù)據(jù)庫(kù)Redis設(shè)計(jì)合適的緩存淘汰策略,將熱點(diǎn)數(shù)據(jù)存入Redis方便后續(xù)讀取。
Todo:引入Redis集群,解決數(shù)據(jù)一致性問(wèn)題,預(yù)防緩存雪崩與緩存穿透問(wèn)題,以搭建高可用的Redis集群。
2、池化技術(shù)
如果每次請(qǐng)求都需要新建連接,即TCP需要經(jīng)歷“三次握手”,這個(gè)過(guò)程很費(fèi)時(shí)間。另外一旦建立連接則還需要關(guān)閉連接,即TCP需要經(jīng)歷“四次揮手”,又需要時(shí)間開(kāi)銷。
問(wèn)題:
- 單連接無(wú)法支撐高并發(fā)
- 每次請(qǐng)求都需要建立和關(guān)閉連接,會(huì)增加請(qǐng)求延遲
- 如果在高并發(fā)下頻繁地建立和關(guān)閉會(huì)導(dǎo)致操作系統(tǒng)耗費(fèi)過(guò)多CPU資源
優(yōu)化方案:引入池化技術(shù)
可以用數(shù)據(jù)庫(kù)連接池來(lái)優(yōu)化數(shù)據(jù)庫(kù)的連接,這就是連接池技術(shù)。即預(yù)先分配一批并將他們放入一個(gè)緩存區(qū)中循環(huán)使用,形成池化效應(yīng)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-469119.html
3、讀寫(xiě)分離
**問(wèn)題:**由于選課系統(tǒng)中每個(gè)人的目標(biāo)課程不同,所以緩存命中率就沒(méi)有那么高,會(huì)有很大的流量被轉(zhuǎn)發(fā)到MySQL數(shù)據(jù)庫(kù)中,MySQL的壓力也隨之增大,單臺(tái)MySQL實(shí)例將面臨無(wú)法滿足當(dāng)前的業(yè)務(wù)需求。
優(yōu)化方案:引入讀寫(xiě)分離
針對(duì)于選課這種并發(fā)量大的讀請(qǐng)求,最直接的便是搭建多臺(tái)MySQL實(shí)例分?jǐn)傋x請(qǐng)求。將讀流量分?jǐn)偟礁鱾€(gè)從庫(kù)中,而主庫(kù)負(fù)責(zé)寫(xiě)流量,通過(guò)Binlog實(shí)現(xiàn)數(shù)據(jù)同步。
4、后續(xù)優(yōu)化
解決數(shù)據(jù)一致性問(wèn)題
做好冪等性設(shè)計(jì)(所謂冪等性即指用戶對(duì)于同一個(gè)操作發(fā)起一次請(qǐng)求或多次請(qǐng)求,得到的結(jié)果都是一樣的,主要用在重復(fù)請(qǐng)求上)。由于并發(fā)量大的問(wèn)題,考慮采用樂(lè)觀鎖而非悲觀鎖以得到更好的并發(fā)訪問(wèn)性能。
引入搜索引擎
每次請(qǐng)求都需要建立和關(guān)閉連接,會(huì)增加請(qǐng)求延遲
- 如果在高并發(fā)下頻繁地建立和關(guān)閉會(huì)導(dǎo)致操作系統(tǒng)耗費(fèi)過(guò)多CPU資源
優(yōu)化方案:引入池化技術(shù)
可以用數(shù)據(jù)庫(kù)連接池來(lái)優(yōu)化數(shù)據(jù)庫(kù)的連接,這就是連接池技術(shù)。即預(yù)先分配一批并將他們放入一個(gè)緩存區(qū)中循環(huán)使用,形成池化效應(yīng)。
項(xiàng)目開(kāi)源地址:
https://gitee.com/Ken-Chy129/
https://github.com/Ken-Chy129/文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-469119.html
到了這里,關(guān)于數(shù)據(jù)庫(kù)大作業(yè)——學(xué)生選課系統(tǒng)(基于SpringBoot+Mysql)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!