高并发系统设计:从理论到实践(适合零基础初学者的入门教程)
🌟 开篇:什么是高并发?它为什么重要?

想象一下,你刚刚上线了一个电商网站。第一天只有10个人访问,系统运行得非常好;第二天有1万人同时访问,你的网站就崩溃了。
这就是我们今天要解决的问题——如何让系统在面对“大量用户同时访问”时仍然能正常运行。这种能力,叫做“高并发处理能力”。
为什么学习高并发?
- 大公司(如淘宝、京东、微博)每天都要处理上百万甚至上亿次请求
- 系统不稳定会让你的网站宕机、用户体验差、老板发火 😂
- 掌握高并发技术是成为后端开发高手的必经之路
接下来我们将通过一个简单的实战项目带你了解什么是高并发,以及如何一步步优化系统来应对它。
⚙️ 环境准备:搭建你的开发环境

在开始前,你需要安装以下几个工具:
1. 安装 Node.js(用于快速编写服务器)
- 下载地址:https://nodejs.org
- 安装 LTS 版本即可
验证是否安装成功:
node -v
npm -v
2. 安装 Express(轻量级 Node.js 框架)
npm install express --save
3. 安装压测工具 Artillery(模拟大量用户)
npm install -g artillery
验证是否安装成功:
artillery version
✅ 小提示:如果你是Windows用户,请使用命令行或 PowerShell 运行这些命令
🔍 核心概念:高并发背后的关键词解释

在正式写代码之前,我们需要理解几个关键术语。我们会用最通俗的语言解释它们。
1. 请求(Request)
当你打开一个网页时,浏览器会向服务器发送一个请求,比如:“请把首页给我”。这个动作就是一次请求。
2. 响应(Response)
服务器收到请求后,会把数据返回给你。比如你访问百度,服务器就返回一个页面内容。
3. 并发(Concurrency)
指“有多少人同时在访问服务器”。例如,100个用户同时刷新页面,就有100个并发请求。
4. 吞吐量(Throughput)
单位时间内服务器能处理多少请求。比如每秒处理100个请求。
5. 阻塞与非阻塞
- 阻塞式调用:必须等前面的请求完成才能继续执行下一个。
- 非阻塞式调用:可以并行处理多个请求(Node.js 默认是非阻塞的)
6. 缓存(Cache)
把常用的数据预先保存在内存里,这样用户下次访问就可以直接从缓存中取,不用每次都去数据库查。
🛠 实战项目:从“单线程服务器”开始

我们将从一个非常简单的 Node.js 应用开始,然后逐步优化它,让它能够承受更大的并发压力。
第一步:创建一个最基础的服务
新建文件 server.js 内容如下:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
console.log("有人访问了首页");
res.send("欢迎来到高并发世界!");
});
app.listen(3000, () => {
console.log("服务启动于 http://localhost:3000");
});
运行服务:
node server.js
访问 http://localhost:3000 看到“欢迎来到高并发世界!”说明服务已启动。
第二步:使用 Artillery 发起并发测试
我们来模拟100个用户同时访问我们的首页。
新建一个压力测试配置文件 load.yaml:
config:
target: "http://localhost:3000"
phases:
- duration: 10
arrivalRate: 100
scenarios:
- flow:
- get:
url: "/"
然后运行压测:
artillery run load.yaml
你会看到输出类似下面的内容:
All virtual users finished
Summary report @ 18:05:00(+0800)
Scenarios launched: 100
Scenarios completed: 100
Requests completed: 100
RPS sent: 9.7
...
这说明我们的服务已经能处理100个并发请求了!是不是很酷?
但是问题来了👇
💥 问题来了:当请求变慢怎么办?
假设我们在首页加了一个耗时操作,比如读取一个大文件或计算斐波那契数列。
修改 server.js 如下:
app.get('/', (req, res) => {
let result = 0;
for (let i = 0; i < 1e8; i++) { // 模拟耗时操作
result += i;
}
console.log("有人访问了首页");
res.send(`结果是:${result}`);
});
再次用 Artillery 测试,你会发现响应时间变得非常慢,甚至有些请求超时了。
原因分析:
Node.js 是单线程的,默认情况下每次请求都会排队处理,如果其中一个请求很慢,其他请求就得等。
🚀 解决方案一:使用异步非阻塞代码
我们可以把“耗时任务”放到另一个线程中去做,避免卡住主进程。
安装多线程库 worker_threads:
npm install worker_threads
修改 server.js:
const express = require('express');
const { Worker } = require('worker_threads');
const app = express();
function runTask() {
return new Promise((resolve, reject) => {
const worker = new Worker('./taskWorker.js');
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`));
});
});
}

app.get('/', async (req, res) => {
const result = await runTask();
res.send(`计算结果是:${result}`);
});
app.listen(3000, () => {
console.log("服务运行在 http://localhost:3000");
});
创建一个新的文件 taskWorker.js,用来执行耗时任务:
const { parentPort } = require('worker_threads');
let result = 0;
for (let i = 0; i < 1e8; i++) {
result += i;
}
parentPort.postMessage(result);
现在再运行 Artillery 测试:
node server.js
artillery run load.yaml
你会发现虽然每个请求本身还是慢,但不会互相阻塞了!
☁️ 解决方案二:引入缓存减少重复计算
刚才的例子中,我们反复做同样的计算。其实很多业务场景也是一样的,比如查热门商品信息。
我们可以用 Redis 来缓存这些重复结果。
安装 Redis 和 Redis 客户端
npm install redis
修改 server.js 加入缓存逻辑:
const express = require('express');
const { Worker } = require('worker_threads');
const redis = require('redis');
const app = express();
const client = redis.createClient();
client.on('error', (err) => {
console.log("Redis Error:", err);
});
function runTask() {
return new Promise((resolve, reject) => {
const worker = new Worker('./taskWorker.js');
worker.on('message', resolve);
worker.on('error', reject);
});
}
app.get('/', async (req, res) => {
const cacheKey = 'fibonacci_result';
client.get(cacheKey, async (err, data) => {
if (data) {
res.send(`从缓存获取结果: ${data}`);
} else {
const result = await runTask();
client.setex(cacheKey, 10, result); // 缓存10秒
res.send(`新计算结果: ${result}`);
}
});
});
app.listen(3000, () => {
console.log("服务运行在 http://localhost:3000");
});
现在再来测试一下,你会发现第一次请求慢,后面的都快了!
🌐 解决方案三:使用 Nginx 做负载均衡(可选进阶)
如果你部署多个 Node.js 实例,可以通过 Nginx 将请求分发到不同的实例上。
示意图如下:
[客户端] ——> [Nginx 负载均衡器] ——> [Node.js 实例1]
\
\——> [Node.js 实例2]
安装 Nginx(以 Ubuntu 为例):
sudo apt update
sudo apt install nginx
配置 /etc/nginx/conf.d/load-balancer.conf:
upstream mynodes {
least_conn;
server localhost:3000;
server localhost:3001;
}
server {
listen 80;
location / {
proxy_pass http://mynodes;
}
}
启动两个 Node.js 实例:
node server.js # 端口3000
node server.js --port 3001 # 修改代码监听3001端口
重启 Nginx:
sudo systemctl restart nginx
现在你可以通过 curl http://localhost 来测试负载均衡效果了。
❓新手常见问题解答
Q1:高并发和高性能有什么区别?
| 对比项 | 高并发 | 高性能 |
|---|---|---|
| 关注点 | 同时处理多少请求 | 单个请求处理有多快 |
| 举例 | 支持1000人同时访问 | 页面加载时间<1s |
Q2:CPU密集型任务怎么处理更好?
- 使用子线程处理(如 worker_threads)
- 或者使用像 Go、Java 这类更适合多线程的语言
- 把计算密集的任务移到后端服务中执行
Q3:缓存失效了怎么办?
- 设置过期时间(TTL)
- 使用缓存预热策略
- 设置降级机制(比如缓存未命中时再去查询数据库)
🎯 学习建议:下一步该学什么?
恭喜你完成了第一个高并发项目的搭建和优化!
接下来你可以继续深入学习以下方向:
✅ 建议路线图:
- 学习更专业的架构模式:如微服务、分布式系统
- 学习使用消息队列(如 Kafka/RabbitMQ)
- 学习数据库优化(索引、分库分表)
- 学习服务注册与发现(Consul、Zookeeper)
- 掌握容器化部署(Docker + Kubernetes)
📚 总结
今天我们从零开始,实现了一个简单但具备初步高并发能力的 Web 服务。主要内容包括:
| 步骤 | 学习内容 | 工具/技术 |
|---|---|---|
| 第一步 | 搭建基础服务 | Express |
| 第二步 | 模拟并发请求 | Artillery |
| 第三步 | 异步处理任务 | worker_threads |
| 第四步 | 引入缓存机制 | Redis |
| 第五步 | 分布式部署 | Nginx |
通过这篇文章的学习,你应该对“高并发系统设计”已经有了感性认识,并且能够动手写出自己的并发服务。
如果你觉得这篇教程对你有帮助,欢迎点赞、分享给更多想入门的同学!我们下期再见 👋
📌 附录:完整代码下载地址
GitHub 示例仓库链接:https://github.com/example/high-concurrency-demo(虚拟链接供示意)
📌 推荐资源
- 《Node.js 高并发编程》
- B站视频合集:高并发系统从入门到实战
- 极客时间专栏:高并发系统核心知识地图

评论 0