当前位置: 首页 > news >正文

12306高并发架构设计:基于区间计数器的网关层拒单方案

引言

在上一篇文章《重新理解12306:它卖的从来不是“库存”,而是“状态”》,我们深入探讨了12306的业务模型核心:它不是简单的库存管理系统,而是基于座位段的状态管理。每个座位被拆分为多个段(例如A-B、B-C、C-D等),售出票时实际是原子性地锁定连续段的使用权。这种模型带来了独特的并发挑战——如何在高并发请求下快速拒绝无效订单,减轻下游系统压力。

假设一列车有1000个座位,同一时刻可能有100万(瞎猜)用户抢票,但最终能成功的只有极少数。如果让所有请求都进入核心下单流程,系统必然崩溃。那么,如何在网关层就识别并拒绝绝大部分无效请求?传统电商的库存计数方案在这里失效了,因为12306的“库存”是动态关联的座位段。

本文将揭示一种高效的架构方案:基于区间计数器的网关层拒单策略。通过这种方案,我们能够将百万并发过滤为可管理的十几万请求,保证系统稳定运行。

核心思路:区间计数器粗粒度过滤

为什么传统库存计数方案不适用?

在传统电商中,我们可以在网关层设置库存计数器:当某商品库存为0时,直接拒绝所有购买请求。但12306的情况截然不同:

  1. 它不是简单减库存,而是需要找到连续座位段并锁定
  2. 同一个座位可以被拆分为多个区段(如A-B、B-C、C-D)售予不同乘客
  3. 不同区间组合(如北京-上海、北京-南京、南京-上海)相互关联且竞争同一座位资源

区间计数器的基本原理

虽然12306的座位段模型复杂,但有一个关键特性:对于任意区间组合(如北京南-上海虹桥),最多可售出的票数不会超过列车总座位数。也就是说,无论有多少种不同的上下车组合,一趟列车的总运力是固定的。

基于这一原理,我们可以为每个区间组合设置一个计数器:

  • 当某个区间组合的请求数达到列车总座位数时,后续请求可直接拒绝
  • 例如:一列车有1000个座位,那么"北京南-上海虹桥"这个区间最多只能有1000个请求通过

计数器数量计算

假设一趟列车有20个站点,那么可能的区间组合数量为:

C(20, 2) = 20 × 19 / 2 = 190

如果列车有1000个座位,那么网关层需要处理的最大请求量为:

190 × 1000 = 171,000

这个数字相比最初的100万并发,已经减少了83%以上!而且这171000请求还可以通过缓存和异步处理进一步消化。

架构设计

整体架构图

用户请求 → 网关层 → Redis计数器 → 消息队列 → 后端服务 → 数据库

详细流程

1. 用户请求到达网关

    • 请求包含车次、起始站、终点站信息
    • 示例:{车次: "G101", 起始站: "北京南", 终点站: "上海虹桥"}

2. 生成区间键

    • 根据请求参数生成唯一键
    • 示例:生成键 "G101:北京南:上海虹桥"

3. 计数器检查

    • Redis计数器值 ≥ 总座位数(如1000),立即拒绝请求,返回“无票”
    • 否则,原子性地递增计数器,并允许请求通过

4. 异步处理

    • 通过的请求被送入消息队列(如Kafka或RabbitMQ)
    • 后端服务异步消费队列,执行实际的座位段锁定和订单创建

5. 计数器校准(可选)

    • 后端处理完成后,根据结果调整计数器
    • 处理失败时递减计数器,避免过度拒绝

关键组件详解

网关层

网关层是整个系统的第一道防线,需要具备极高的性能和可靠性:

  • 选择高性能API网关:如Nginx+OpenResty
  • 实现限流机制:防止单个用户或IP发送过多请求
  • 保持无状态设计:方便水平扩展

Redis计数器存储

Redis作为内存数据库,提供高速的计数器操作:

  • 使用原子操作:保证并发下的数据一致性
  • 设置过期时间:自动清理过期车次的计数器
  • 分片存储:根据车次或区间哈希分布到多个实例,避免热点

消息队列

消息队列起到削峰填谷的作用:

  • 选择高吞吐量消息队列:如Kafka或RabbitMQ
  • 配置多个消费者组:并行处理不同车次的请求
  • 实现死信队列:处理多次失败的消息

后端服务

后端服务负责精确的座位分配:

  • 实现分布式事务:保证座位锁定和订单创建的一致性
  • 设计幂等操作:防止重复处理同一请求
  • 采用批量处理:提高数据库操作效率

 

方案优势

  1. 高效过滤:能在网关层拒绝80%以上的无效请求
  2. 简单可靠:基于Redis的计数器方案易于实现和维护
  3. 可扩展性:通过分片和异步处理,系统可以水平扩展​

总结

12306这类系统的高并发挑战并非无解。关键在于识别出业务模型中“每区间出票存在上限”这一核心特征,并据此在网关层实施区间计数过滤。通过粗粒度的请求控制,将极大部分的无效并发挡在门外,从而为后端复杂事务争取更多的处理资源与时间。

http://www.hskmm.com/?act=detail&tid=12568

相关文章:

  • 各位同学,大家好!我想请大家回忆一段我们在刘集中学的故事,和我单独联系。我想把这些故事写出来保存。欢迎与我分享!谢谢!
  • 实用指南:centos sshd:xxx.xxx.xxx.xxx:allow 如何设置
  • vite7-vue3-os网页os管理|vue3+vite7+arco.design网页pc版webos系统
  • 高并发高吞吐量
  • 服务降级
  • 镜像制作
  • 20231427田泽航第二周预习报告
  • 近期 CF 题不怎么做
  • Day24_【深度学习—广播机制】 - 详解
  • IAR Embedded Workbench中的MCU启动过程分析
  • CSP-S 2025
  • 别样的CSP-S初赛大战(又名:我和油一的那些年)
  • 在ubuntu系统的c语言程序
  • springboot2整合dynamic-datasource-spring-boot-starter多数据源
  • 赛前训练2 extra 思维与构造
  • 详细介绍:基于java的奶茶店管理系统的设计与实现37038-计算机毕设原创(免费领源码+部署教程)
  • 详细介绍:算法题(203):矩阵最小路径和
  • 使用jdbcTemplate查询数据库
  • 线性结构之链表预备知识typedef[基于郝斌课程]
  • Excel滚动表格表头不见了,来回翻动很麻烦,Excel如何固定显示表头?
  • asfp导入framework搭建环境
  • 赛前训练2 连通性问题
  • 用 【C# + WinUI3 + 图像动画】 来理解:高数 - 函数 - 初等函数 - 行人-
  • ansible语句
  • Window 连接 Ubuntu远程桌面
  • 代码随想录算法训练营第四天 |24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II
  • 浅谈根号分治
  • 提高杂题
  • 【比赛记录】2025CSP-S模拟赛51
  • 完整教程:【前端面试题✨】Vue篇(一)