高并发系统设计:新手也能看懂的实战指南
大家好,我是掘金上常写入门教程的全栈工程师。最近不少刚入行的朋友私信问我:“高并发到底是什么?我学 Java 三个月,简历上写‘了解高并发’真的能过面试吗?”说实话,我当初学的时候也一脸懵——什么叫“扛住百万请求”?数据库崩了怎么办?缓存怎么用才不翻车?
今天这篇教程,就是为零基础但想真正搞懂高并发的同学写的。我会从最朴素的问题出发,用 Java 做工具,一步步带你搭一个能“撑住压力”的小系统。不讲虚的,全是能跑的代码和可落地的思路。无论你是准备求职、做课程设计,还是想提升产品技术视野,这篇文章都能帮你打下扎实的地基。
一、高并发不是玄学,而是“人多时别卡死”
简单说,高并发系统就是当大量用户同时访问你的服务时,系统依然能快速响应、不崩溃、数据不错乱。
举个例子:
- 你做的电商产品,双11有10万人同时抢购;
- 你开发的社交App,热门帖子被瞬间转发万次;
- 你参与的求职平台,毕业季千人同时投递简历。
如果系统没做好高并发设计,用户就会看到“502 Bad Gateway”、“加载超时”、“库存变成负数”……这种体验,产品口碑直接崩盘。
所以,高并发不是“高级工程师才碰的东西”,而是每个开发者迟早要面对的现实问题。
二、环境准备:5分钟搭好开发环境
我们用最主流的 Java 技术栈来实践。你需要:
| 工具 | 版本建议 | 作用 |
|---|---|---|
| JDK | 17+ | Java 运行环境 |
| Maven | 3.8+ | 项目依赖管理 |
| Redis | 7.x | 缓存中间件 |
| MySQL | 8.0+ | 数据库 |
| IntelliJ IDEA | 最新版 | 开发 IDE |
安装步骤(Mac/Linux/Windows 通用)
安装 JDK 17
# Mac (用 Homebrew) brew install openjdk@17 # Windows: 去 Oracle 官网下载安装包启动 Redis(用 Docker 最快)
docker run -d --name redis -p 6379:6埠 redis:7创建 MySQL 表
CREATE DATABASE high_concurrency; USE high_concurrency; CREATE TABLE product ( id INT PRIMARY KEY, name VARCHAR(100), stock INT NOT NULL ); INSERT INTO product VALUES (1, '秒杀手机', 100);新建 Maven 项目
pom.xml中加入核心依赖:<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> </dependencies>
💡 提示:如果你还没学 Spring Boot,别慌!我们只用它简化配置,核心逻辑全是原生 Java 思维。
三、三大核心概念:缓存、限流、队列
高并发系统的骨架,就靠这三根支柱撑起来。
1. 缓存(Cache):别老去查数据库
问题:每次用户查商品库存,都去 MySQL 查一次?10万次请求 = 10万次磁盘 IO,数据库直接累趴。
解法:把热点数据放内存(比如 Redis),读取速度提升 100 倍。
// 伪代码:先查缓存,没有再查 DB
public int getProductStock(int productId) {
String cacheKey = "stock:" + productId;
String cached = redis.get(cacheKey);
if (cached != null) {
return Integer.parseInt(cached);
}
// 缓存未命中,查数据库
int stock = database.queryStock(productId);
redis.setex(cacheKey, 60, String.valueOf(stock)); // 缓存60秒
return stock;
}
✅ 新手避坑:缓存和数据库的一致性怎么保证?
简单方案:写操作时先更新 DB,再删除缓存(Cache-Aside 模式)。复杂场景再考虑消息队列同步。
2. 限流(Rate Limiting):拒绝超额请求
问题:系统最多处理 1000 QPS(每秒请求数),但突然涌来 5000 请求,怎么办?
解法:像地铁安检一样,控制进站人数。超过阈值的请求直接拒绝,保护系统不崩。
Java 实现(用 Guava 的令牌桶算法):
import com.google.common.util.concurrent.RateLimiter;
public class OrderService {
// 每秒最多放行 100 个请求
private RateLimiter limiter = RateLimiter.create(100.0);
public String createOrder(int userId, int productId) {
if (!limiter.tryAcquire()) {
return "系统繁忙,请稍后再试";
}
// 执行下单逻辑...
return "下单成功";
}
}
📌 关键点:限流不是“降低用户体验”,而是避免所有人一起失败。宁可让部分人等待,也不能让整个系统瘫痪。
3. 队列(Queue):削峰填谷
问题:秒杀开始瞬间,10万请求砸过来,数据库写不过来。
解法:用消息队列(如 RabbitMQ、Kafka)当“缓冲池”。请求先入队,后端慢慢消费。
流程:
用户请求 → 写入消息队列 → 后台消费者逐个处理 → 更新库存
虽然用户不能“立刻”看到结果,但系统稳了。适合非实时场景(如发短信、日志处理)。
🔍 对比三种策略:
策略 适用场景 用户体验 实现难度 缓存 读多写少 快速响应 ★★☆ 限流 保护系统 可能被拒 ★★ 队列 写压力大 异步延迟 ★★★
四、实战:用 Java 写一个防超卖的秒杀系统
现在,我们整合上面知识,做一个库存不会变负数的秒杀接口。
步骤 1:定义数据模型
@Entity
@Table(name = "product")
public class Product {
@Id
private Integer id;
private String name;
private Integer stock;
// getter/setter 略
}
步骤 2:实现带缓存和限流的下单逻辑
@RestController
public class SeckillController {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private ProductRepository productRepo;
private final RateLimiter limiter = RateLimiter.create(50.0); // 每秒50单
@PostMapping("/seckill/{id}")
public String seckill(@PathVariable Integer id) {
// 1. 限流
if (!limiter.tryAcquire()) {
return "请求太频繁,请稍后再试";
}
// 2. 检查缓存库存
String stockStr = redisTemplate.opsForValue().get("stock:" + id);
int stock = stockStr == null ? -1 : Integer.parseInt(stockStr);
if (stock <= 0) {
return "商品已售罄";
}
// 3. 扣减缓存库存(原子操作!)
Long result = redisTemplate.opsForValue().decrement("stock:" + id);
if (result < 0) {
// 库存不足,回滚
redisTemplate.opsForValue().increment("stock:" + id);
return "手慢了,库存不足";
}
// 4. 异步下单(这里简化,实际应发消息到队列)
asyncCreateOrder(id);
return "秒杀成功!";
}
private void asyncCreateOrder(Integer productId) {
// 模拟异步处理:记录订单、扣真实库存等
new Thread(() -> {
// 注意:真实场景要用线程池,别直接 new Thread!
Product product = productRepo.findById(productId).orElse(null);
if (product != null && product.getStock() > 0) {
product.setStock(product.getStock() - 1);
productRepo.save(product);
}
}).start();
}
}
步骤 3:初始化缓存
应用启动时,把数据库库存同步到 Redis:
@PostConstruct
public void initCache() {
Product product = productRepo.findById(1).orElse(null);
if (product != null) {
redisTemplate.opsForValue().set("stock:1", String.valueOf(product.getStock()));
}
}
💡 为什么用 Redis 扣库存而不是数据库?
- Redis 的
DECR是原子操作,天然防超卖;- 数据库即使加
SELECT FOR UPDATE,在高并发下也会锁表,性能差。
五、新手常踩的 5 个坑 & 解法
“我用了缓存,为什么还是超卖?”
→ 没用原子操作!GET → CHECK → SET不是原子的。必须用DECR或 Lua 脚本。“限流后用户总被拒,体验很差”
→ 调整策略:前端加排队动画,或用“令牌预分配”(如提前发券)。“Redis 挂了,整个系统就崩了?”
→ 设计降级方案:缓存失效时,直接走数据库(加分布式锁),并报警。“简历写‘高并发经验’,面试官问细节答不上”
→ 求职建议:不要堆关键词!说清楚你解决了什么问题(如“用 Redis 原子操作防止超卖,QPS 从 200 提升到 3000”)。“工具太多,不知道学哪个”
→ 初学者聚焦:Redis + Spring Boot + JMeter(压测工具)。其他如 Kafka、Nginx 限流,后续再补。
六、下一步学习路径建议
高并发是个系统工程,别指望一篇教程吃透。我的建议:
短期(1个月内)
- ✅ 动手跑通本文代码,用 JMeter 压测(命令:
jmeter -n -t test.jmx) - ✅ 学透 Redis 5 种数据结构,重点掌握 String、Hash、Lua 脚本
- ✅ 理解数据库事务隔离级别(尤其是“可重复读”如何防幻读)
中期(3个月)
- 🔧 学习 Nginx 限流配置(
limit_req模块) - 🔧 掌握 RabbitMQ/Kafka 基础,实现真正的异步解耦
- 🔧 用分布式锁(Redisson)解决集群环境下的并发问题
长期(求职/晋升)
- 📊 学会监控:Prometheus + Grafana 看 QPS、错误率、延迟
- 🧪 掌握压测方法论:如何模拟真实流量?如何分析瓶颈?
- 💼 结合产品思维:高可用 ≠ 盲目堆技术,要平衡成本、体验、风险
最后的话
我当初第一次做高并发项目时,以为加个 Redis 就万事大吉,结果上线当天库存变成负数,被产品经理追着问……后来才明白:高并发不是某个工具,而是一套系统性思考方式。
希望这篇教程能让你少走弯路。记住:所有复杂的架构,都是从一行正确的代码开始的。
如果你觉得有帮助,欢迎在掘金关注我,我会持续输出“能跑、能懂、能用”的实战教程。下次见!

评论 0