服务端性能优化
问题
服务端性能优化有哪些常见手段?如何定位性能瓶颈?
答案
性能优化全景
常见瓶颈与优化
1. N+1 查询问题
n-plus-one.ts
// ❌ N+1 问题:查询 100 个用户,每个用户再查一次订单 = 101 条 SQL
const users = await db.user.findMany();
for (const user of users) {
user.orders = await db.order.findMany({ where: { userId: user.id } });
}
// ✅ 批量查询:只需 2 条 SQL
const users = await db.user.findMany();
const userIds = users.map(u => u.id);
const orders = await db.order.findMany({ where: { userId: { in: userIds } } });
const orderMap = groupBy(orders, 'userId');
users.forEach(user => { user.orders = orderMap[user.id] || []; });
// ✅ ORM 的 include/eager loading
const users = await prisma.user.findMany({
include: { orders: true },
});
2. 连接池配置
connection-pool.ts
// 数据库连接池
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
database: 'mydb',
connectionLimit: 20, // 最大连接数
waitForConnections: true, // 连接池满时等待
queueLimit: 0, // 排队限制
});
// 连接池大小建议:connections = (CPU 核心数 * 2) + 磁盘数
// 一台 4 核机器:约 10 个连接
3. 异步处理
async-processing.ts
// ❌ 同步处理(接口响应慢)
app.post('/api/orders', async (req, res) => {
const order = await createOrder(req.body);
await sendEmail(order); // 等 500ms
await sendSMS(order); // 等 300ms
await updateInventory(order); // 等 200ms
res.json(order); // 总共 1s+
});
// ✅ 异步处理(接口快速返回)
app.post('/api/orders', async (req, res) => {
const order = await createOrder(req.body);
// 异步任务丢入消息队列
await queue.add('send-email', order);
await queue.add('send-sms', order);
await queue.add('update-inventory', order);
res.json(order); // 快速返回
});
压力测试
# 使用 autocannon (Node.js)
npx autocannon -c 100 -d 30 http://localhost:3000/api/users
# -c 100: 100 个并发连接
# -d 30: 持续 30 秒
# 使用 wrk
wrk -t12 -c400 -d30s http://localhost:3000/api/users
常见面试问题
Q1: 一个接口响应很慢,怎么排查?
答案:
- 查看日志:请求各阶段耗时
- 检查数据库:慢查询日志(EXPLAIN 分析)
- 检查缓存:是否未命中
- 检查网络:服务间调用延迟
- 检查资源:CPU、内存、磁盘 I/O
Q2: 如何应对高并发?
答案:
- 缓存:减少数据库访问
- 异步:非核心逻辑异步处理
- 限流:保护下游服务
- 水平扩展:增加服务实例 + 负载均衡
- 数据库优化:读写分离、索引优化
Q3: QPS 和 TPS 的区别?
答案:
- QPS(Queries Per Second):每秒查询数,衡量读性能
- TPS(Transactions Per Second):每秒事务数,衡量写性能
- 一个 TPS 可能包含多个 QPS
Q4: 如何设置合理的超时时间?
答案:
- 数据库查询:3-5 秒
- 内部服务调用:5-10 秒
- 外部 API 调用:10-30 秒
- 级联超时:上游超时 > 下游超时,避免下游还在跑但上游已经超时返回了