真正能撑住双 11 流量洪峰的,不是某个单一的优化,而是 从前端到数据库的全链路协同设计。当你构建出这样一套体系,面对千万级并发也能做到“系统稳如老狗”,再也不用担心用户抱怨“点了没反应,结果秒没了”。
想象这样一个场景:
- 午夜零点,某款新手机开放抢购;
- 数十万人几乎在同一毫秒同时点击“立即购买”;
- 页面瞬间卡死,支付没反应,库存提示“售罄”;
- 结果大多数人都没有下单成功,却感觉像被“欺骗”。
这就是 高并发秒杀。它不仅仅是卖货的活动,更是对 系统架构、并发处理、用户体验 的极限考验。
秒杀的本质特点包括:
- 瞬时高并发:同时涌入的请求可能超过 10 万;
- 资源极度稀缺:几百件商品要面对几十万的抢购请求;
- 一致性要求高:不能出现超卖、重复下单;
- 用户体验敏感:哪怕页面延迟一秒,都会带来大量投诉。
如果没有任何防护,所有请求直冲数据库,结局可想而知:连接池打满、锁竞争、CPU 飙升、事务阻塞、系统崩溃。
那我们该如何从容应对?本文将通过 7 大策略,结合前后端代码实例,为你完整拆解 Java 高并发秒杀的应对方案。
一、前端优化:第一层拦截
前端虽然无法彻底阻止恶意攻击,但却是最接近用户的一层,可以显著减少无效请求涌入后端。
按钮防连点(防误触)
避免用户因手滑或卡顿多次提交请求。
<template>
<button
:disabled="isDisabled || countdown > 0"
@click="handleClick"
class="seckill-btn"
>
{{ buttonText }}
</button>
</template>
<script>
export default {
data() {
return {
isDisabled: false,
countdown: 0,
maxCountdown: 5
}
},
computed: {
buttonText() {
if (this.countdown > 0) return `请等待${this.countdown}秒`
return this.isDisabled ? '抢购中...' : '立即抢购'
}
},
methods: {
async handleClick() {
if (this.isDisabled || this.countdown > 0) return
this.isDisabled = true
try {
const result = await this.$api.createOrder()
if (result.success) {
this.$message.success('抢购成功')
} else {
this.startCountdown()
this.$message.error(result.message || '抢购失败')
}
} catch (e) {
this.startCountdown()
this.$message.error('请求异常,请稍后重试')
} finally {
this.isDisabled = false
}
},
startCountdown() {
this.countdown = this.maxCountdown
const timer = setInterval(() => {
this.countdown--
if (this.countdown <= 0) clearInterval(timer)
}, 1000)
}
}
}
</script>
优化点:
- 请求失败后,按钮进入冷却期,避免用户疯狂点击;
- 提供友好的提示,降低用户焦虑感。
请求频率限制(节流)
即使前端无法防住所有脚本攻击,节流 依然是减少无效请求的有效手段。
function throttle(fn, delay) {
let lastCall = 0
return function (...args) {
const now = Date.now()
if (now - lastCall < delay) {
console.warn('操作过于频繁')
return
}
lastCall = now
return fn.apply(this, args)
}
}
const throttledCreateOrder = throttle(createOrder, 500) // 500ms 内最多一次
二、后端核心方案:架构护城河
流量削峰:Redis Streams 缓冲队列
直接把上百万请求打到数据库,必死无疑。我们需要 Redis Streams 来作为缓冲器。
路径:/src/main/java/com/icoderoad/seckill/service/SeckillQueueService.java
package com.icoderoad.seckill.service;
@Slf4j
@Service
public class SeckillQueueService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
private static final String STREAM_KEY = "seckill:requests";
private static final String GROUP = "seckill_group";
private static final String DLQ_KEY = "seckill:dlq";
@PostConstruct
public void initGroup() {
try {
redisTemplate.opsForStream().createGroup(STREAM_KEY, ReadOffset.from("0-0"), GROUP);
} catch (Exception e) {
log.info("消费者组已存在: {}", GROUP);
}
}
/** 入队:防重复提交 + 写入消息队列 */
public boolean enqueue(String userId, String productId) {
String key = "seckill:participated:" + productId;
if (Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, userId))) return false;
Map<String, Object> msg = Map.of(
"userId", userId,
"productId", productId,
"time", System.currentTimeMillis(),
"reqId", UUID.randomUUID().toString()
);
redisTemplate.opsForStream().add(STREAM_KEY, msg);
redisTemplate.opsForSet().add(key, userId);
redisTemplate.expire(key, 10, TimeUnit.MINUTES);
return true;
}
/** 消费请求 */
@Async("seckillExecutor")
public void consume() {
while (true) {
try {
List<MapRecord<String, Object, Object>> records = redisTemplate.opsForStream()
.read(Consumer.from(GROUP, "c-" + Thread.currentThread().getId()),
StreamReadOptions.empty().count(1).block(Duration.ofSeconds(5)),
StreamOffset.create(STREAM_KEY, ReadOffset.lastConsumed()));
if (records == null) continue;
for (MapRecord<String, Object, Object> rec : records) {
Map<Object, Object> body = rec.getValue();
String uid = (String) body.get("userId");
String pid = (String) body.get("productId");
if (process(uid, pid)) {
redisTemplate.opsForStream().acknowledge(STREAM_KEY, GROUP, rec.getId());
} else {
redisTemplate.opsForList().leftPush(DLQ_KEY, body);
}
}
} catch (Exception e) {
log.error("消费异常", e);
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
}
}
}
private boolean process(String uid, String pid) {
if (reduceStock(pid, 1)) {
createOrder(uid, pid);
return true;
}
return false;
}
private boolean reduceStock(String pid, int count) {
// Redis Lua 扣减逻辑
return true;
}
private void createOrder(String uid, String pid) {
log.info("订单创建成功:user={} product={}", uid, pid);
}
}
优化点:
- 使用
DLQ死信队列保存失败请求,便于人工干预; - 异步消费,平滑处理请求;
- 结合 Redis ACK 机制,保证消息可靠。
三、防超卖:Redis + Lua 原子扣减
路径:/src/main/java/com/icoderoad/seckill/service/StockService.java
核心逻辑:检查库存 + 扣减 必须是一个原子操作,否则会导致超卖。
@Service
@Slf4j
public class StockService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
private static final String LUA_SCRIPT =
"local stock = redis.call('get', KEYS[1]) " +
"if not stock then return 0 " +
"elseif tonumber(stock) < tonumber(ARGV[1]) then return 0 " +
"else redis.call('decrby', KEYS[1], ARGV[1]) return 1 end";
public boolean reduceStock(String productId, int qty) {
DefaultRedisScript<Long> script = new DefaultRedisScript<>(LUA_SCRIPT, Long.class);
Long res = redisTemplate.execute(script, List.of("product:stock:" + productId), String.valueOf(qty));
return res != null && res == 1L;
}
public void preloadStock(String productId, int stock) {
redisTemplate.opsForValue().set("product:stock:" + productId, stock);
}
public void syncStockToDB(String productId, int finalStock) {
// 批量写回 MySQL,避免频繁 I/O
log.info("库存同步至DB product={} stock={}", productId, finalStock);
}
}
四、防重复下单:多层幂等控制
- Redis 集合:快速拦截
- 数据库唯一索引:最终保障
- Token 机制:防机器人刷单
- 分布式锁:防止并发写入
这里保留示例代码,优化在于增加日志与统一异常处理。
五、限流与降级:Sentinel
利用 Alibaba Sentinel,针对 QPS、参数热点、异常比例 实现全链路保护。
六、库存回滚:预扣 + 超时释放
防止“下单未支付”造成库存假性减少。
方案:
- 抢购成功后先 预扣库存,写入 Redis,并设置 TTL;
- 超时未支付则自动释放;
- 定时任务兜底扫描。
七、整体防护链路总结
- 前端:按钮防连点、请求节流;
- 网关层:基础限流与防刷;
- 队列层:Redis Streams 削峰填谷;
- 库存层:Redis + Lua 保证原子扣减;
- 订单层:防重复下单(幂等性 + Token + 锁);
- 服务层:Sentinel 限流熔断;
- 善后机制:库存回滚 + 死信队列补偿。
结论
秒杀系统不是一招鲜的技术,而是一套 完整的多层防护方案。
- 前端负责“拦截垃圾流量”;
- 队列与 Redis 负责“削峰与防超卖”;
- 数据库与分布式锁负责“一致性保障”;
- Sentinel 等限流机制提供“兜底保护”。
真正能撑住双 11 流量洪峰的,不是某个单一的优化,而是 从前端到数据库的全链路协同设计。
当你构建出这样一套体系,面对千万级并发也能做到“系统稳如老狗”,再也不用担心用户抱怨“点了没反应,结果秒没了”。
AI大模型学习福利
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
一、全套AGI大模型学习路线
AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取
二、640套AI大模型报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
三、AI大模型经典PDF籍
随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
四、AI大模型商业化落地方案

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量
586

被折叠的 条评论
为什么被折叠?



