1. 电商高并发场景的技术挑战与选型逻辑
去年双十一期间,我作为核心开发参与了一个峰值QPS超过5万的电商促销系统改造。当秒杀开始时,监控大屏上的曲线像过山车一样直线上升,Nginx日志里瞬间涌现出大量499状态码——这正是典型的高并发场景下系统崩溃的前兆。这次经历让我深刻认识到,在电商领域应对高并发绝非简单的"加机器"就能解决,而是需要从架构设计到技术选型的全链路优化。
为什么选择Spring Boot+Redis+Kafka这个技术栈?Spring Boot提供了快速构建微服务的能力,其自动配置和starter机制让开发人员能专注于业务逻辑;Redis作为内存数据库,单机就能支撑10W+的QPS,是缓解数据库压力的利器;而Kafka的吞吐量可以达到百万级,是异步削峰的最佳选择。这三个技术的组合,恰好形成了高并发场景下的"黄金三角"。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Spring Boot在高并发场景下的实战技巧
2.1 线程池的精细化配置
在application.yml中配置Tomcat参数时,很多开发者会直接使用默认值,这在高并发场景下是致命的:
yaml复制server:
tomcat:
max-threads: 800 # 根据压测结果调整
min-spare-threads: 100
accept-count: 1000 # 等待队列长度
重要提示:不要盲目设置max-threads为1000+,过多的线程会导致CPU频繁上下文切换,反而降低性能。建议通过压测找到最佳值。
2.2 连接池的优化之道
数据库连接池配置是另一个关键点。我们曾经因为HikariCP配置不当导致连接泄漏,最终引发雪崩:
java复制@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(50); // 建议为核心数*2 + 磁盘数
config.setConnectionTimeout(3000); // 超时时间不宜过长
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
return new HikariDataSource(config);
}
}
3. Redis的十八般武艺
3.1 缓存设计模式
在商品详情页场景中,我们采用"缓存+本地缓存"的多级架构:
- 先查本地Caffeine缓存(纳秒级响应)
- 未命中则查询Redis(毫秒级)
- 仍未命中则回源数据库(需防穿透)
java复制public Product getProduct(Long id) {
// 本地缓存查询
Product product = caffeineCache.get(id);
if (product != null) return product;
// Redis查询
String key = "product:" + id;
product = redisTemplate.opsForValue().get(key);
if (product == null) {
// 使用互斥锁防止缓存击穿
String lockKey = "lock:" + key;
if (redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS)) {
try {
product = dbQuery(id);
redisTemplate.opsForValue().set(key, product, 1, TimeUnit.HOURS);
} finally {
redisTemplate.delete(lockKey);
}
} else {
// 等待重试或返回默认值
Thread.sleep(100);
return getProduct(id);
}
}
return product;
}
3.2 分布式锁的陷阱
Redis实现分布式锁时要注意:
- 必须设置过期时间,防止死锁
- 加锁和设置过期时间必须是原子操作
- 释放锁时要验证锁的持有者
- 考虑锁续期问题(Redisson的WatchDog机制)
4. Kafka的消息治理
4.1 生产者调优
在秒杀场景中,我们这样配置Kafka生产者:
java复制@Bean
public ProducerFactory<String, String> producerFactory() {
Map<String, Object> config = new HashMap<>();
config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka1:9092,kafka2:9092");
config.put(ProducerConfig.ACKS_CONFIG, "1"); // 平衡可靠性和性能
config.put(ProducerConfig.RETRIES_CONFIG, 3);
config.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384); // 16KB
config.put(ProducerConfig.LINGER_MS_CONFIG, 10); // 10ms
config.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432); // 32MB
return new DefaultKafkaProducerFactory<>(config);
}
4.2 消费者最佳实践
订单处理消费者组的配置要点:
java复制@KafkaListener(topics = "order.create", groupId = "order-processor")
public void handleOrder(ConsumerRecord<String, String> record) {
try {
Order order = parseOrder(record.value());
// 处理订单
processOrder(order);
} catch (Exception e) {
// 记录异常并发送到死信队列
sendToDLQ(record);
}
}
5. 面试中的高频问题解析
5.1 Redis持久化机制
面试官常问:"RDB和AOF有什么区别?生产环境如何选择?"
- RDB:定时快照,恢复快但可能丢失数据
- AOF:记录每个写操作,更安全但文件较大
- 生产建议:同时开启,AOF每秒同步,RDB每小时备份
5.2 Kafka的ISR机制
"解释下Kafka的ISR列表和HW的作用?"
- ISR(In-Sync Replicas):与Leader保持同步的副本集合
- HW(High Watermark):消费者能读取到的最大偏移量
- 当Follower落后太多会被移出ISR,影响可用性
6. 性能压测与监控体系
6.1 JMeter压测方案
我们设计的压测场景包括:
- 阶梯式增加并发用户(50-100-200...)
- 持续高峰值压力(10分钟以上)
- 突发流量模拟(瞬间增加500%流量)
压测时要监控:
- 平均响应时间(RT)
- 错误率(应<0.1%)
- 系统资源(CPU、内存、IO)
6.2 监控指标看板
Prometheus+Grafana的监控指标包括:
- 应用层:QPS、RT、错误码分布
- 中间件:Redis命中率、Kafka堆积量
- 系统层:CPU使用率、GC次数、线程数
7. 真实案例:秒杀系统设计
去年设计的秒杀系统架构:
- 前端:静态化+CDN+限流(Nginx层)
- 网关:令牌桶限流(每秒5000个令牌)
- 服务层:
- 库存校验:Redis原子递减
- 订单创建:Kafka异步处理
- 数据层:分库分表+读写分离
关键代码片段(库存扣减):
java复制public boolean deductStock(Long itemId, int num) {
String key = "seckill:stock:" + itemId;
Long value = redisTemplate.opsForValue().decrement(key, num);
if (value != null && value >= 0) {
// 异步更新数据库
kafkaTemplate.send("stock.update", new StockMessage(itemId, num));
return true;
} else {
// 回滚
redisTemplate.opsForValue().increment(key, num);
return false;
}
}
8. 避坑指南:那些年踩过的坑
-
缓存雪崩:某次大促,Redis集群同时过期大量key,导致数据库被打垮
- 解决方案:过期时间加随机值
-
消息堆积:Kafka消费者处理太慢,堆积百万消息
- 解决方案:增加消费者实例,优化处理逻辑
-
线程阻塞:一个同步Redis调用阻塞了整个Tomcat线程池
- 解决方案:改用异步非阻塞客户端(Lettuce)
-
GC问题:频繁Full GC导致服务不可用
- 解决方案:调整JVM参数,-Xmx和-Xms保持一致
9. 技术演进:从单体到云原生
当前架构正在向云原生演进:
- 容器化:Docker+K8s部署
- 服务网格:Istio实现细粒度流量控制
- 可观测性:OpenTelemetry全链路追踪
- Serverless:部分场景使用函数计算
10. 面试实战:如何回答系统设计题
当面试官问:"设计一个支持百万并发的电商系统?"
建议回答框架:
- 需求澄清(峰值QPS、一致性要求等)
- 架构设计(分层、组件选型)
- 关键问题解决方案(库存超卖、消息顺序等)
- 容灾方案(降级、熔断)
- 监控指标(如何发现瓶颈)
记住:面试官更关注你的思考过程,而不是完美的解决方案。可以坦诚地说:"在实际项目中,我们会通过压测不断优化这个设计..."
