千万级学生管理系统考试试卷存储方案
业务背景
[考试]
假设每门学科每年 2 次考试,每个学生平均一学期 20 门课,考试采取机考的方式,每门考试的答案 20 道判断题、20 道选择题、4 道大题(答案 200 字以内),考试结果永久保存,在校学生能够看到自己曾经的考试结果,则考试结果记录的存储量为:
在校生:1000 万*20(课)*2(考试次数)*1000(答案) *2(学期)*3(只有前 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/每秒
约束和限制
暂无
总体架构
考试试卷存储架构总体上使用 Redis Sentinel 存储方案,SDK 客户端连接哨兵节点获取 Redis server 主实例,从而跟主实例进行通信交互。
3.1 架构分析
3.1.1 高可用
哨兵节点 3 大作用:
监控
选主
切换通知
首先监视 redis 实例的健康情况,属于被动型活性拨测,当从实例挂掉,主动剔除即可,当主实例挂掉,根据从实例的日志进度等信息进行选主,选完主后,进行客户端的流程切换,从而达到高可用。
3.2 总体架构
1)、考试开始前 1 分钟,学生通过 Nginx 负载均衡访问到后端考试服务器;
2)、考试服务通过 Jedis SDK 通过 Redis 服务实例;
3)、Redis 实例把试卷内容下发到客户端;
详细设计
4.1 核心功能
4.1.1 请求试卷
试卷试题分为 3 类:20 道判断题、20 道选择题(可能是多选题)、4 道分析大题
【判断题】:
通过 redis 的 list 数据类型可以存储题目:
rpush exam0 q0
rpush exam0 q1
...
rpush exam0 q19
即可将 20 到判断题定义出来
可通过 lrange exam0 0 -1 将判断题从第一题列出直到最后一题,exam0 认为为就是判断题,题目答案自动补充 ()正确 ()错误,让学生做出打勾判断
【选择题】:
rpush exam1 q20
rpush exam1 q21
...
rpush exam1 q39
即可将 20 到选择题定义出来,
假定每道选择题都有 4 个选项,通过定义一个 zset 来表示 4 个选项,即 zadd op20 1 A 2 B 3 C 4 D
【分析题】
rpush exam2 q40
rpush exam2 q41
rpush exam2 q42
rpush exam2 q43
定义即可
4.1.2 提交试卷
【判断题】
使用一个 hash 来表示一个学生所判断的答案,即 mset ans0 1/0 1 表示正确、0 表示错误
【选择题】
对应每道选择题使用一个 zset 来保存,即 zadd ans20 1 A 3 C,加入选择了 A、C 选项;
【分析题】
4 到分析题,通过 String 来保存答案即可,即 set ans40 *****
4.2 关键设计
由于是千万级别学生系统,加上一个学校有 5 万人,大致有 200 间学校,为每间学校搭建一个 Redis Sentinel 集群,能够支撑到 5 万的 qps。
质量设计
5.1 成本
由于 Redis 集群方案使用 Sentinel 模式,为了节约成本,兼顾高可用,每个集群仅使用一个从机。
评论