作业:架构实战营模块 4
背景
设计千万级的学生管理系统的考试试卷存储方案。
基于模块 4 第 6 课的估算结果和 Redis sentinel 的初步方案设计,完善考试试卷存储方案,具体包括:
完善 Redis 的数据结构设计,明确具体使用哪种 Redis 数据结构
设计具体的读写流程(可以文字描述也可以使用序列图描述,序列图要有文字辅助说明)。
对照模块 4 第 6 课的性能估算结果,计算 Redis Sentinel 集群的服务器数量和性能。
假设学校的考试都安排在某一个月内,考试的时候请求试卷,提交答案,中间答题过程浏览器本地完成,由于考试集中在上午 4 小时和下午 4 小时,
且请求试卷集中在考试开始的前 1 分钟,提交答案集中在考试结束前的 30 分钟,因此估算如下:
• 请求试卷:1000 万 * 20(课)/ 20(周末不考试) / 4(每天 4 堂考试)/ 1 分钟 = 250 万请求/分钟 ≈ 5 万/每秒。
• 提交试卷: 1000 万 * 20(课)/ 20(周末不考试) / 4(每天 4 堂考试)/ 30 分钟 = 1700/每秒。
Redis Sentinel: https://redis.io/topics/sentinel
Redis 数据结构设计
方案 1:
数据结构:List
场景:获取试卷内容时,需要遍历 List 的数据。
键:学校 ID+学生年级 ID+学科(看不同学校班级同一科目试卷是否相同)
值格式:Json(包括了题目序号、题目类型、选择题选项列表等)
性能:由于是获取所有数据,因此时间复杂度是 O(N);
方案 2:
数据结构:Sets
场景:获取试卷内容时,需要遍历 Set 的数据,且需要对考试内容按照题目顺序进行排序。
键:学校 ID+学生年级 ID+学科(看不同学校班级同一科目试卷是否相同)
值格式:Json(包括了题目序号、题目类型、选择题选项列表等)
性能:获取所有题目时,只需要通过 key 获取即可。
方案 3:
数据结构:Strings
场景:获取考试题目时,单 key 查询,时间复杂度为 O(1),但可能因为 key 值较大导致性能较差。
键:学校 ID+学生年级 ID+学科(看不同学校班级同一科目试卷是否相同)
值格式:Json(包括了题目序号、题目类型、选择题选项列表等)
性能:获取所有题目时,只需要通过 key 获取即可。
最终选择:方案 2.
理由:
查询方式:一次性拉取
数据内容:大部分为文字;小部分图片,多为简单线条,容易压缩占用空间小。
因此实际性能优先考虑使用 Strings 进行存储,如果在存储方案验证阶段发现有问题,可以很容易替换为 List 方式。
Set 因为多了一步排序操作,增加了复杂度和服务计算压力,排除。
读写流程
开考前一段时间,批量写入试卷数据。
读取数据为,根据考生信息对应的键进行 GET 查询。
性能评估
根据上述预估,考试时请求试卷 QPS 约等于 5w/s,对此数量进行适当预留,预估 7.5W/s 是够用的。
采用架构为 Redis Sentinel,可以很容易做到读写分离,使得读请求在 Sentinel 之间分配。
根据 Redis 官方的数据大小与读取吞吐量的表格(https://redis.io/topics/benchmarks)说明:
数据大小在 1KB 以内时,可以达到 10w QPS
当数据大小增加到 10KB 时,1Gbps 局域网 QPS 下降到 1W,而本地测试 QPS 依然接近 10W。
网络带宽和延迟通常是最大的短板。
在吞吐量足够情况下,QPS 大约是 10w/s。
假设试卷平均 100KB
网络瓶颈方面:带宽至少为 100000*75000 约等于 7.5GB/s,对于 10Gbps 的内网,至少需要 7.5/(10/8)=6 台服务器能满足需求。
计算瓶颈方面:单台机器的计算能力已经可以满足需求。根据场景需求,主要请求都为读取操作,写入操作引起的复制、AOF、RDB 压力不会很大,因此采用双核即可满足需求。
存储空间方面:大量重复内容,很容易满足需求。4GB 足够。
因此采用 2C4G 的服务器*6 台即可。
版权声明: 本文为 InfoQ 作者【Poplar89】的原创文章。
原文链接:【http://xie.infoq.cn/article/dc0d43251edba3650a32644dd】。未经作者许可,禁止转载。
评论