模块 4 作业 千万级学生管理系统考试试卷存储方案
【作业要求】
基于模块 4 第 6 课的估算结果和 Redis sentinel 的初步方案设计,完善考试试卷存储方案,具体包括:1)完善 Redis 的数据结构设计,明确具体使用哪种 Redis 数据结构
2)设计具体的读写流程(可以文字描述也可以序列图描述,序列图要有文字辅助说明)
3)对照模块 4 第 6 课的性能估算结果,计算 Redis sentinel 集群的服务器数量和性能
性能估算
假设该系统面向的在校大学生数量为 1000 万人,学生的考试均在该系统上进行操作。
假设每门学科每年 2 次考试,每个学生平均一学期 20 门课,考试采取机考的方式,且考试都安排在某一个月内。考试的时候请求试卷,提交答案,中间答题过程浏览器本地完成,学生在考试结束后不能再直接请求试卷内容,试卷内容会结合其作答结果保存至考试结果中。由于考试集中在上午 4 小时和下午 4 小时,且请求试卷集中在考试开始的前 1 分钟,因此可估算试卷请求性能需求:
1000 万 * 20(课)/ 20(周末不考试) / 4(每天 4 堂考试)/ 1 分钟 = 250 万请求/分钟 ≈ 5 万/每秒
大学公共课程每个同学都需要上,但只需要一名老师,而选修课程上课人数则较少,因此假设平均每门课程 200 人,每个老师平均上 2 门课,不同学校间课程和考试资源独立,则可以估算出老师数量为:
1000 万*20(课)/200(每门课 200 人)/2(每个老师上 2 门课)=50 万
而每次考试的试卷数量则为:50 万*2(课)=100 万份
假设每门考试的试卷包括 20 道判断题、20 道选择题、4 道大题,试卷内容永久保存,则可以估算出试卷存储数据量:
每次考试试卷存储数据量:100 万份*(20x100 字节+20x240 字节+4x400 字节+2M 试题图片数据)≈ 2T
假设老师出卷也是在考试安排的一个月内进行,出卷的时候可以查询历史试卷内容,以及上传当前考试试卷内容。假设老师出卷的操作集中在工作日早上 8 点至晚上 8 点之间,出卷期间平均会查询 5 份历史试卷内容,上传一份当前考试试卷内容,则可以估算出:
查询历史试卷:50 万*5(次)*2(课)/20(仅工作日操作)/12(小时)≈ 10 个请求/秒
上传当前试卷:50 万*2(课)/20(仅工作日操作)/12(小时)≈ 2 个请求/秒
性能汇总分析
试卷记录每年 200 万条,存储数据量为 4T,且每年都会按此增长。单次考试试卷记录 100 万条,数据量 2T。
老师查询历史试卷和上传当前考试试卷的性能需求分别为 10QPS、2TPS,可以忽略不计。
老师查询历史试卷时允许查询本门课程过往任意一份试卷内容,但只能查询本校本课程的历史数据,而不允许跨校查询,且对查询性能要求很低。
学生在考试开始前 1 分钟请求试卷的性能需求为 5 万 QPS。
每张试卷大小约为 2.1M,因此按照 5 万 QPS 的请求量,则理论上请求试卷带宽达到 103Gbps,但是由于同一门课程的同学请求的是同一份试卷,可以采用多级缓存机制,假设每门课平均 200 名同学,则实际请求试卷后端存储的带宽需求约为 0.6Gbps。
存储系统选择和架构设计
根据上述性能分析结果,使用 Redis 作为考试期间试卷内容的存储系统,而历史试卷的存储则可以使用 HBase,按学校+年份+期中期末+课程作为 key。
由于每次考试的试卷存储量达到 2T,单机无法支撑,因此使用分片集群架构。假设单机可以存储容量 1T,预留 20%存储空间,则至少需要 3 个分片。为了便于计算以及一定的冗余需求,在此选择创建 5 个分片,每个分片使用 1 主 2 从读写分离架构,总共 15 台机器。每个分片中主机同时处理读写请求,从机只负责处理读请求,由于写请求性能需求非常低,可以忽略不计,而针对读请求,每个分片可以支撑 15~30 万 QPS,足以满足需求。
为了确保 Redis 集群的高可用,使用 Redis Sentinel 架构,Sentinel 本身也需要做高可用,在此还需要 3 台机器。
考虑到 Redis 在持久化方面的不可靠性,因此仅使用集群存储本次考试的试卷内容,同时考虑到不同学校可能都会开同一门课,但试卷不同,因此按照学校 ID 作为分片依据是最合理的。
数据结构
Redis
Key:学校 ID+课程 ID
数据类型:String(json 格式的试卷内容转换为 String)
HBase
Key:学校 ID+年份+考试类型(期中/期末)+课程 ID
Colume Family:exam
Colume:context(json 格式的试卷内容)
读写过程
老师本身被分配了指定的学校 ID 和课程 ID,在编写试卷期间查询历史试卷,通过指定年份和考试类型,再自动带上其学校 ID 和课程 ID,以此组成的 key 查询 HBase,得到历史试卷数据。
老师编写完试卷内容后,以新的 key 存储到 HBase,并由后台程序异步转换数据格式后分发到 Redis 集群中。
学生开考前,通过当前考试所属的学校 ID 和课程 ID 组成 key 请求 Redis,获取试卷数据。
版权声明: 本文为 InfoQ 作者【TH】的原创文章。
原文链接:【http://xie.infoq.cn/article/caabdb6f2d4569b8e4d850255】。未经作者许可,禁止转载。
评论