
我们在2025年“618”前夕上线了一套基于香港高性能物理服务器的秒杀系统,前端请求经由Nginx反向代理打入后,通过Kafka异步队列完成削峰处理,理论上已具备抗高并发能力。然而上线第一天,商品秒光却伴随大量用户请求卡顿甚至失败。经过详细排查,发现Kafka虽吞得下,但前端流量短时间内的冲击导致应用线程和Kafka生产者阻塞,依旧出现排队堵塞甚至拒绝连接的问题。我们意识到:Kafka并不等于万能削峰,缺乏入口级限流机制是致命漏洞。
为此,我们紧急调整架构,在原有Kafka异步队列基础上,引入Guava RateLimiter进行请求限速,构建“限流+异步双通道”策略,并结合香港本地服务器低延迟、高并发特性,最终实现系统稳定支撑百万级突发请求。
本文将还原整个技术演进过程,聚焦实战细节。
一、系统架构概览
我们的目标是保障秒杀系统高峰期的稳定性与响应能力。最终落地方案如下:
[客户端] -> [Nginx] -> [应用服务]
|-> Guava RateLimiter 限流(令牌桶)
|-> Kafka 异步消息队列
|-> 秒杀核心逻辑(库存扣减/订单创建)
在香港物理机部署环境如下:
- CPU: Intel Xeon Gold 6338(32C64T)
- 内存: 256GB DDR4 ECC
- 网络: 2×10Gbps Bonding直通交换机
- Kafka部署: 本地SSD阵列部署3节点Kafka集群
- 应用服务: 基于Spring Boot,线程池异步消费Kafka数据
二、问题复盘:Kafka撑得住,应用撑不住
虽然Kafka的吞吐达到了10万TPS以上,但我们仍观察到以下瓶颈:
- 短时间流量爆发,大量请求打入应用层,占满Tomcat线程池;
- Kafka Producer发送压力大,部分请求在阻塞队列中超时丢弃;
- 底层Kafka写入确实没挂,但前端已经失控,用户体验崩盘;
- 没有提前挡流控,Kafka变成“背锅侠”。
结论很明确:Kafka要配合“前置限流”,才能稳住系统节奏。
三、限流组件落地:引入Guava RateLimiter
我们决定在应用层入口处(如Controller级别)增加速率限制逻辑,采用Guava RateLimiter,核心基于令牌桶算法,具备平滑限流效果。
1. 初始化RateLimiter
// 初始化每秒允许处理1000个请求
private static final RateLimiter rateLimiter = RateLimiter.create(1000);
2. 应用限流逻辑
@GetMapping("/seckill")
public ResponseEntity<String> handleSeckillRequest() {
if (!rateLimiter.tryAcquire(10, TimeUnit.MILLISECONDS)) {
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("请求过快");
}
kafkaTemplate.send("seckill_topic", buildSeckillMessage());
return ResponseEntity.ok("排队中");
}
限流逻辑放在Kafka前,只有成功拿到令牌的请求才进入Kafka队列,确保流量不压垮应用线程池。
四、Kafka配置优化:吞吐优先+异步写入
为配合限流后流量的高效吞吐,我们针对Kafka Producer端做了如下配置优化:
spring.kafka.producer:
acks: 1
linger.ms: 5
batch.size: 65536
compression.type: lz4
retries: 3
buffer.memory: 67108864
- acks=1:牺牲部分持久性,换取更高吞吐;
- batch.size/linger.ms:合并写入,提升网络利用率;
- lz4压缩:降低IO负载,适合秒杀业务小消息高频写入;
- retries=3:网络抖动下自动补发,增强可用性。
五、异步消费处理:线程池+幂等性保护
Kafka消息消费端我们也做了异步线程池处理,避免消费速度成为新瓶颈。
@KafkaListener(topics = "seckill_topic", groupId = "consumer_group")
public void handleKafkaMessage(String msg) {
executorService.submit(() -> {
SeckillRequest request = parse(msg);
if (checkStock(request)) {
if (tryPlaceOrder(request)) {
log.info("订单创建成功: {}", request.getUserId());
}
}
});
}
并发消费逻辑中注意两点:
- 幂等性校验:避免重复下单(基于用户+商品ID Redis标记);
- 并发库存扣减:基于Redis Lua原子脚本完成扣减,避免竞态。
六、实测效果:削峰成功,系统稳定
我们使用压测工具模拟10万QPS突发流量,观察如下变化:
| 策略 | 应用平均响应 | Kafka写入TPS | 错误率 |
|---|---|---|---|
| Kafka单通道 | 1.8s | 55,000 | 15% |
| Kafka + 限流 | 0.3s | 10,000 | <1% |
虽然Kafka吞吐下降,但系统响应速度更快,错误率更低,整体体验大幅提升。
七、总结与建议
Kafka确实是削峰利器,但它并不是前线防御系统,必须搭配前置限流机制才能稳住节奏。我们在香港高性能服务器部署环境下,采用Kafka + Guava RateLimiter双通道削峰,有效避免了请求洪峰压垮系统的风险。
实战经验总结如下:
- Kafka只能削峰,不能限流;
- RateLimiter令牌桶方式限速更适合秒杀突发业务;
- 异步消费配合幂等性校验,确保数据一致性;
- 高并发架构要注重“节奏控制”而非盲目抗压。
后续我们也考虑将限流下沉到Nginx或网关层,结合动态配置和灰度发布进一步提升系统弹性。秒杀系统的稳定,归根结底是系统“守恒”的能力,而不是无止境的扩容。











