bookworm-smart-assistant/skills/performance-expert/SKILL.md

300 lines
6.7 KiB
Markdown
Raw Normal View History

---
name: performance-expert
description: >
性能优化专家。当用户需要进行前端性能优化、后端性能调优、数据库优化、性能监控、
Core Web Vitals(LCP/FID/CLS)优化、首屏加载优化、内存优化、索引优化,
或说 "性能优化"、"加载慢"、"响应慢" 时使用此技能。
allowed-tools: Read, Glob, Grep, Edit, Write, Bash, mcp__chrome-devtools, mcp__playwright
maturity: stable
last-reviewed: 2026-02-18
composable: true
enhances: [sre-expert, database-tuning-expert, frontend-expert]
---
# 性能优化专家 (Performance Expert)
> **Output Style**: 本技能使用内联输出规范
资深性能优化工程师,精通前后端性能分析、优化策略和监控方案。
## 触发关键词
- **前端性能**: `首屏优化`, `加载慢`, `LCP`, `FCP`, `Core Web Vitals`
- **后端性能**: `响应慢`, `API慢`, `延迟高`, `吞吐量`
- **资源优化**: `内存优化`, `CPU优化`, `带宽优化`
- **数据库**: `查询慢`, `数据库优化`, `索引优化`
- **通用**: `性能优化`, `性能调优`, `性能问题`
## 前端性能优化
### Core Web Vitals
```yaml
LCP (Largest Contentful Paint):
目标: < 2.5s
优化:
- 优化关键渲染路径
- 预加载关键资源
- 使用 CDN
- 图片优化
FID (First Input Delay):
目标: < 100ms
优化:
- 减少 JS 执行时间
- 代码分割
- Web Worker
CLS (Cumulative Layout Shift):
目标: < 0.1
优化:
- 图片设置尺寸
- 字体预加载
- 避免动态插入内容
```
### 代码分割
```typescript
// 路由级别分割
const Dashboard = lazy(() => import('./pages/Dashboard'));
// 组件级别分割
const HeavyChart = lazy(() => import('./components/HeavyChart'));
// 条件加载
const AdminPanel = lazy(() =>
user.isAdmin ? import('./AdminPanel') : import('./UserPanel')
);
```
### 图片优化
```typescript
// Next.js Image
import Image from 'next/image';
<Image
src="/hero.jpg"
width={1200}
height={600}
priority // 关键图片预加载
placeholder="blur"
blurDataURL={blurUrl}
/>
// 响应式图片
<picture>
<source srcSet="image.avif" type="image/avif" />
<source srcSet="image.webp" type="image/webp" />
<img src="image.jpg" alt="..." loading="lazy" />
</picture>
```
### 缓存策略
```typescript
// Service Worker 缓存
const CACHE_NAME = 'v1';
const STATIC_ASSETS = ['/app.js', '/styles.css'];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(STATIC_ASSETS))
);
});
// HTTP 缓存头
Cache-Control: public, max-age=31536000, immutable // 静态资源
Cache-Control: no-cache, must-revalidate // API 响应
```
## 后端性能优化
### 数据库优化
```sql
-- 索引优化
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at DESC);
-- 查询分析
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 1;
-- 避免 N+1
SELECT u.*, o.* FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.id IN (1, 2, 3);
```
### 缓存层
```typescript
// Redis 缓存
async function getUserWithCache(userId: string) {
const cacheKey = `user:${userId}`;
// 先查缓存
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
// 查数据库
const user = await db.user.findUnique({ where: { id: userId } });
// 写入缓存
await redis.setex(cacheKey, 3600, JSON.stringify(user));
return user;
}
```
### 连接池
```typescript
// 数据库连接池
const pool = new Pool({
max: 20, // 最大连接数
min: 5, // 最小连接数
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
```
## 性能监控
### 前端监控
```typescript
// Web Vitals 监控
import { onLCP, onFID, onCLS } from 'web-vitals';
onLCP((metric) => {
analytics.send('LCP', metric.value);
});
onFID((metric) => {
analytics.send('FID', metric.value);
});
onCLS((metric) => {
analytics.send('CLS', metric.value);
});
```
### 后端监控
```typescript
// 请求耗时中间件
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
metrics.histogram('http_request_duration', duration, {
method: req.method,
path: req.path,
status: res.statusCode,
});
});
next();
});
```
## 性能检查清单
```markdown
### 前端
- [ ] 代码分割和懒加载
- [ ] 图片优化 (WebP/AVIF)
- [ ] 关键 CSS 内联
- [ ] 预加载关键资源
- [ ] 减少第三方脚本
### 后端
- [ ] 数据库索引
- [ ] 查询优化
- [ ] 缓存策略
- [ ] 连接池配置
- [ ] 异步处理
### 网络
- [ ] CDN 配置
- [ ] 压缩 (Gzip/Brotli)
- [ ] HTTP/2
- [ ] 缓存头设置
```
## 输出规范
- 量化性能指标
- 提供具体优化代码
- 说明优化效果预期
- 给出优先级建议
## 压测脚本生成
### k6 负载测试模板
```javascript
// load-test.js — k6 脚本
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 50 }, // Ramp-up
{ duration: '1m', target: 50 }, // Steady
{ duration: '30s', target: 200 }, // Spike
{ duration: '1m', target: 200 }, // Sustained peak
{ duration: '30s', target: 0 }, // Ramp-down
],
thresholds: {
http_req_duration: ['p(95)<500', 'p(99)<1000'], // 95%<500ms, 99%<1s
http_req_failed: ['rate<0.01'], // 错误率<1%
},
};
export default function () {
const res = http.get('http://localhost:3000/api/health');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 200ms': (r) => r.timings.duration < 200,
});
sleep(1);
}
// 运行: k6 run load-test.js
// 云端: k6 cloud run load-test.js
```
### Artillery 压测模板
```yaml
# artillery-config.yml
config:
target: "http://localhost:3000"
phases:
- duration: 60
arrivalRate: 10
name: "Warm up"
- duration: 120
arrivalRate: 50
name: "Sustained load"
defaults:
headers:
Content-Type: "application/json"
scenarios:
- name: "API health check"
flow:
- get:
url: "/api/health"
expect:
- statusCode: 200
# 运行: npx artillery run artillery-config.yml
```
### 压测检查清单
- [ ] 基准测试: 单用户响应时间 baseline
- [ ] 阶梯加压: 10→50→100→200 并发
- [ ] 峰值测试: 设计容量 2x 突发
- [ ] 浸泡测试: 正常负载持续 4h+ (检测内存泄漏)
- [ ] 数据库连接池是否耗尽
- [ ] 文件句柄/Socket 是否泄漏
- [ ] GC 暂停是否影响 P99 延迟
## 禁止事项
- ❌ 不要过早优化
- ❌ 不要忽略监控数据
- ❌ 不要只优化不验证
- ❌ 不要忽视用户体验
- ❌ 不要在没有 baseline 的情况下做优化