1. 项目概述与背景
在线教育行业近年来呈现爆发式增长,特别是在后疫情时代,企业对员工培训、学校对远程考核的需求激增。传统考试系统普遍面临两大痛点:一是高并发场景下系统稳定性不足,二是缺乏完善的防作弊机制。我们团队基于Vue.js和.NET技术栈开发的这套系统,在日活10万+的实际生产环境中验证了其可靠性。
技术选型背后的思考:Vue.js的轻量级特性和响应式数据绑定非常适合频繁交互的考试场景,而.NET Core的高性能与跨平台能力为后端服务提供了坚实保障。这种组合在保证开发效率的同时,也满足了企业级应用对稳定性的严苛要求。
2. 技术架构设计
2.1 前后端分离架构实践
采用经典的MVVM模式:
- 前端:Vue 2.x + Vuex状态管理
- 后端:.NET Core 3.1 WebAPI
- 数据库:PostgreSQL 12(支持JSONB格式存储考试记录)
- 消息队列:RabbitMQ处理异步阅卷任务
csharp复制// 典型API控制器示例
[ApiController]
[Route("api/exam")]
public class ExamController : ControllerBase
{
private readonly IExamService _examService;
[HttpPost("submit")]
public async Task<IActionResult> SubmitAnswers([FromBody] AnswerSheetDto answers)
{
// 防重复提交校验
var cacheKey = $"submit_lock_{answers.UserId}_{answers.ExamId}";
if(_cacheService.Exists(cacheKey)){
return BadRequest("请勿重复提交");
}
_cacheService.Set(cacheKey, true, TimeSpan.FromSeconds(30));
// 异步处理答卷
_messageQueue.Publish(new GradingTask(answers));
return Accepted();
}
}
2.2 高并发解决方案
针对考试开始时的流量洪峰,我们实现了三级缓存策略:
| 缓存层级 | 技术实现 | 缓存时效 | 适用场景 |
|---|---|---|---|
| 一级缓存 | 内存缓存 | 5分钟 | 高频访问的试题数据 |
| 二级缓存 | Redis集群 | 2小时 | 考试场次配置信息 |
| 三级缓存 | 静态HTML | 24小时 | 课程介绍等不变内容 |
数据库层面采用:
- 读写分离(1主3从)
- 试题表按课程ID分片
- 考试记录表按月分区
3. 核心功能实现
3.1 智能组卷系统
组卷算法采用权重分配+随机抽样策略:
- 管理员设置题型分布(如选择题40%、填空题30%)
- 系统根据难度系数筛选题库
- 使用Fisher-Yates算法进行题目洗牌
javascript复制// 前端组卷配置界面逻辑
export default {
data() {
return {
ruleForm: {
examType: 'chapter',
questionRules: [
{ type: 'single', count: 20, score: 2 },
{ type: 'multi', count: 10, score: 3 }
]
}
}
},
methods: {
async generatePaper() {
const { data } = await this.$http.post('/api/paper/generate', this.ruleForm)
this.paperPreview = data
}
}
}
3.2 防作弊技术实现
我们采用分层防御策略:
客户端防护:
- 通过MutationObserver监听DOM变化
- 禁止开发者工具快捷键(Ctrl+Shift+I)
- 全屏API锁定考试界面
服务端校验:
- 答题时间间隔分析(如每道题<3秒视为异常)
- 答案相似度对比
- IP地址与设备指纹绑定
csharp复制// 防切屏检测中间件
public class AntiCheatingMiddleware
{
public async Task InvokeAsync(HttpContext context)
{
var watch = Stopwatch.StartNew();
await _next(context);
watch.Stop();
if (context.Request.Path.StartsWithSegments("/api/exam"))
{
var session = context.Session.GetString("ExamSession");
if (watch.Elapsed.TotalSeconds > 5)
{
_logger.LogWarning($"可疑操作检测:用户{session}可能切换窗口");
}
}
}
}
4. 性能优化实践
4.1 前端性能提升
-
懒加载优化:
- 试题图片使用WebP格式
- 视频采用HLS分片传输
- 非核心组件异步加载
-
状态管理优化:
javascript复制// 使用Vuex模块化考试状态
const examModule = {
state: () => ({
currentQuestion: null,
answers: new Map()
}),
mutations: {
cacheAnswer(state, { qid, answer }) {
state.answers.set(qid, answer)
localStorage.setItem('exam_cache', JSON.stringify([...state.answers]))
}
}
}
4.2 后端高并发处理
压力测试指标对比:
| 场景 | 未优化QPS | 优化后QPS | 提升幅度 |
|---|---|---|---|
| 考试提交 | 1200 | 5600 | 367% |
| 成绩查询 | 800 | 4500 | 462% |
关键优化手段:
- 使用Dapper替代EF Core处理高频查询
- 试卷HTML预渲染
- 引入Polly实现弹性重试
5. 部署与监控
5.1 CI/CD流程
采用GitHub Actions实现自动化部署:
yaml复制name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '3.1.x'
- run: dotnet publish -c Release -o ./publish
- name: Deploy to IIS
uses: appleboy/scp-action@master
with:
host: ${{ secrets.PROD_SERVER }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
source: "./publish/*"
target: "/var/www/exam_system"
5.2 监控体系搭建
使用Prometheus+Grafana监控关键指标:
- 考试提交成功率
- 平均响应时间
- 数据库连接池使用率
- 消息队列积压情况
告警规则示例:
code复制groups:
- name: exam.alerts
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1
for: 10m
labels:
severity: critical
annotations:
summary: "High error rate on {{ $labels.instance }}"
6. 踩坑经验分享
-
内存泄漏问题:
初期发现Node.js服务内存持续增长,最终定位到是Vue SSR的缓存策略问题。解决方案:javascript复制// 修改createRenderer配置 const renderer = createRenderer({ cache: new LRU({ max: 1000, maxAge: 1000 * 60 * 15 }) }) -
分布式事务难题:
当用户提交考试时,需要同时更新成绩、记录日志、发送通知。我们最终采用Saga模式:code复制开始事务 -> 步骤1:保存答卷(可重试) -> 步骤2:计算分数(可补偿) -> 步骤3:发送通知(可跳过) 结束事务 -
移动端适配陷阱:
- iOS的Safari对WebSocket支持不稳定,需要降级到长轮询
- 部分安卓机型会杀死后台Tab页,需添加Page Visibility API检测
这套系统目前已在3家教育机构和5家企业稳定运行2年,最高支撑过单场5万人同时在线考试。技术栈的选择经过充分验证,特别是PostgreSQL的JSONB类型极大简化了考试结果的存储和查询。对于想要自建考试系统的团队,建议先从核心的组卷和防作弊功能入手,再逐步扩展其他模块。