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>
604 lines
11 KiB
Markdown
604 lines
11 KiB
Markdown
# 性能优化
|
||
|
||
## 问题
|
||
|
||
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. Locust(Python)**:
|
||
```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)
|
||
- 能根据业务特点制定性能指标
|