Files
interview/questions/performance-tuning.md
yasinshaw fe2e6dc2f2 feat: add 50 backend interview questions and answers
Generated comprehensive interview preparation materials covering:
- Distributed systems (transactions, locks, ID generation, consistency)
- Database (indexing, sharding, replication, transactions)
- Caching (Redis, cache problems, distributed lock)
- Message queues (RocketMQ, Kafka)
- Concurrency (ThreadLocal, ConcurrentHashMap, thread pools)
- JVM (GC, memory, tuning)
- System design (seckill, short URL, IM, feed, LBS)
- Algorithms (B+ tree, LRU, Red-Black tree, Skip list, Timing wheel)
- Network (TCP/IP, HTTP/HTTPS)
- Security (encryption, SQL injection, XSS)
- Performance tuning
- Design patterns
- Microservices (Spring Boot, Gateway, Service Mesh)
- Container orchestration (Kubernetes, Docker)
- CI/CD, observability

Each file includes:
- Detailed questions
- Comprehensive answers
- Code examples
- Real project experience
- Alibaba P7 level requirements

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-01 00:09:50 +08:00

604 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 性能优化
## 问题
1. 性能优化的常见思路和方法有哪些?
2. 如何进行系统性能瓶颈分析?
3. 数据库性能优化有哪些方法?
4. JVM 性能调优的常见问题和解决方案?
5. 接口性能优化有哪些技巧?
6. 如何进行全链路压测?
7. 在实际项目中如何进行性能优化?
---
## 标准答案
### 1. 性能优化思路
#### **优化原则**
1. **测量优先**:先测量,后优化
2. **抓大放小**:优化瓶颈,而非所有地方
3. **数据驱动**:用数据说话
4. **权衡取舍**:优化往往带来复杂性
---
#### **优化层次**
```
用户响应时间
前端优化减少请求、CDN、缓存
网络优化(减少 RTT、压缩
后端优化(代码、算法、并发)
数据库优化(索引、分库分表)
操作系统优化TCP、内核参数
硬件优化CPU、内存、磁盘、网络
```
---
### 2. 性能瓶颈分析
#### **分析工具**
**1. CPU 分析**
```bash
# top 命令
top -p <pid>
# 查看 CPU 使用率
%CPU: 80.5
# 查看线程 CPU
top -H -p <pid>
```
**2. 内存分析**
```bash
# 查看内存使用
free -h
# 查看进程内存
ps aux | grep java
# JVM 堆内存
jmap -heap <pid>
```
**3. 磁盘 I/O**
```bash
# iostat
iostat -x 1
# 查看 I/O 等待
%iowait: 15.2 # 高说明磁盘瓶颈
```
**4. 网络 I/O**
```bash
# 查看网络连接
netstat -anp | grep <pid>
# 查看网络流量
iftop
```
---
#### **Java 性能分析工具**
**1. JProfiler**
- CPU Profiler
- Memory Profiler
- Thread Profiler
**2. Arthas阿里开源**
```bash
# 安装
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 查看 CPU 最高的线程
dashboard
# 查看方法调用耗时
trace com.example.UserService getUser
# 查看类加载
sc -d com.example.User
```
**3. VisualVM**
- JDK 自带
- 可视化界面
---
### 3. 数据库性能优化
#### **优化层次**
```
SQL 优化
索引优化
表结构优化
数据库配置优化
架构优化(读写分离、分库分表)
```
---
#### **SQL 优化**
**1. 避免 SELECT \***
```sql
-- ❌ 查询所有列
SELECT * FROM users WHERE id = 1;
-- ✅ 只查询需要的列
SELECT id, name, email FROM users WHERE id = 1;
```
**2. 避免 IN 子查询**
```sql
-- ❌ 子查询
SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE status = 1);
-- ✅ JOIN
SELECT o.* FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE u.status = 1;
```
**3. 批量操作**
```sql
-- ❌ 单条插入
INSERT INTO orders (id, user_id) VALUES (1, 100);
INSERT INTO orders (id, user_id) VALUES (2, 100);
INSERT INTO orders (id, user_id) VALUES (3, 100);
-- ✅ 批量插入
INSERT INTO orders (id, user_id) VALUES
(1, 100),
(2, 100),
(3, 100);
```
**4. 使用 UNION ALL 代替 UNION**
```sql
-- ❌ UNION去重
SELECT name FROM users_a
UNION
SELECT name FROM users_b;
-- ✅ UNION ALL不去重
SELECT name FROM users_a
UNION ALL
SELECT name FROM users_b;
```
---
#### **索引优化**
**1. 创建合适的索引**
```sql
-- 为查询条件创建索引
CREATE INDEX idx_user_id ON orders(user_id);
-- 为排序创建索引
CREATE INDEX idx_created_at ON orders(created_at);
-- 联合索引(注意最左前缀)
CREATE INDEX idx_user_status ON orders(user_id, status);
```
**2. 避免索引失效**
```sql
-- ❌ 使用函数
SELECT * FROM orders WHERE YEAR(created_at) = 2024;
-- ✅ 范围查询
SELECT * FROM orders WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
-- ❌ 隐式转换
SELECT * FROM users WHERE phone = 13800138000; -- phone 是 VARCHAR
-- ✅ 显式转换
SELECT * FROM users WHERE phone = '13800138000';
-- ❌ 前缀模糊查询
SELECT * FROM users WHERE name LIKE '%张';
-- ✅ 后缀模糊查询
SELECT * FROM users WHERE name LIKE '张%';
```
---
#### **表结构优化**
**1. 垂直拆分**
```sql
-- 拆分前(大表)
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
password VARCHAR(100),
intro TEXT, -- 简介(可能很长)
settings JSON, -- 设置
created_at DATETIME
);
-- 拆分后
CREATE TABLE users_base (
id BIGINT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
password VARCHAR(100),
created_at DATETIME
);
CREATE TABLE users_ext (
user_id BIGINT PRIMARY KEY,
intro TEXT,
settings JSON
);
```
**2. 水平拆分**
```sql
-- 拆分前(单表数据量大)
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT,
amount DECIMAL(10,2),
created_at DATETIME
); -- 1 亿条数据
-- 拆分后(按时间分表)
CREATE TABLE orders_2024_01 (
id BIGINT PRIMARY KEY,
user_id BIGINT,
amount DECIMAL(10,2),
created_at DATETIME
);
CREATE TABLE orders_2024_02 (
...
);
```
---
### 4. JVM 性能调优
#### **常见问题**
**1. 内存泄漏**
```java
// ❌ 内存泄漏
public class Cache {
private static final Map<String, Object> cache = new HashMap<>();
public void put(String key, Object value) {
cache.put(key, value); // 永不清理,内存泄漏
}
}
// ✅ 使用 Guava Cache
public class Cache {
private static final Cache<String, Object> cache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(10000)
.build();
public void put(String key, Object value) {
cache.put(key, value);
}
}
```
---
**2. 频繁 GC**
```bash
# 查看 GC 情况
jstat -gcutil <pid> 1000
# 输出
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 70.15 80.23 65.40 95.12 90.23 1523 45.236 10 12.345 57.581
# YGC年轻代 GC 次数(正常 1000 次/小时以下)
# FGC老年代 GC 次数(应该接近 0
# GCT总 GC 时间(应该 < 5%
```
**调优**
```bash
# 调整堆内存大小
-Xms4g -Xmx4g
# 调整年轻代大小
-Xmn2g
# 使用 G1 收集器(大堆内存推荐)
-XX:+UseG1GC
# 调整 GC 并行线程
-XX:ParallelGCThreads=8
```
---
**3. CPU 100%**
```bash
# 查看最耗 CPU 的线程
top -H -p <pid>
# 转换线程 ID 为 16 进制
printf "%x" <tid>
# 查看线程堆栈
jstack <pid> | grep <tid-in-hex> -A 20
```
---
### 5. 接口性能优化
#### **优化技巧**
**1. 异步处理**
```java
// ❌ 同步处理(慢)
@PostMapping("/order")
public String createOrder(@RequestBody Order order) {
// 1. 保存订单100ms
orderService.save(order);
// 2. 发送邮件500ms
emailService.send(order);
// 3. 发送短信300ms
smsService.send(order);
// 总耗时900ms
return "success";
}
// ✅ 异步处理(快)
@PostMapping("/order")
public String createOrder(@RequestBody Order order) {
// 1. 保存订单100ms
orderService.save(order);
// 2. 异步发送邮件、短信
CompletableFuture.runAsync(() -> {
emailService.send(order);
smsService.send(order);
});
// 总耗时100ms
return "success";
}
```
---
**2. 缓存**
```java
// ❌ 每次查询数据库
public User getUser(Long userId) {
return userMapper.selectById(userId); // 50ms
}
// ✅ 使用缓存
@Cacheable(value = "users", key = "#userId")
public User getUser(Long userId) {
return userMapper.selectById(userId); // 第一次 50ms后续 1ms
}
```
---
**3. 批量查询**
```java
// ❌ 循环查询N+1 问题)
List<Order> orders = orderMapper.selectList();
for (Order order : orders) {
User user = userMapper.selectById(order.getUserId()); // N 次查询
order.setUser(user);
}
// ✅ 批量查询
List<Order> orders = orderMapper.selectList();
Set<Long> userIds = orders.stream()
.map(Order::getUserId)
.collect(Collectors.toSet());
Map<Long, User> userMap = userMapper.selectByIds(userIds); // 1 次查询
orders.forEach(o -> o.setUser(userMap.get(o.getUserId())));
```
---
**4. 连接池优化**
```yaml
# HikariCP 配置
spring:
datasource:
hikari:
minimum-idle: 10 # 最小空闲连接
maximum-pool-size: 50 # 最大连接池大小
connection-timeout: 30000 # 连接超时时间
idle-timeout: 600000 # 空闲连接超时
max-lifetime: 1800000 # 连接最大生命周期
```
---
### 6. 全链路压测
#### **压测工具**
**1. JMeter**
- 图形化界面
- 支持分布式压测
- 可录制脚本
**2. LocustPython**
```python
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(1, 3)
@task
def index(self):
self.client.get("/")
@task(3)
def api(self):
self.client.get("/api/users")
```
**运行**
```bash
locust -f locustfile.py --host=https://example.com
```
---
#### **压测流程**
```
1. 制定压测计划
- 确定目标QPS、响应时间
- 确定场景(秒杀、日常流量)
2. 编写压测脚本
- 模拟真实用户行为
- 准备测试数据
3. 执行压测
- 逐步加压
- 记录指标
4. 分析结果
- 找出瓶颈
- 优化后再次压测
5. 容量评估
- 确定系统容量
- 预留缓冲(如 30%
```
---
#### **压测指标**
| 指标 | 说明 | 目标值 |
|------|------|--------|
| **QPS** | 每秒请求数 | 根据业务需求 |
| **响应时间** | P99 < 200ms | 根据业务需求 |
| **错误率** | 错误请求比例 | < 0.1% |
| **CPU 使用率** | CPU 占用 | < 70% |
| **内存使用率** | 内存占用 | < 80% |
| **TPS** | 每秒事务数 | 根据业务需求 |
---
### 7. 实际项目案例
#### **案例 1接口响应时间从 2s 优化到 100ms**
**问题**
- 用户列表接口响应时间 2 秒
- 数据库查询慢
**分析**
```sql
EXPLAIN SELECT * FROM users WHERE status = 1;
-- type: ALL全表扫描
-- rows: 1000000
```
**优化**
```sql
-- 1. 添加索引
CREATE INDEX idx_status ON users(status);
-- 2. 只查询需要的字段
SELECT id, name, email FROM users WHERE status = 1;
-- 3. 添加缓存
@Cacheable("users")
```
**结果**:响应时间降至 100ms
---
#### **案例 2解决频繁 GC 问题**
**问题**
- 应用频繁 Full GC
- CPU 使用率 100%
**分析**
```bash
# 查看 GC 日志
jstat -gcutil <pid> 1000
# FGC 频繁,说明老年代内存不足
```
**优化**
```bash
# 调整 JVM 参数
-Xms8g -Xmx8g # 增加堆内存
-Xmn4g # 调整年轻代大小
-XX:+UseG1GC # 使用 G1 收集器
-XX:MaxGCPauseMillis=200 # 设置最大 GC 暂停时间
```
**结果**Full GC 次数从每小时 10 次降至 0 次
---
### 8. 阿里 P7 加分项
**深度理解**
- 理解性能优化的底层原理(操作系统、网络、数据库)
- 理解各种性能分析工具的实现原理
- 理解性能测试的统计学方法
**实战经验**
- 有将接口从秒级优化到毫秒级的经验
- 有解决线上性能问题的经验
- 有全链路压测的经验
**架构能力**
- 能设计高性能架构
- 能设计性能监控体系
- 能制定性能优化规范
**技术选型**
- 了解各种性能分析工具JProfiler、Arthas、SkyWalking
- 了解分布式追踪系统Zipkin、Jaeger
- 能根据业务特点制定性能指标