写点什么

架构实战营作业 M04

用户头像
Shawn Liu
关注
发布于: 1 小时前

已知存储性能需求:

  • 请求试卷:5w/s

  • 提交试卷:1700/s


已知:Redis 数据模型包含下面几种

  • String

  • Hashtable

  • Linked List

  • Set

  • Sorted Set


前提:

  • 这里选择题默认都是单选题,如果有多选的场景,额外拆分出一个类目”多选题“,和其他题目类型同级别处理


考卷存储结构

因为是机考,所以出试卷的方式有多种策略:

  1. 所有学生试卷一致

  2. 学生试卷题目固定几种,如 AB 卷

  3. 学生试卷题目完全随机

且可以设置每类题目出现顺序是否一致


然后因为需要支撑多种学科、多门课程的试题,所以需要考虑到题库之间的数据隔离。因为学科、课程种类繁多,虽然 Redis 支持多 DataBase,但是显然是不能够满足一类考试一个 DataBase 的。所以将所有题库都放在一个 DataBase 中,通过 Key 的 Pattern 来区分开类别。


1. 所有学生考卷一致

如果考卷内容完全一致,那么其实只需要老师在他的教师端系统编辑好考卷,然后在 Redis 中存储一份试卷内容即可。Redis 中 Key 满足下面格式:

exam:<course_id>:fixede.g. examp:0:fixed
复制代码

course_id 为其他存储(系统)中,科目、课程对应的主键,为方便下面描述,这里统一选取 course_id = 0 进行描述

其中 fixed 为考卷策略的缩写,为了和下面几种不同策略保持整体 Pattern 的一个一致性而保留。Redis 中的 Value 为实际的题目内容,可以使用 JSON 格式进行保存。整体格式形如:

{  "type": "panduan", // 用于存储题目的类型,判断题->panduan、选择->xuanze、大题->wenda  "id": "xxx", // 实际题目的一个唯一标识,用于唯一标识一个题目  "content": "xxx", // 问题主体,  "options": [  // 选项本体,只有在选择和判断时使用,选择题时可以酌情将[]改为{}  ]}
复制代码

这里需要考虑到题目出现顺序的可配置,但是同类题目顺序的随机化其实没有必要在 Redis 上进行操作,完全可以学生请求试卷时,后端程序根据配置使用代码进行顺序的随机化。这样在 Redis 上实际存储内容无需变动。个人感觉更加方便。


请求试卷流程:直接获取对应 Key 的考题内容,按照是否需要”题目顺序随机化“需求,生成考卷内容,返回前端


2. 学生试卷题目固定几种

和上面的存储类似,不过是老师在制作试卷的时候需要制作多套而已。实际 Value 的存储设计也可以和上面的策略保持一致。Key 需要区分出场景,满足下面的 Pattern

exam:<course_id>:multi:<a/b/c>
复制代码

其中 multi 是固定字面量,用于标识出这个 K,V 放的都是 AB 卷这种形式的卷子内容

当学生在获取试卷时,后端程序先按照一定算法(如 A、B、C 卷随机)指定一套卷子,然后用同策略 1 一样的方式获取试卷内容即可。


请求试卷流程:直接获取对应 Key 的考题内容,按照是否需要”题目顺序随机化“需求,生成考卷内容,返回前端


3. 考试题目完全随机

和上面 2 种策略不同,试题随机处理起来相对复杂。因为题目随机,所以需要引申出”题库“的概念。学生请求试卷时,需要后端程序能够动态的从题库中提取出指定数量的题目,生成试卷。Key 我们和上面保持类似的 Pattern:

exam:<course_id>:rand-tk:<question_type>
复制代码

其中 rand-tk 标识这是试卷内容的题库,question_type 用来区分是哪类型的题目

为了方面描述,做下面的定义:

  • 判断题:question_type 固定为 panduan

  • 选择题:question_type 固定为 xuanze

  • 大题(问答题):question_type 固定为 wenda

所有类型题目都使用 Set 进行存储,因为涉及到题目的随机化,这部分逻辑如果放在后端程序进行实现,需要拉取整体题库,然后随机化。这样操作对网络、Redis 性能影响可能都比较大,且如果在后端进行局部缓存的方式来提升性能,那 Redis 的意义又不太明显。所以考虑将随机化动作放在 Redis 侧,利用 Redis 的 srandmemeber 命令来从集合中获取随机内容。

Redis 中 Value 为实际题目的内容,因为在 Key 层已经区分了 question_type,所以 Value 可以用下面的格式进行存储:

{  "id": "xxx", // 实际题目的一个唯一标识,用于唯一标识一个题目  "content": "xxx", // 问题主体,  "options": [  // 选项本体,只有在选择和判断时使用,选择题时可以酌情将[]改为{}  ]}
复制代码

ps:因为考题在一开始已经随机化,所以试题出现顺序的随机化这个动作没有什么实际意义了


请求试卷流程:后端程序分别从 3 类 question_type 的 K,V 中 srandmemeber <key> [count]出指定数量的题目,然后生成考试试卷,返回给考试系统即可。


学生试卷答案

经评估,考生提交试卷的 TPS 要求约为 1700,量级不大,这部分逻辑如果放在 Redis 的话,可以使用 Map 进行存储,其中 Key 为上面提到的题目 id,Value 为实际的答案,比如判断 T/F、选择题存 A/B/C/D、大题直接存学生填入的内容

这样存储结构比较简单,也可以满足实际需求。


服务器数量评估

经评估,Redis 集群化方案使用 Redis Sentinel。单机 Redis 的 TPS 为 5~10 万。那么按照性能需求的 5w 来计算,最好能够保证 2 台 Slave 来处理读请求,Master 负责 Cover 提交的场景。整体评估如下:

  1. 总共 Redis 需要 3 台机器,其中 1 台作为 Master、2 台作为 Slave

  2. Slave 单机负责 Cover 约 2.5w 的 TPS,Master 负责 Cover1700 的提交 TPS

发布于: 1 小时前阅读数: 6
用户头像

Shawn Liu

关注

还未添加个人签名 2018.05.04 加入

还未添加个人简介

评论

发布
暂无评论
架构实战营作业 M04