架构训练营 week4 作业
1. 业务背景
千万级的学生管理系统需要有相应的试卷存储和读取的机制,有以下业务要求:每门学科每年 2 次考试,每个学生平均一学期 20 门课,考试采取机考的方式,每门考试的答案 20 判断题、20 选择题、4 道大题(答案 200 字以内),考试结果永久保存,在校学生能够看到自己曾经的考试结果。
学校的考试都安排在某一个月内,考试的时候请求试卷,提交答案,中间答题过程浏览器本地完成,由于考试集中在上午 4 小时和下午 4 小时,且请求试卷集中在考试开始的前 1 分钟,提交答案集中在考试结束前的 30 分钟。
2. 约束和限制
试卷在读取的时候不能出现读取失败的情况,否则会影响考试进程
试卷要可以随时编辑和保存
试卷内容永久保存,不能丢失
3. 总体架构
3.1 架构分析
高可用:使用了 Redis sentinel 对于整个 redis 的集群进行了高可用的保障,任何一个 redis 的实例出现写入或者读取问题的时候,sentinel 就会重新确定 master,并且尝试恢复不可服务的实体,在重启后将它改为 slave。
高性能:单个 redis 在压测过程中,完全可以支持 5 万/s 的并发量,所以三个 redis 组成的集群,更加可以应付这样的读取压力。而试题的写入是一个并发量极低的过程,所以无需考虑写入的性能问题。
数据永久保存:redis 有持久化功能,使用 redis 的 RDB 的功能,定时对于数据进行持久化,并且用 sentinel 保证主从之间的数据的一致性,可以保证数据不丢失。
3.2 总体架构
采用 redis sentinel 来监控各个 redis 实例的状态,保证 redis 集群内每个 redis 的状态正常
3 台服务器中,一台上部署了 master redis,两台上部署了 slave redis。
一共 3 台服务器,每台服务器上包含一个 redis 和一个 sentinel,这样用 3 台机器的成本就完成了整个 redis 服务集群的搭建
master 提供读写,slave 仅提供读服务,并且其数据是从 master 同步来的。
在某一个 redis 实例宕机的时候,sentinel 会在第一时间发现故障,并且选出新的主 redis 服务实例,在之前宕机的主 redis 恢复之后,它会成为从 redis 继续提供服务
因为一个 sentinel 对于 3 个服务器进行监控的情况下,可能不客观,所以我们在三台服务器上都部署了 sentinel,在一个 sentinel 发现 master 宕机后,会发起一次投票,只有投票通过之后,master 才会下线,并选出 slave 中的一个成为新的 master
即使主服务器宕机了,并且 sentinel 也没有能够选出新的 master,也不影响其他的 slave 继续提供读取服务。只是此时系统无法新增或者编辑试卷信息而已
4. 详细设计
4.1 核心功能
试题写入、编辑流程
试题的写入或者编辑流程,由教师在界面上编辑完试卷的内容,经过浏览器发送请求至 nginx,经由 App 最终到达 Redis,Redis 存入内存中。之后 redis 会定时将内存中的数据持久化,持久化之后的数据就不会因为宕机而丢失,而是存在磁盘中。
试题读取流程
因为试题是存储在 Redis 中的,所以在读取的时候,根据用户传来的 key 可以直接获取试题的内容。
考生会通过浏览器选择哪一年的几年级的什么科目的期中或者期末考试试题,选完之后,参数通过浏览器、nginx 经由 app 最后发送至 Redis,redis 根据 key 可以很快获取到对应的试题(List),List 最终返回给浏览器之后,被渲染成一份完整的试卷展示给考生,考生就可以考试作答了。
4.2 关键设计
数据存储的可靠性:Redis 作为一个内存数据库,主要并非用于持久化,但是它本身其实也可以进行持久化,支持 AOF 和 RDB 两种方式。万一由于宕机,要回复数据也可以借由 RDB+AOF 的方式快速恢复。
读取高性能:Redis 作为一个内存数据库,其读取性能是很高的,足够应付 5W/S 的 QPS,并且我们采用了 3 台 Redis 的主从集群,这个压力更是不在话下,万一其中一台服务器宕机,剩余两台也可以保证进行正常的读取服务。
高可用:由于 Redis + Sentinel 的模式保证了在某一个 redis 宕机的时候,sentinel 会选出新的 redis master,提供读写服务,而剩下的 redis slave 则可以提供读服务。在试题这个案例中,即使 master 宕机,只剩下 slave,整个 redis 集群依然可以提供试题读取服务。
4.3 设计规范
试题存储采用 Redis 的 List 的数据结构。因为试题有很多题,且是有顺序的,而试题的读取是一个顺序遍历的过程就可以解决的,不需要进行索引。而试题编辑的话,也需要将所有的试题罗列出来,编辑其中的部分,最后全量提交即可,因此 List 的结构就可以完全满足。
试题的 key 使用 年份+年级+课程+期中(1)/期末(2)
试题的 Value 使用 Redis 的 List 保存一套试卷的所有试题。
5. 质量设计
无,因为仅仅是存储系统部分
6. 演进规划
无,因为是存储系统部分
版权声明: 本文为 InfoQ 作者【红莲疾风】的原创文章。
原文链接:【http://xie.infoq.cn/article/98a28cbf451c16b9e6decedcb】。未经作者许可,禁止转载。
评论