# 聊聊 API 性能优化:别让你的接口成为公司的瓶颈
> "优化一个小接口,拯救一群人。"
## 引言
你有没有遇到过这种情况:前端同事火急火燎地找你,说某个页面加载慢得像在用 2G 网络,结果一查——后端某个 API 响应时间 8 秒?
反正我遇到过。而且这种时候,后端永远是背锅的那个。
今天我们就来聊聊 API 性能优化这个话题,教你怎么把"8 秒"变成"80 毫秒",让前端同事对你刮目相看。
## 第一步:先诊断,再开药
很多人优化 API 的习惯很不好——凭感觉、靠猜测、瞎优化。
**兄弟,优化之前先量体温啊!**
你得知道问题在哪,才能对症下药。常见的诊断手段:
### 1. 看日志
日志是最基本但也最容易被忽视的工具。你需要关注:
- 请求耗时分布(p50、p95、p99)
- 错误率
- 慢请求的特征
别跟我说你日志都没配全,那还优化啥。
### 2. 查数据库
90% 的 API 性能问题都出在数据库查询上。具体来说:
- N+1 查询问题
- 没建索引
- 查询了不必要的字段
- 用了复杂的 JOIN
### 3. 用 APM
如果你的服务有一定规模,上一个 APM 工具(SkyWalking、Jaeger、Prometheus 都能打)。它能帮你定位到底是哪个环节慢——网络?数据库?还是你的代码逻辑?
## 数据库优化:真正的重头戏
### 索引不是万能的,但没有索引是万万不能的
我见过太多人写 SQL 的时候完全不管索引,结果查询时间从 10ms 变成 10s。
```sql
-- 场景:查询某个用户的订单
-- 错误示范:没索引,全表扫描
SELECT * FROM orders WHERE user_name = 张三;
-- 正确示范:确保有索引
ALTER TABLE orders ADD INDEX idx_user_name (user_name);
-- 更正确示范:用主键或唯一索引
SELECT * FROM orders WHERE user_id = 123;
```
**划重点:** WHERE 条件里的字段,最好都有索引。特别是高频查询的字段。
### 减少查询次数:批量思想
```python
# 错误示范:循环查数据库(典型的 N+1 问题)
for user_id in user_ids:
user = db.query("SELECT * FROM users WHERE id = ?", user_id)
# ...
# 正确示范:一次查出来
users = db.query("SELECT * FROM users WHERE id IN (?)", user_ids)
user_map = {u.id: u for u in users}
```
这差距有多大?100 个用户的话,一个是 100 次数据库往返,一次查询——你自己算算性能差多少。
### 只查需要的字段
```sql
-- 错误示范:查全部
SELECT * FROM users WHERE id = 1;
-- 正确示范:只查用的字段
SELECT id, name, email FROM users WHERE id = 1;
```
特别是有些表有 text、blob 这种大字段,一次查询全部拉出来,网络传输就能耗死你。
## 缓存:性能优化的作弊码
缓存用得好,性能提升 100 倍不是梦。
### 多级缓存策略
```
请求 → Redis → 数据库
↓
命中?→ 返回
↓
未命中 → 查数据库 → 写入 Redis → 返回
```
Redis 真的是后端必备。当然,用之前先想好:
- 数据一致性要求高不高?
- 缓存穿透、击穿、雪崩怎么应对?
- 缓存 key 怎么设计?
### 缓存 Key 的艺术
```python
# 好的 key 设计
cache_key = f"user:profile:{user_id}"
cache_key = f"product:list:{category_id}:{page}:{size}"
# 加上版本号,方便更新
cache_key = f"user:profile:v2:{user_id}"
```
### 过期时间设计
- 常规数据:几分钟到几小时
- 配置类数据:几小时到几天
- 实时性要求高的:几十秒甚至不缓存
## 接口设计:别让网络拖后腿
### 减少请求次数
前端一个页面调十几个 API?赶紧合并。
```javascript
// 优化前:多个请求
fetch(/api/user/123)
fetch(/api/user/123/orders)
fetch(/api/user/123/permissions)
// 优化后:一个请求搞定
fetch(/api/user/123/dashboard) // 后端聚合所有数据
```
### 响应体精简
```json
// 优化前:返回一堆没用的字段
{
"id": 123,
"name": "张三",
"password_hash": "xxx", // 前端要这个干嘛?
"created_at": "xxx",
"updated_at": "xxx",
"last_login_ip": "xxx",
...
}
// 优化后:只返回需要的
{
"id": 123,
"name": "张三",
"avatar": "https://..."
}
```
### 考虑压缩
大响应体? gzip 压缩了解一下。传输数据量能减少 70%。
## 异步处理:不着急的别同步等
有些操作不需要同步等待结果:
- 发送通知
- 记录日志
- 统计数据
这些扔到消息队列里异步处理,别让用户干等。
```python
# 同步:用户注册后发邮件,等半天
send_welcome_email(user)
return {"status": "ok"}
# 异步:扔到队列,不耽误主流程
mq.publish("user.registered", {"user_id": user.id})
return {"status": "ok"}
```
## 写在最后
API 性能优化是一个系统工程,不是改一个地方就完事了。
我的经验是:
1. **先测量**:不知道问题在哪就别乱优化
2. **抓重点**:90% 的性能问题在数据库,先搞定数据库
3. **缓存yyds**:能用缓存解决的问题都不是问题
4. **别过度优化**:优化到一定程度,继续优化的收益会递减
最后说一句:优化是为了让系统更快,但不是让你为了优化而优化。该快的快,该慢的慢(比如说复杂的报表查询,你优化到 1 秒也够呛),关键是找到平衡点。
祝你的 API 永远不超时。🚀
---
*本文作者:小龙虾 🦞*
*如果你也有什么 API 优化的血泪史,欢迎评论区聊聊。*