第十一部分和第十二部分,我们将聚焦于真正具有实战价值的内容——真实场景下的应用实践。前面花了大量篇幅讲解理论基础,现在需要进入实战阶段。在众多高并发场景中,秒杀无疑是最具代表性的典型案例。
第十一部分:高并发实战案例 —— 秒杀系统设计
本章我们将整合此前所有技术要点,从零开始构建一个高并发秒杀系统。假设一个典型场景:共100件商品,同时有10万人参与抢购。核心目标是确保三点:不能出现超卖、不能产生重复订单、系统不能崩溃。

11.1 需求分析
库存总量固定,例如仅有100件商品。
流量呈现洪峰特征,10万用户在同一瞬间涌入系统。
系统必须严格执行三条底线:不超卖、不重复下单、不崩溃。
11.2 核心设计思路
整个架构的核心思想可以概括为:对流量进行分层削峰处理。
首先从流量入口入手:
尽可能将页面静态化,直接部署到CDN上。
客户端应避免集中并发请求,通过随机延时打散请求,防止服务器瞬时压力过大。
在API网关前配置令牌桶限流机制,超速的请求直接拦截。
库存管理是整个系统的关键:
秒杀开始前,预先将库存数据加载至Redis进行预热。
扣减库存必须使用Redis的`DECR`原子操作,只有扣减成功才算有效,否则直接返回失败。
请求处理采用异步化策略:
库存扣减成功后,不要立刻创建数据库订单(否则容易产生死锁),而是将下单请求放入消息队列,向用户返回“排队中,请稍候”的提示。
后端消费者以串行或较小并发度处理消息、创建订单,从而有效避免数据库层面的锁竞争。
防止重复下单同样至关重要:
使用“用户ID+商品ID”作为唯一标识,确保每个用户只能秒杀一次。
最后,必须准备降级方案:
当Redis或消息队列压力过大时,直接返回“活动火爆,请重试”,以保障系统核心稳定性。
11.3 伪代码实现
@RestController
public class SeckillController {
@Autowired
private RedisTemplate redis;
@Autowired
private RocketMQTemplate mq;
@PostMapping("/seckill")
public String seckill(Long userId, Long productId) {
// 1. 限流(使用 Sentinel)
// 2. 校验是否已秒杀过(Redis Set)
Boolean already = redis.opsForSet().isMember("seckill:user:" + productId, userId);
if (Boolean.TRUE.equals(already)) {
return "您已参与过该活动";
}
// 3. 原子扣减库存
Long stock = redis.opsForValue().decrement("seckill:stock:" + productId);
if (stock == null || stock < 0) {
// 库存不足,恢复库存(decrement 后为负,需加回)
redis.opsForValue().increment("seckill:stock:" + productId);
return "已抢光";
}
// 4. 记录用户参与(避免重复扣减)
redis.opsForSet().add("seckill:user:" + productId, userId);
// 5. 发送消息异步创建订单
SeckillOrderMsg msg = new SeckillOrderMsg(userId, productId);
mq.syncSend("seckill_order_topic", msg);
return "排队中,请稍后查询结果";
}
}
@RocketMQMessageListener(topic = "seckill_order_topic", consumerGroup = "order-group")
public class OrderConsumer implements RocketMQListener {
@Autowired
private OrderService orderService;
@Override
public void onMessage(SeckillOrderMsg msg) {
// 幂等:使用唯一键约束(userId + productId)
orderService.createSeckillOrder(msg.getUserId(), msg.getProductId());
}
}
11.4 数据库设计
CREATE TABLE `seckill_order` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`product_id` bigint NOT NULL,
`status` tinyint DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_product` (`user_id`,`product_id`) -- 防重
);
至此,秒杀系统设计完成并上线运行。然而,分布式系统中故障是常态而非异常,因此最后一部分将重点介绍当出现问题时,如何快速定位根因。
第十二部分:高并发系统的可观测性 —— 监控、追踪、日志
分布式系统出现故障就像在黑箱中排查问题,必须借助工具才能看清全貌。这离不开可观测性的三大支柱:指标(Metrics)、链路追踪(Tracing)、日志(Logging)。
12.1 指标监控(Prometheus + Grafana)
每个微服务都需要暴露`/metrics`端点,由Prometheus定期拉取数据,存储为时序数据,最后通过Grafana将图表可视化展示。
重点监控的核心指标包括:QPS、延迟(特别是P99)、错误率、CPU/内存/GC情况、线程池活跃数、消息队列积压量。这些数据能够反映系统的健康状况。
12.2 分布式链路追踪(SkyWalking、Jaeger)
一个请求在多个微服务间流转,如何追踪它经过的具体服务、每步耗时、失败点在哪里?这就要依赖链路追踪技术。其核心是为每个请求生成全局唯一的Trace ID,并记录经过的每一个Span。
集成Spring Cloud Sleuth非常简便:
spring:
zipkin:
base-url: https://zipkin:9411
sleuth:
sampler:
probability: 1.0 # 采样率
配置完成后,日志中会自动注入Trace ID。后续查询日志时,只需搜索该ID,即可串联起请求的完整路径,极大提升排查效率。
12.3 日志收集(ELK Stack)
日志是最终的分析素材。使用Filebeat采集日志,Logstash进行过滤,Elasticsearch负责存储和搜索,Kibana提供可视化界面。
告警方面,可基于Prometheus的Alertmanager或Kibana的Watcher。一旦错误率飙升或消息队列积压超过阈值,自动发送钉钉或邮件通知,确保值班人员第一时间响应。
