可以。Redis + Node.js 支撑百万级并发,核心不是"Redis 能不能扛百万",而是把请求链路做成无状态、异步化、缓存化,并把单机瓶颈拆到多个实例。
一个典型架构可以是:
less
┌──────────────┐
│ CDN / WAF │
└──────┬───────┘
│
┌──────▼───────┐
│ Load Balancer│
└──────┬───────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
Node.js #1 Node.js #2 Node.js #N
stateless stateless stateless
│ │ │
└────────────────┼────────────────┘
│
┌──────────▼──────────┐
│ Redis Cluster │
│ Shard 1 ... Shard N│
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ MySQL / PostgreSQL │
│ Read Replica / Shard│
└─────────────────────┘
1. Node.js:不要让单进程成为瓶颈
Node.js 本身适合大量 I/O 并发,但单个 Node 进程不能简单理解成能处理百万连接。
通常做法:
markdown
百万客户端连接
↓
Load Balancer
↓
100 × Node.js instances
↓
Redis Cluster
例如:
ini
import http from 'node:http';
const server = http.createServer(async (req, res) => {
const data = await redis.get(`user:${req.userId}`);
res.end(data ?? '{}');
});
server.listen(3000);
然后通过 Kubernetes / Docker / PM2 / ECS 等横向扩容。
关键原则:
- Node 服务无状态
- 不在进程内保存用户 Session
- 不依赖本地内存作为唯一数据源
- 不做同步 CPU 密集型任务
- 长任务放 MQ / Worker
- 使用连接池
- Keep-Alive
- 合理设置超时
- 做好 graceful shutdown
2. Redis:单机 Redis ≠ 百万级架构
这是最容易踩坑的地方。
如果你说:
"我启动一个 Redis,然后 Node.js 连接它,能不能百万并发?"
通常答案是:不能直接这么设计。
应该考虑:
markdown
Redis Cluster
┌────────┬────────┬────────┐
│Shard 1 │Shard 2 │Shard 3 │
│Master │Master │Master │
└───┬────┴───┬────┴───┬────┘
│ │ │
Replica Replica Replica
Redis Cluster 根据 key 做分片:
makefile
user:10001 → Shard 1
user:10002 → Shard 2
user:10003 → Shard 3
...
这样才能把:
100 万 QPS
拆成:
Shard 1 → 20 万
Shard 2 → 20 万
Shard 3 → 20 万
Shard 4 → 20 万
Shard 5 → 20 万
具体数字当然需要根据机器 CPU、内存、value 大小、命令类型和网络情况压测,不能简单按节点数线性估算。
3. Node → Redis 不要创建大量连接
一个非常重要的误区:
100 万用户
=
100 万 Redis TCP 连接
完全不是这么回事。
应该是:
markdown
100 万客户端
↓
几百/几千个 Node 实例
↓
每个 Node 使用 Redis connection pool
↓
Redis Cluster
例如单个 Node 实例可能维持有限数量的 Redis 连接,而不是每个用户创建一个连接。
4. 缓存设计比 Redis 本身更重要
例如用户请求:
sql
GET /api/user/10086
不要每次:
Node
↓
MySQL
↓
返回
而是:
sql
Node
↓
Redis GET
↓
命中
↓
返回
代码类似:
vbnet
const key = `user:${userId}`;
let user = await redis.get(key);
if (!user) {
user = await db.query(
'SELECT * FROM users WHERE id = ?',
[userId]
);
await redis.set(
key,
JSON.stringify(user),
{ EX: 300 }
);
}
return JSON.parse(user);
如果数据库平均只能承受:
20,000 QPS
但 Redis 可以承受远高于这个数量级的请求,那么大量读请求就不会直接打到数据库。
5. 最危险的问题:缓存击穿
假设:
makefile
user:10086
突然过期。
然后同时来了:
100,000 requests
结果:
markdown
100,000 Node requests
↓
Redis MISS
↓
100,000 requests 查询 MySQL
数据库直接被打爆。
这就是缓存击穿。
可以使用:
Single Flight / 分布式锁
markdown
Redis MISS
│
┌─────────┴─────────┐
│ │
请求 1 获取锁 请求 2~N
│ │
▼ │
查询 DB │
│ │
▼ │
写 Redis │
│ │
└──────────┬────────┘
▼
返回数据
例如:
vbnet
const lockKey = `lock:${key}`;
const locked = await redis.set(
lockKey,
'1',
{ NX: true, EX: 5 }
);
if (locked) {
try {
const data = await loadFromDB();
await redis.set(key, JSON.stringify(data), { EX: 300 });
} finally {
await redis.del(lockKey);
}
}
生产环境还要考虑锁 token、续期、异常释放等问题,不能简单把 SET NX 当成完整分布式锁方案。
6. 缓存雪崩也必须处理
假设你有:
perl
1,000,000 keys
全部:
ini
TTL = 300
如果大量 key 在同一时间过期:
erlang
Redis
↓
大量 MISS
↓
DB
↓
DB CPU 100%
↓
服务雪崩
不要:
ini
EX = 300
全部固定。
可以加入随机 TTL:
javascript
const ttl = 300 + Math.floor(Math.random() * 60);
await redis.set(
key,
JSON.stringify(data),
{ EX: ttl }
);
让过期时间分散。
7. 热点 Key 是百万并发架构里的大坑
例如:
ini
商品 ID = 10086
突然:
500,000 QPS
全部访问:
makefile
product:10086
即使 Redis Cluster 有 20 个 shard:
bash
product:10086
↓
同一个 hash slot
↓
同一个 Redis shard
这叫热点 Key。
可以考虑:
makefile
product:10086:1
product:10086:2
product:10086:3
...
product:10086:N
或者在 Node 本地做极短时间的 L1 Cache:
vbscript
Request
↓
Node L1 Cache
↓ miss
Redis
↓ miss
DB
例如:
L1:几十毫秒~几秒
L2:Redis
L3:DB
对于极热、变化不频繁的数据非常有效。
8. 写请求不要全部同步打数据库
假设用户行为:
bash
POST /api/like
100 万并发下,如果每个请求都:
sql
Node
↓
MySQL UPDATE
↓
等待
↓
Response
数据库很容易成为瓶颈。
可以变成:
arduino
Client
↓
Node
↓
Redis
↓
MQ
↓
Worker
↓
MySQL
例如:
arduino
点赞
↓
Redis INCR
↓
Kafka / Redis Stream
↓
Worker 批量处理
↓
MySQL
于是 Web 请求不需要等待数据库事务完成。
9. Redis 不应该承担所有事情
比较合理的职责:
| 数据 | 推荐 |
|---|---|
| Session | Redis |
| 登录 Token | Redis |
| 热点数据 | Redis |
| 排行榜 | Redis |
| Rate Limit | Redis |
| 分布式锁 | Redis |
| Pub/Sub | Redis |
| 持久业务数据 | MySQL/PostgreSQL |
| 大文件 | OSS/S3 |
| 日志 | Kafka/Log system |
| 大规模异步任务 | Kafka/RabbitMQ 等 |
尤其不要把 Redis 当成:
"天下无敌的数据库"
Redis 的内存成本很高,而且很多业务数据仍然需要关系数据库提供事务、复杂查询和持久化能力。
10. 限流是百万并发的必需品
百万并发并不意味着:
所有请求都应该进入业务系统。
例如 API:
bash
/api/login
/api/order
/api/payment
必须限流。
Redis 可以实现 Token Bucket / Sliding Window:
sql
User
↓
Rate Limiter
↓
Redis
↓
允许 → Node
拒绝 → 429
例如:
bash
IP:100 req/s
User:50 req/s
API:10,000 req/s
Global:1,000,000 req/s
不同维度分别控制。
11. Node.js 还要特别注意事件循环
下面这种代码:
ini
app.get('/api/data', (req, res) => {
const result = heavyCalculation();
res.json(result);
});
如果:
scss
heavyCalculation()
耗时 500ms,并且占满 CPU,那么一个 Node 进程的事件循环会被阻塞。
结果:
vbscript
Request 1 ──┐
Request 2 ──┤
Request 3 ──┼── Event Loop 被卡住
Request 4 ──┤
Request 5 ──┘
所以 CPU 密集型任务应该考虑:
Node
↓
Worker Threads / Job Queue
↓
Worker
或者直接拆成独立 Worker 服务。
12. 一个比较完整的百万并发架构
如果让我设计一个典型的:
Node.js + Redis + MySQL 百万级并发系统
我会考虑:
less
Internet
│
┌──────▼──────┐
│ CDN / WAF │
└──────┬──────┘
│
┌──────▼──────┐
│ LoadBalancer│
└──────┬──────┘
│
┌─────────────────┼─────────────────┐
│ │ │
Node #1 Node #2 Node #N
│ │ │
└─────────────────┼─────────────────┘
│
┌─────────▼─────────┐
│ Redis Cluster │
│ │
│ Shard 1 │
│ Shard 2 │
│ Shard 3 │
│ ... │
└─────────┬─────────┘
│
┌──────────┴──────────┐
│ │
▼ ▼
Message Queue MySQL
│ Read Replicas
▼
Workers
再配:
diff
CDN
+
WAF
+
Load Balancer
+
Node.js Cluster
+
Redis Cluster
+
MQ
+
MySQL Read Replica
+
Monitoring
+
Rate Limiting
+
Circuit Breaker
+
Autoscaling
13. 真正需要计算的是这几个数字
"百万并发"本身其实不是一个完整的性能指标。
必须区分:
100 万 TCP/WebSocket 长连接
和:
100 万 RPS
完全是两个问题。
例如:
场景 A
1,000,000 长连接
10,000 RPS
Node.js 非常适合。
场景 B
sql
1,000,000 RPS
每次请求 Redis GET
重点变成:
vbnet
Redis Cluster
网络
Node 实例数量
请求大小
命令类型
热点 Key
场景 C
1,000,000 RPS
每次请求都查询 MySQL
这时候 Redis 也救不了你。
最后给你一个实际落地思路
如果你是准备做真正的百万级并发项目,不要一上来就堆几十台服务器。
建议按这个顺序:
markdown
① Node.js 单实例压测
↓
② Redis 单实例压测
↓
③ Node × N 横向扩容
↓
④ Redis Cluster
↓
⑤ 缓存击穿/雪崩/热点 Key
↓
⑥ DB 读写分离
↓
⑦ MQ 异步化
↓
⑧ 限流 + 熔断 + 降级
↓
⑨ 全链路监控
↓
⑩ 压测到目标 QPS
千万不要用"百万并发"直接反推机器数量。 应该先定义目标,例如:
erlang
并发连接:1,000,000
目标 QPS:200,000
P99:< 100ms
Redis 命中率:> 95%
单请求平均响应:20ms
可用性:99.99%
然后根据压测结果倒推 Node、Redis、数据库和网络规模。
如果你愿意,我也可以进一步给你一套**"Node.js + Redis Cluster + MySQL 实现 100 万并发"的生产级项目架构**,包括 Docker/K8s、Redis Cluster、Node.js 代码、限流、缓存击穿、MQ、数据库分库分表以及压测方案。