2026年6月22日/ 案例

TicketRush 高并发票务秒杀系统

Java 21 + Spring Boot 3 高并发票务项目,覆盖防超卖、限流、异步削峰、幂等、最终一致性、压测、监控和部署闭环。

项目概览

主线、难点和结果。

负责范围

抢票入口、库存预占、防超卖策略、RocketMQ 异步下单、幂等消费、超时补偿、监控和压测。

核心难点

热点票档下同时处理入口限流、库存一致性、重复请求和异步链路补偿。

验证结果

压测记录保留 Prometheus RPS 828.63/s、HTTP p95 3.1ms;执行器对比中虚拟线程提升 22.55x。

关键流程

主链路怎么跑起来。

下面按顺序记录项目里真正跑通的几个环节。

01

入口治理

限流和准入令牌先保护热点票档

抢票请求先经过 Sentinel 全局/热点票档限流,再用 Redis 准入令牌控制进入库存链路的并发量。

02

库存一致性

三种防超卖策略可以横向对比

Redis Lua、Redis 分布式锁和 MySQL 乐观锁都能跑同一条链路,重点检查初始库存、成功数、失败数、最终库存和重复订单数是否对得上。

03

异步补偿

RocketMQ 下单、幂等消费和超时释放

库存预占成功后异步创建订单;消费者幂等处理重复消息,发送失败或订单超时后释放库存。

04

压测记录

828.63/s RPS、3.1ms p95 和 22.55x 对比

压测数字和环境一起展示:并发、请求量、错误率、Prometheus 指标、执行器对比和系统健康状态要能互相解释。

828.63/s
Prometheus RPS
3.1ms
HTTP p95
22.55x
Virtual Threads

运行画面

运行画面

核心链路演示:库存预加载、抢票请求、幂等返回和指标变化。
TicketRush 控制台总览
控制台总览:把库存、订单、压测和系统状态放在同一页观察。
TicketRush 系统健康检查
系统健康页用于检查 Redis、RocketMQ、MySQL 和服务状态。
TicketRush 抢票操作界面
抢票操作页展示票档、请求参数和下单结果。
TicketRush 执行器压测对比
执行器压测页对比不同策略下的吞吐、延迟和执行结果。

问题

秒杀系统的核心在热点票档、高并发和重复请求下处理库存、入口流量、异步补偿和监控指标,并让这些行为可以通过压测和脚本检查。

方案

我把主链路拆成 Sentinel 限流、Redis 准入令牌、Java 21 Virtual Threads 库存预占、Redis Lua / Redis Lock / MySQL 乐观锁三种防超卖策略、RocketMQ 异步下单、消费幂等、订单超时关闭补偿,以及 Prometheus/Grafana 指标闭环。

展示重点

TicketRush 主要记录秒杀系统的后端主链路:库存扣减、重复请求、入口限流、异步下单和监控指标都可以在本地跑起来检查。

1000 -> 999 -> 999
DuplicateCode: A0429
processedByVirtualThread: true

工程讲解

可以先用 smoke 脚本展示库存轨迹和幂等结果,再解释 Redis Lua、分布式锁、MySQL 乐观锁三种策略的差异,最后用压测报告和 Prometheus 指标说明库存、重复请求和入口治理的实际表现。

实现细节

这个项目主链路从抢票入口开始:请求先经过 Sentinel 全局/热点票档限流,再通过 Redis 准入令牌控制进入库存扣减链路的并发量。库存预占在 Java 21 Virtual Threads 中执行,底层可切换 Redis Lua、Redis 分布式锁和 MySQL 乐观锁三种策略,方便做横向压测。

抢票成功后不会同步创建完整订单,而是发布 RocketMQ 消息异步下单;消费者负责幂等创建 PENDING 订单,发送失败或订单超时会触发库存释放。项目还用 k6、Prometheus、Grafana 和 smoke 脚本验证库存轨迹、重复请求、限流比例和 p95 延迟。

验证记录会优先看行为而不是只看组件名:初始库存、并发请求数、成功订单数、失败请求数、最终库存和重复订单数需要能对得上;重复点击、重复消息和消费者重试都应该返回同一个业务结果或保持幂等。

压测结果需要和环境一起读:并发数、请求总量、持续时间、RPS、p95、错误率、CPU、Redis、MySQL 和 RocketMQ 状态要放在同一个语境里。单独写一个吞吐数字没有意义,必须说明它是在什么环境、什么数据量和什么失败率下得到的。

这个项目聚焦后端主链路:防超卖、削峰、幂等、一致性和可观测。库存、订单、消息和指标放在同一条链路里观察。

The main flow starts at the rush-ticket API. Requests pass through Sentinel global and hot-SKU limits, then Redis admission tokens control how many requests enter the inventory reservation path. Reservation runs on Java 21 Virtual Threads and can switch between Redis Lua, Redis Lock and MySQL optimistic locking for benchmark comparison.

A successful reservation does not synchronously create the full order. It publishes a RocketMQ message for async order creation; the consumer creates a PENDING order idempotently, and failed sends or expired orders release reserved inventory. k6, Prometheus, Grafana and smoke scripts validate inventory flow, duplicate requests, throttling ratio and p95 latency.

The validation notes focus on behavior, not component names: initial inventory, concurrent requests, successful orders, failed requests, final inventory and duplicate order count should line up. Duplicate clicks, duplicate messages and consumer retries should return the same business result or remain idempotent.

Benchmark results need their environment: concurrency, total requests, duration, RPS, p95, error rate, CPU, Redis, MySQL and RocketMQ status should be read together. A standalone throughput number is weak unless it explains the environment, data size and failure rate behind it.

I position this as a backend engineering showcase focused on oversell prevention, peak shaving, idempotency, consistency and observability, with inventory, orders, messaging and metrics read as one path.

复盘

高并发项目不能只讲架构图,最好把库存轨迹、重复请求、限流结果、压测报告和监控指标放在一起说明。
Redis Lua 更适合热点库存的原子扣减,但仍需要入口限流、准入令牌、消费幂等和超时补偿配合。
Virtual Threads 更适合 IO 密集环节,能改善线程模型和吞吐表现,但不能替代库存一致性和压测验证。