设计千万级学生管理系统的考试试卷存储方案 - 模块四
1. 学生考试场景用户行为建模和性能估算
假设每门学科每年 2 次考试,每个学生平均一学期 20 门课,考试采取机考的方式,每门考试的答案 20 判断题、20 选择题、4 道大题(答案 200 字以
内),考试结果永久保存,在校学生能够看到自己曾经的考试结果,
则考试结果记录的存储量为:
在校学生:1000 万 * 20(课)* 2(考试次数) * 1000(答案)* 2(学期) * 3(只有前三年考试)= 2.4T。
离校学生:每年 250 万,存储量为 0.6T。
假设学校的考试都安排在某一个月内,考试的时候请求试卷,提交答案,中间答题过程浏览器本地完成,由于考试集中在上午 4 小时和下午 4 小时,
且请求试卷集中在考试开始的前 1 分钟,提交答案集中在考试结束前的 30 分钟,因此估算如下:
请求试卷:1000 万 * 20(课)/ 20(周末不考试) / 4(每天 4 堂考试)/ 1 分钟 = 250 万请求/分钟 ≈ 5 万/每秒。
提交试卷: 1000 万 * 20(课)/ 20(周末不考试) / 4(每天 4 堂考试)/ 30 分钟 = 1700/每秒。
2. 存储性能需求汇总
1. 在校学生考试结果存储:2.4T;
2. 离校学生考试结果存储:每年增长 0.6T;
3. 试卷请求 QPS:5 万/s;
4. 提交试卷 TPS:1700/s
3. 存储架构的选择逻辑
根据存储性能需求汇总数据分析可知
在校学生的考试结果数据本身很大,同时每年都有新生入学,数据会持续增长,单机无法存储所有数据,因此需要 分片存储,同时毕业生离校,离校学生数据不会经常被查询,因此需要做数据的 冷热分离 存储
试卷请求 QPS 高达 5W/s,因此需要考虑对试卷内容进行缓存,同时评估缓存容量。全国大致 3000 大学,500 专业课,假设平均每个大学开设 200 个专业,同时每个学校每个专业的试卷都不一样,一次期末考试生成 3000*200=60W 套试卷,60W 试卷/20 天/4 场= 7500 套, 1 场考试 7500 套试卷,每套试卷 100KB,缓存容量,7500*100KB 约为 800MB,因此缓存 单机可存储,无需考虑缓存分片
4. 存储架构设计
简要说明
试卷存储访问:读取 QPS 较大,且需要高可用,采用 redis 缓存
老师课程考试结果: 主要记录学生的课程的基本考试结果,用于基本信息查询,以及学校老师对考试情况的分析。数据每年增长,还要便于查询统计,因此采用 MySQL 分库分表,对数据进行分片
学生考试结果明细:考试结果,流水数据,持续增长,内容较大,没有统计分析需求,考虑数据分片,冷热分离,存储成本,采用 Hbase 存储
4.1 缓存架构设计
由于缓存容量需求不大,单台服务器可缓存所有试卷内容,且单台服务器可以抗住 5W 的 QPS,因此不用考虑数据分片,但是考试时读取试卷不能出现故障,需要保证高可用,因此引入 Redis sentinel 部署模式,采用 3 台服务器,1 主 2 从,每台机器同时部署哨兵进程和 Redis 服务进程。
参考:
Redis sentinel 文档:https://redis.io/topics/sentinel
阿里云 Redis 最低配性能指标:https://help.aliyun.com/document_detail/145227.htm?spm=a2c4g.11186623.2.7.aaf01dbdvjq5K5#concept-2348281
6. 存储方案设计
6.1 存储内容设计
考试涉及的主要实体以及关系
重点说明:
1、除了考试结果-明细数据采用 Hbase 存储,其他数据采用 MySQL 进行存储,其中 试卷信息、考试结果会持续增长,因此考虑按年分表
考试结果-明细(HBase 存储)
Key:学校 ID + 学号 ID + 考试 ID。
Column Family:test。
Column:result, score, 其中 result 是 JSON 格式。
6.2 缓存内容设计
缓存内容:试卷信息
缓存数据类型:采用 redis 字符串即可,KEY 为课程 ID, VALUE 为完整试卷的 JSON 串
缓存策略:缓存直接采用 LRU 策略即可,缓存只在请求试卷的那一分钟,过期时间分钟级即可,试卷内容一旦生成不会更改,无需主动淘汰缓存
缓存读写流程:由于一场考试最多 7500 套试卷内容,数量并不多,因此可采取读取时加载缓存,没有命中则从数据库中读取后加载到缓存,无需专门进行试卷缓存提前预热
评论