Organized 50 interview questions into 12 categories: - 01-分布式系统 (9 files): 分布式事务, 分布式锁, 一致性哈希, CAP理论, etc. - 02-数据库 (2 files): MySQL索引优化, MyBatis核心原理 - 03-缓存 (5 files): Redis数据结构, 缓存问题, LRU算法, etc. - 04-消息队列 (1 file): RocketMQ/Kafka - 05-并发编程 (4 files): 线程池, 设计模式, 限流策略, etc. - 06-JVM (1 file): JVM和垃圾回收 - 07-系统设计 (8 files): 秒杀系统, 短链接, IM, Feed流, etc. - 08-算法与数据结构 (4 files): B+树, 红黑树, 跳表, 时间轮 - 09-网络与安全 (3 files): TCP/IP, 加密安全, 性能优化 - 10-中间件 (4 files): Spring Boot, Nacos, Dubbo, Nginx - 11-运维 (4 files): Kubernetes, CI/CD, Docker, 可观测性 - 12-面试技巧 (1 file): 面试技巧和职业规划 All files renamed to Chinese for better accessibility and organized into categorized folders for easier navigation. 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>
11 KiB
11 KiB
性能优化
问题
- 性能优化的常见思路和方法有哪些?
- 如何进行系统性能瓶颈分析?
- 数据库性能优化有哪些方法?
- JVM 性能调优的常见问题和解决方案?
- 接口性能优化有哪些技巧?
- 如何进行全链路压测?
- 在实际项目中如何进行性能优化?
标准答案
1. 性能优化思路
优化原则
- 测量优先:先测量,后优化
- 抓大放小:优化瓶颈,而非所有地方
- 数据驱动:用数据说话
- 权衡取舍:优化往往带来复杂性
优化层次
用户响应时间
↓
前端优化(减少请求、CDN、缓存)
↓
网络优化(减少 RTT、压缩)
↓
后端优化(代码、算法、并发)
↓
数据库优化(索引、分库分表)
↓
操作系统优化(TCP、内核参数)
↓
硬件优化(CPU、内存、磁盘、网络)
2. 性能瓶颈分析
分析工具
1. CPU 分析:
# top 命令
top -p <pid>
# 查看 CPU 使用率
%CPU: 80.5
# 查看线程 CPU
top -H -p <pid>
2. 内存分析:
# 查看内存使用
free -h
# 查看进程内存
ps aux | grep java
# JVM 堆内存
jmap -heap <pid>
3. 磁盘 I/O:
# iostat
iostat -x 1
# 查看 I/O 等待
%iowait: 15.2 # 高说明磁盘瓶颈
4. 网络 I/O:
# 查看网络连接
netstat -anp | grep <pid>
# 查看网络流量
iftop
Java 性能分析工具
1. JProfiler:
- CPU Profiler
- Memory Profiler
- Thread Profiler
2. Arthas(阿里开源):
# 安装
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 *:
-- ❌ 查询所有列
SELECT * FROM users WHERE id = 1;
-- ✅ 只查询需要的列
SELECT id, name, email FROM users WHERE id = 1;
2. 避免 IN 子查询:
-- ❌ 子查询
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. 批量操作:
-- ❌ 单条插入
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:
-- ❌ 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. 创建合适的索引:
-- 为查询条件创建索引
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. 避免索引失效:
-- ❌ 使用函数
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. 垂直拆分:
-- 拆分前(大表)
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. 水平拆分:
-- 拆分前(单表数据量大)
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. 内存泄漏:
// ❌ 内存泄漏
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:
# 查看 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%)
调优:
# 调整堆内存大小
-Xms4g -Xmx4g
# 调整年轻代大小
-Xmn2g
# 使用 G1 收集器(大堆内存推荐)
-XX:+UseG1GC
# 调整 GC 并行线程
-XX:ParallelGCThreads=8
3. CPU 100%:
# 查看最耗 CPU 的线程
top -H -p <pid>
# 转换线程 ID 为 16 进制
printf "%x" <tid>
# 查看线程堆栈
jstack <pid> | grep <tid-in-hex> -A 20
5. 接口性能优化
优化技巧
1. 异步处理:
// ❌ 同步处理(慢)
@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. 缓存:
// ❌ 每次查询数据库
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. 批量查询:
// ❌ 循环查询(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. 连接池优化:
# 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):
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")
运行:
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 秒
- 数据库查询慢
分析:
EXPLAIN SELECT * FROM users WHERE status = 1;
-- type: ALL(全表扫描)
-- rows: 1000000
优化:
-- 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%
分析:
# 查看 GC 日志
jstat -gcutil <pid> 1000
# FGC 频繁,说明老年代内存不足
优化:
# 调整 JVM 参数
-Xms8g -Xmx8g # 增加堆内存
-Xmn4g # 调整年轻代大小
-XX:+UseG1GC # 使用 G1 收集器
-XX:MaxGCPauseMillis=200 # 设置最大 GC 暂停时间
结果:Full GC 次数从每小时 10 次降至 0 次
8. 阿里 P7 加分项
深度理解:
- 理解性能优化的底层原理(操作系统、网络、数据库)
- 理解各种性能分析工具的实现原理
- 理解性能测试的统计学方法
实战经验:
- 有将接口从秒级优化到毫秒级的经验
- 有解决线上性能问题的经验
- 有全链路压测的经验
架构能力:
- 能设计高性能架构
- 能设计性能监控体系
- 能制定性能优化规范
技术选型:
- 了解各种性能分析工具(JProfiler、Arthas、SkyWalking)
- 了解分布式追踪系统(Zipkin、Jaeger)
- 能根据业务特点制定性能指标