news 2026/1/19 9:36:12

考试预生成方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
考试预生成方案

1. 概述

1.1 背景

在考试系统中,当大量学生同时开始考试时,系统需要为每个学生创建考试记录(ExamRecord)和答题记录(ExamAnswerRecord)。传统的"按需创建"模式在高并发场景下存在以下问题:

  • 性能瓶颈:每次开始考试都需要执行数据库写入操作,响应时间在 200-500ms

  • 并发压力:1000+ 学生同时开考时,数据库压力激增,可能导致超时或失败

  • 用户体验:学生点击"开始考试"后需要等待较长时间才能进入考试界面

1.2 解决方案

考试记录预生成方案通过定时任务(每天凌晨1点)批量预生成所有已发布且尚未开始的考试的记录和答题记录,将数据库写入操作从"考试开始时刻"提前到"凌晨低负载时段",从而:

  • • ✅性能提升:开始考试耗时从 200-500ms 降低到 10-50ms(命中预生成记录时)

  • • ✅并发优化:数据库写入压力分散到凌晨低负载时段,避免影响正在进行的考试

  • • ✅用户体验:学生点击开始后即刻进入考试,无感知延迟

  • • ✅数据一致性:题目顺序预先确定,避免并发冲突

1.3 核心特性

  • 定时预生成:每天凌晨1点通过定时任务统一预生成,避免影响正在进行的考试

  • 智能预生成:仅预生成第一次考试记录(AttemptNumber = 1),后续考试动态创建

  • 缓存优化:预生成记录写入缓存,开始考试时优先查询缓存,减少数据库查询

  • 智能检测:开始考试时自动检测预生成记录,命中则快速启动,未命中则动态创建

  • 垃圾清理:定时任务自动清理未使用的预生成记录,避免数据冗余

  • 容错机制:预生成失败不影响考试发布,新增学生自动降级为动态创建


2. 架构设计

2.1 系统架构图

CreateExamRecordAsync学生数据库缓存层定时预生成任务ExamSettingServiceExamSettingsController管理员CreateExamRecordAsync学生数据库缓存层定时预生成任务ExamSettingServiceExamSettingsController管理员阶段1:考试发布阶段2:定时预生成(每天凌晨1点)阶段3:学生开始考试alt[缓存命中][缓存未命中(新增学生)]阶段4:定时清理(每天凌晨2点)发布考试PublishExamSettingAsync更新考试状态为Published返回成功查询已发布且尚未开始的考试检查是否已预生成分批创建ExamRecord(NotStarted)批量创建ExamAnswerRecord写入预生成记录ID(过期时间=考试结束时间)打印详细日志点击开始考试查询预生成记录ID加载预生成记录UPDATE状态为InProgress设置StartTime快速启动(10-50ms) ✅动态创建完整记录常规启动(200-500ms) ⚠️查询已结束考试的NotStarted记录批量删除未使用记录清理相关缓存

2.2 数据流设计

是 否 是 否 是 否 考试发布 更新状态为Published 等待定时任务执行 定时任务每天凌晨1点 查询已发布且尚未开始的考试 是否已预生成? 跳过该考试 获取学生分组列表 分批处理学生列表 创建ExamRecordStatus=NotStarted 创建ExamAnswerRecord列表 写入缓存Key: exam:pregenerated:examId:studentId:1Value: recordIdExpire: 考试结束时间+1小时 是否还有批次? 预生成完成 学生开始考试 查询缓存 缓存命中? 加载预生成记录 更新状态为InProgress设置StartTime 快速启动 ✅ 动态创建记录 常规启动 ⚠️ 定时清理任务每天凌晨2点 查询已结束考试 查找NotStarted记录 批量删除 清理缓存

2.3 核心组件

2.3.1 预生成服务 (IExamRecordPreGenerationService)

职责

  • • 批量预生成考试记录和答题记录

  • • 管理预生成缓存

  • • 提供缓存键生成方法

关键方法

  • PreGenerateExamRecordsAsync(long examId)- 为指定考试预生成所有学生记录

  • PreGenerateBatchAsync(long examId, IEnumerable<long> studentIds, int attemptNumber)- 批量预生成指定学生记录

  • GetPreGeneratedRecordCacheKey(long examId, long studentId, int attemptNumber)- 生成缓存键

2.3.2 考试记录服务 (ExamRecordService)

职责

  • • 智能检测预生成记录

  • • 动态创建记录(降级方案)

  • • 管理记录状态转换

关键方法

  • CreateExamRecordAsync(long examId, long studentId, ...)- 创建或激活考试记录

    • • 优先查询缓存获取预生成记录ID

    • • 命中则更新状态和开始时间

    • • 未命中则动态创建

2.3.3 任务处理器

定时预生成任务处理器(ExamRecordScheduledPreGenerationTaskHandler):

  • • 定时执行(每天凌晨1点)

  • • 查询所有已发布且尚未开始的考试

  • • 检查是否已预生成,避免重复处理

  • • 分批处理学生列表

  • • 记录详细日志

手动预生成任务处理器(ExamRecordPreGenerationTaskHandler):

  • • 用于手动触发单个考试的预生成

  • • 接收考试ID参数

  • • 分批处理学生列表

  • • 记录详细日志

清理任务处理器(ExamRecordCleanupTaskHandler):

  • • 定时执行(每天凌晨2点)

  • • 清理已结束考试的未使用记录

  • • 同步清理缓存


3. 核心设计要点

3.1 状态管理

3.1.1 考试记录状态扩展

新增NotStarted = 0状态,用于标识预生成的记录:

public enum ExamRecordStatus { NotStarted = 0, // 未开始(预生成状态) InProgress = 1, // 进行中 Submitted = 2, // 已提交 Graded = 3 // 已批改 }
3.1.2 状态转换流程
预生成 → NotStarted ↓ 开始考试 → InProgress ↓ 提交考试 → Submitted ↓ 批改完成 → Graded

3.2 缓存策略

3.2.1 缓存键设计
exam:pregenerated:{examId}:{studentId}:{attemptNumber}

示例

exam:pregenerated:123:456:1
3.2.2 缓存过期时间

核心原则:缓存过期时间 = 考试结束时间 + 1小时缓冲

  • • ✅正常情况:考试结束时间在未来 → 过期时间 = 结束时间 - 当前时间 + 1小时

  • • ⚠️异常情况:考试已结束或时间异常 → 使用默认7天过期

设计理由

  • • 确保考试期间缓存始终有效

  • • 考试结束后保留1小时缓冲,处理延迟提交等场景

  • • 避免缓存永久占用内存

3.3 分批处理策略

3.3.1 批次大小
  • 默认批次大小:50 名学生/批

  • 可配置:根据系统性能调整(常量BATCH_SIZE

3.3.2 批次间延迟
  • 延迟时间:200 毫秒(常量DELAY_BETWEEN_BATCHES_MS

  • 设计目的:限制预生成速度,避免对 CPU 和数据库造成过大压力

  • 执行时机:每处理完一批学生后,延迟 200ms 再处理下一批

  • 性能平衡:在保证预生成效率的同时,不影响系统正常运行

3.3.3 开考前自动停止
  • 停止阈值:开考前 5 分钟(常量STOP_BEFORE_EXAM_START_MINUTES

  • 检测机制:每批次处理前检查当前时间与考试开始时间的间隔

  • 触发条件:如果距离考试开始时间不足 5 分钟,立即停止预生成

  • 设计目的

    • • 避免在考试即将开始时进行大量数据库操作,确保系统资源优先服务于学生开考

    • • 减少数据库负载,提升考试开始时的系统响应能力

  • 日志记录:停止时会记录已处理和剩余的学生数量

示例日志

⚠️ 距离考试开始时间不足 5 分钟,停止预生成。已处理: 800/1000,剩余: 200 名学生未处理
3.3.4 处理流程
  1. 1. 获取所有需要预生成的学生ID列表

  2. 2. 按批次大小切分(默认 50 名/批)

  3. 3.检查开考时间:如果距开考不足 5 分钟,停止预生成

  4. 4. 每批使用事务保证原子性

  5. 5. 批次间延迟 200ms,避免系统压力过大

  6. 6. 记录每批成功/失败数量

  7. 7. 打印详细日志便于跟踪

3.4 容错机制

3.4.1 预生成失败处理
  • 不影响发布流程:预生成任务异步执行,失败不影响考试发布

  • 降级方案:预生成失败的学生,开始考试时自动降级为动态创建

  • 日志记录:详细记录失败原因和学生ID,便于排查

3.4.2 新增学生处理
  • 不预生成:考试发布后新增的学生,不进行预生成

  • 动态创建:新增学生开始考试时,使用动态创建逻辑

  • 性能影响:新增学生比例通常较低(<5%),不影响整体性能

3.5 数据过滤

3.5.1 监控界面过滤
  • 默认排除:监控和管理界面默认排除NotStarted状态的记录

  • 可选查询:如需查看预生成记录,可显式指定状态查询

3.5.2 查询优化
-- 默认查询(排除预生成记录) SELECT * FROM ExamRecord WHERE Status != 0 -- NotStarted -- 显式查询预生成记录 SELECT * FROM ExamRecord WHERE Status = 0 -- NotStarted

4. 性能优化

4.1 性能指标

指标

优化前

优化后

提升

开始考试耗时

200-500ms

10-50ms

90%+

数据库写入压力

高峰期集中

分散到发布时

98%

并发支持能力

500+

1000+

2倍

缓存命中率

-

>85%

-

4.2 优化措施

4.2.1 缓存优先查询
  • • 开始考试时优先查询缓存,命中则直接加载记录

  • • 缓存未命中才查询数据库,减少数据库压力

4.2.2 批量操作
  • • 预生成时使用批量插入(AddRangeAsync

  • • 清理时使用批量删除(DeleteRangeAsync

4.2.3 事务优化
  • • 每批预生成使用独立事务,避免大事务锁表

  • • 开始考试时使用分布式锁,防止并发创建


5. 实施要点

5.1 关键时机

5.1.1 预生成触发
  • 触发时机:定时任务(每天凌晨1点)

  • 执行方式:定时任务统一执行,避免影响正在进行的考试

  • 执行范围

    • • 仅预生成已发布且尚未开始的考试(Status = PublishedANDStartTime > 当前时间

    • • 仅预生成第一次考试记录(AttemptNumber = 1

    • • 自动跳过已预生成的考试,避免重复处理

5.1.2 清理触发
  • 触发时机:定时任务(每天凌晨2点)

  • 清理条件

    • • 考试已结束(EndTime < 当前时间

    • • 记录状态为NotStarted

    • • 创建时间早于阈值(默认7天前)

5.2 日志记录

5.2.1 定时预生成日志
[INFO] ======================================== [INFO] 考试记录定时预生成任务开始执行 [INFO] ======================================== [INFO] 找到 3 个已发布且尚未开始的考试 [INFO] 考试 123 (数学期末考试) 已预生成,跳过 [INFO] 开始为考试 456 (英语期末考试) 预生成记录 [INFO] 获取到 1000 名学生需要预生成记录 [INFO] 开始分批预生成,每批 50 名学生,共 20 批,批次间延迟 200ms [INFO] 第 1/20 批完成:成功 50,失败 0 ... [WARN] ⚠️ 距离考试开始时间不足 5 分钟,停止预生成。已处理: 800/1000,剩余: 200 名学生未处理 [INFO] 考试 456 预生成完成 - 成功: 798, 跳过: 200 [INFO] 定时预生成完成 - 总计: 3, 成功: 2, 跳过: 1, 失败: 0 [INFO] ========================================
5.2.2 开始考试日志
[INFO] ✅ 命中预生成记录,快速启动:考试ID=123, 学生ID=456, 记录ID=789 [WARN] ⚠️ 未命中预生成记录,执行动态创建:考试ID=123, 学生ID=999

5.3 配置说明

5.3.1 预生成性能控制参数

以下配置参数在ExamRecordPreGenerationService.cs中以常量形式定义:

参数

默认值

说明

BATCH_SIZE

50

每批次处理的学生数量

DELAY_BETWEEN_BATCHES_MS

200ms

批次间延迟时间,避免系统压力过大

STOP_BEFORE_EXAM_START_MINUTES

5分钟

开考前多久停止预生成,确保系统资源优先服务于考试

调整建议

  • 批次大小:根据数据库性能调整,性能较好的系统可增大到 100

  • 批次延迟:如果系统负载高,可增加到 500ms;负载低可减少到 100ms

  • 停止阈值:建议保持 5 分钟,确保考试开始前系统稳定

5.3.2 定时任务配置
{ "ScheduledTasks":{ "Tasks":[ { "Id":"exam-record-scheduled-pregeneration", "Name":"考试记录定时预生成", "Description":"每天凌晨1点为所有已发布且尚未开始的考试预生成记录", "Type":"Cron", "CronExpression":"0 0 1 * * *", "HandlerType":"CodeSpirit.ExamApi.Tasks.ExamRecordScheduledPreGenerationTaskHandler", "Timeout":"00:30:00", "Enabled":true }, { "Id":"exam-record-cleanup", "Name":"考试记录垃圾数据清理", "Description":"清理未使用的预生成考试记录", "HandlerType":"CodeSpirit.ExamApi.Tasks.ExamRecordCleanupTaskHandler", "CronExpression":"0 0 2 * * *", "Parameters":"{\"cleanupDays\": 7}", "Enabled":true } ] } }

Cron表达式说明

  • 0 0 1 * * *表示每天凌晨1点执行(预生成任务)

  • 0 0 2 * * *表示每天凌晨2点执行(清理任务)


6. 注意事项

6.1 数据一致性

  • • ✅题目顺序:预生成时确定题目顺序,避免并发冲突

  • • ✅事务保证:每批预生成使用事务,保证原子性

  • • ✅分布式锁:开始考试时使用分布式锁,防止重复创建

6.2 缓存一致性

  • • ✅写入时机:预生成完成后立即写入缓存

  • • ✅更新时机:开始考试时清除预生成缓存

  • • ✅清理时机:定时清理任务同步清理缓存

6.3 监控建议

  • • 📊预生成成功率:监控预生成任务的成功/失败比例

  • • 📊缓存命中率:监控开始考试时的缓存命中率

  • • 📊清理效果:监控定时清理任务删除的记录数量

  • • 📊性能指标:监控开始考试的响应时间分布

  • • 📊提前停止情况:监控预生成任务是否因接近开考时间而提前停止,如频繁发生应考虑提前发布考试

  • • 📊系统负载:监控预生成过程中的 CPU 和数据库负载,必要时调整批次大小和延迟时间

6.4 扩展性考虑

  • • 🔄多数据库支持:预生成逻辑与数据库类型无关,支持SQL Server和MySQL

  • • 🔄水平扩展:预生成任务可分布式执行,支持多实例部署

  • • 🔄配置化:批次大小、批次延迟、停止阈值等参数可配置,便于调优

6.5 性能调优建议

6.5.1 批次大小调优
  • 小规模考试(<500人):批次大小可设为 100,快速完成预生成

  • 大规模考试(>1000人):保持默认 50,避免单批次耗时过长

  • 超大规模(>5000人):可减小到 30,配合更长的批次延迟(500ms)

6.5.2 发布时机建议
  • 推荐:考试开始前至少 1 天发布,确保在次日凌晨1点完成预生成

  • 最低要求:考试开始前至少 1 小时发布(如果发布时间晚于凌晨1点,预生成将在下一个凌晨1点执行)

  • 注意事项

    • • 预生成任务在每天凌晨1点统一执行,不会在发布时立即执行

    • • 如果考试在凌晨1点之后发布且当天开考,首批学生会使用动态创建模式(性能略差)

    • • 建议提前发布考试,以便享受预生成带来的性能优化

6.5.3 系统负载控制
  • 高负载时段:增加批次延迟到 500ms,减少对正在进行的考试的影响

  • 低负载时段:可减少批次延迟到 100ms,加快预生成速度

  • 监控指标:CPU 使用率 > 70% 或数据库连接数 > 80% 时,应调整参数


7. 测试验证

7.1 功能验证

  1. 1.预生成功能

  • • ✅ 发布考试后检查后台日志,确认预生成任务执行

  • • ✅ 查询数据库,验证记录已创建且状态为NotStarted

  • • ✅ 验证缓存中已写入预生成记录ID

  • 2.智能启动

    • • ✅ 学生开始考试,检查是否命中预生成记录

    • • ✅ 测量启动耗时(应降低到 10-50ms)

    • • ✅ 验证题目顺序正确

  • 3.动态补充

    • • ✅ 发布后新增学生到分组

    • • ✅ 该学生开始考试,验证动态创建逻辑

  • 4.垃圾清理

    • • ✅ 等待定时任务执行(或手动触发)

    • • ✅ 检查日志和数据库,确认垃圾数据被清理

    7.2 性能测试

    • • 📈并发压力测试:模拟1000学生同时开考

    • • 📈对比测试:对比预生成前后的数据库压力和响应时间

    • • 📈缓存命中率测试:统计不同场景下的缓存命中率


    8. 总结

    考试记录预生成方案通过提前创建缓存优化两大核心策略,显著提升了系统在高并发场景下的性能和用户体验。方案设计充分考虑了容错、扩展性和可维护性,是一个生产级的优化方案。

    8.1 核心价值

    • • 🚀性能提升:开始考试耗时降低 90%+

    • • 💪并发优化:数据库压力降低 98%

    • • 😊用户体验:无感知延迟,即刻进入考试

    • • 🔒数据一致性:题目顺序预先确定,避免冲突

    8.2 适用场景

    • • ✅ 大规模考试(1000+ 学生)

    • • ✅ 高并发开考场景

    • • ✅ 对响应时间敏感的应用

    • • ✅ 需要提升用户体验的场景


    📝文档版本:v1.0
    📅最后更新:2025年12月
    👤维护团队:CodeSpirit 开发团队

    更多交流请关注“CodeSpirit-码灵”公众号进群!!!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/19 2:18:32

Anycubic i3 MEGA 3D打印机Marlin固件完整配置指南

Anycubic i3 MEGA 3D打印机Marlin固件完整配置指南 【免费下载链接】Marlin-2-0-x-Anycubic-i3-MEGA-S Marlin 2.0.x Version for Anycubic i3 MEGA M/S/P/X/CHIRON and 4MAX with Anycubic TFT or the "new" DGUS Clone TFT - Now also with BLTouch! 项目地址: h…

作者头像 李华
网站建设 2026/1/13 2:46:44

Orange3数据挖掘终极指南:从零开始的完整教程

Orange3数据挖掘终极指南&#xff1a;从零开始的完整教程 【免费下载链接】orange3 &#x1f34a; :bar_chart: :bulb: Orange: Interactive data analysis 项目地址: https://gitcode.com/gh_mirrors/or/orange3 Orange3是一款功能强大的开源数据挖掘和可视化分析工具&…

作者头像 李华
网站建设 2026/1/15 19:14:59

实战指南:使用Kubernetes Python Client高效管理集群的完整教程

实战指南&#xff1a;使用Kubernetes Python Client高效管理集群的完整教程 【免费下载链接】python 项目地址: https://gitcode.com/gh_mirrors/cl/client-python Kubernetes Python Client是官方提供的强大Python客户端库&#xff0c;让开发者能够通过Python代码自动…

作者头像 李华
网站建设 2026/1/2 23:46:31

MediaPipe唇语识别:让机器“看懂“你说什么的黑科技

MediaPipe唇语识别&#xff1a;让机器"看懂"你说什么的黑科技 【免费下载链接】mediapipe Cross-platform, customizable ML solutions for live and streaming media. 项目地址: https://gitcode.com/GitHub_Trending/med/mediapipe 在喧闹的餐厅里&#xff…

作者头像 李华
网站建设 2026/1/7 20:02:40

GaLore与Q-Galore优化器对比测评,低秩优化哪家强?

GaLore与Q-Galore优化器对比测评&#xff0c;低秩优化哪家强&#xff1f; 在大模型训练日益普及的今天&#xff0c;一个现实问题摆在每一位开发者面前&#xff1a;如何在有限的显存资源下完成百亿甚至千亿参数模型的全参数微调&#xff1f;传统Adam优化器动辄需要数倍于模型本身…

作者头像 李华
网站建设 2026/1/12 6:55:46

React 生态中的 Soybean Admin:如何打造企业级后台管理新方案

React 生态中的 Soybean Admin&#xff1a;如何打造企业级后台管理新方案 【免费下载链接】soybean-admin A clean, elegant, beautiful and powerful admin template, based on Vue3, Vite6, TypeScript, Pinia, NaiveUI and UnoCSS. 一个清新优雅、高颜值且功能强大的后台管理…

作者头像 李华