一次集中普查刚开场十几分钟,提交按钮就开始转圈,后台数据库的连接数顶满,写入排队、报告页也跟着变慢——这几乎是所有把答卷全压在一个 MySQL 实例上的系统都会遇到的场面。平时几十上百人零散作答毫无压力,可一旦几千人被通知在同一节课、同一个通知窗口里集中提交,读和写就会在同一个库上互相抢资源。
单库能扛住日常,是因为日常的写入是稀疏的。集中普查把这种稀疏彻底打破:短时间内大量 INSERT 涌入答题明细表,同时管理员还在刷新完成率、教师在看班级进度、个别报告在实时生成。写请求要拿锁、要刷盘,读请求要扫描聚合,两边都盯着同一批磁盘和同一个连接池,谁也快不起来。这时候盲目往上加配置,多半只是把崩溃点往后挪一点,并没有解决读写互相踩踏的根子。
先把读和写分开
最该动手的不是加机器,而是把读写分离。答卷提交属于写,完成率统计、报告查询、进度看板属于读。让写走主库、读走只读从库,高峰期占比最大的那批统计和查询就不再和提交抢主库资源。从库有一点复制延迟,对“完成率晚几秒更新”这种场景完全可以接受,对答卷本身的写入安全则没有影响。
橙星云在设计这类高并发场景时,就把作答写入和后台统计放在不同的读写路径上,让一次集中普查的提交不至于被后台的报表查询拖垮。
把峰值削平,而不是硬顶
读写分离解决了互相干扰,但集中提交的写入峰值本身还在。这里的关键是别让每一次提交都同步做完所有事。一份答卷交上来,真正必须马上落库的是原始作答;而计分、生成报告、更新统计,完全可以先进队列,由后台按自己的节奏消化。用户侧只要确认“交卷成功”,不必等报告算完。
这样峰值就从“几千次完整业务处理”降成“几千次轻量写入”,数据库的瞬时压力被摊平到随后的几分钟里。读那一侧也能再减负:完成率、进度看板这类会被反复刷新的聚合数字,用缓存挡在数据库前面,让高峰期成千上万次刷新落到缓存而不是每次都真去查库。
真要再往上走,还可以按机构或按考试批次做分库分表,让不同学校的答卷落在不同的数据分片上,单个实例永远只承担一部分写入。规模没到那一步之前,读写分离加队列削峰通常就够用,不必一上来就把架构做复杂。
单库 MySQL 不是不能用,而是不能让它一个人同时当写入库、查询库和计算库。把读写拆开、用队列削平峰值、热点读加一层缓存、必要时再做水平拆分,这几步走完,同一场集中普查就从“开场就崩”变成“平稳收题”。
