场景特点

选课系统是典型的高并发写入场景,它的负载形态相当极端:

  • 瞬时并发极高:选课通道在固定时点开放,大量学生在几秒内同时发起请求,峰值 QPS 与平均水位相差悬殊;
  • 强竞争:热门课程名额有限,大量请求在同一时刻争抢同一行数据;
  • 正确性要求刚性:名额不能超卖,课程容量是硬约束;
  • 不允许重复:同一学生不能重复选中同一门课,也不能出现时间冲突;
  • 结果需即时可见:学生提交后需要立刻知道是否成功,不能异步返回。

「高并发」与「强正确性」同时出现,是这个场景的核心矛盾。

超卖防控

名额超卖是选课系统最严重的事故。防控的基本手段是在数据库层面保证条件的原子性:

  1. 条件更新:把判断与扣减合并成一条语句,例如「已选人数小于容量时才允许增加并返回影响行数」,通过影响行数判断是否成功;
  2. 唯一约束兜底:为「学生 + 课程」建立唯一约束,从数据库层面杜绝重复选中;
  3. 显式事务包裹:扣减名额与写入选课记录必须在同一事务内,避免部分成功;
  4. 失败快速返回:条件不满足时直接返回失败,不做多余的等待与重试。
需要注意的是:分布式数据库中显式加锁的代价较高,容易造成大量请求排队。使用条件更新把判断与写合并,通常比「先查再锁再审」的方式更高效。

热点行的处理

热门课程的名额行会成为整个系统最热的数据。所有请求都更新同一行,写入无法并行,这是物理上的限制。常见缓解思路:

  • 前置过滤:在应用层或缓存层先做资格校验(是否已选、时间是否冲突),把明显无效的请求挡在数据库之外;
  • 名额分桶:把名额拆成若干份分别扣减,降低单行竞争,最终汇总校验;
  • 排队削峰:请求先进入队列,按可控速率消费,把瞬时洪峰摊平到一段时间内;
  • 分批开放:按年级、按学院分时段开放选课,从源头降低同时竞争的人数;
  • 限制单用户并发:同一学生的重复提交应被幂等处理,避免一人占用多个请求名额。

短事务与幂等设计

在极端并发下,事务持续时间直接决定系统的吞吐能力:

  1. 事务内只做必要操作:资格校验、缓存查询、消息通知都不应放在事务内;
  2. 避免远程调用:事务中调用外部服务会显著拉长持锁时间,是并发场景的大忌;
  3. 幂等处理:学生重复点击或网络重试时,应通过唯一约束或请求标识保证同一请求只生效一次;
  4. 重试要有退避:失败重试若不带退避,会在高峰时加剧冲突,形成雪崩。

可观测与容量准备

  • 提前压测:按预期峰值并发的 1.5 倍做压测,确认瓶颈位置;
  • 监控关键指标:连接数、活跃事务数、锁等待、慢查询数量,这些指标通常先于业务失败暴露问题;
  • 关注延迟分位:平均值在突发场景下几乎没有参考价值,P99 与 P999 才是真实体验;
  • 准备降级方案:极端情况下可关闭非核心功能(如课程评价、推荐),把资源集中到选课主链路;
  • 容量弹性:计算层可在选课开放前临时扩容,结束后回收,兼顾成本与稳定。

经验小结

选课系统的技术要点可以浓缩为一句话:用数据库的原子性保证正确,用排队与分桶缓解热点,用短事务与幂等提升吞吐。正确性绝不能靠应用层的判断逻辑兜底,因为在高并发下「先查后写」之间的时间窗口足以造成超卖。把正确性下沉到数据库约束,系统才有可靠的底线。

案例要点速览
行业场景高校选课与成绩系统,开放瞬间并发极高且名额不可超卖
核心矛盾瞬时高并发与强正确性要求同时存在
超卖防控条件更新合并判断与扣减、唯一约束防重复、名额扣减与选课记录同事务
热点缓解前置过滤无效请求、名额分桶、排队削峰、分批开放、限制单用户并发
吞吐保障事务内只做必要操作、避免远程调用、幂等处理与带退避的重试