概述

性能问题几乎是每个 SRE 都会遇到的高频场景:用户反馈"好慢"、告警说"P99 延迟超标"、监控显示"CPU 快满了"。但很多团队对性能问题的处理方式是"哪里高了调哪里"——CPU 高了就加机器,SQL 慢了就加索引,延迟高了就加缓存。这种头痛医头的做法短期内可能有效,但长期来看会让系统越来越复杂、成本越来越高、问题越来越难排查。

性能工程(Performance Engineering)与性能调优(Performance Tuning)有本质区别。性能调优是"发现问题→优化"的反应式过程;性能工程是"建立基线→持续度量→主动发现→系统优化"的工程化体系。SRE 的视角不是"让某个接口快 10ms",而是"建立系统性的性能管理体系,让性能问题在被用户感知之前发现和解决"。

从方法论、分析框架、基线建立、瓶颈定位、优化策略到持续管理,详细梳理 SRE 视角的性能工程。

关于性能分析的系统性方法,可参考 Brendan Gregg - USE MethodTom Wilkie - RED Method

一、性能工程 vs 性能调优

概念区分

维度性能调优性能工程
时机性能问题出现后贯穿系统全生命周期
目标解决当前的性能问题建立持续的性能管理体系
方法经验驱动,试试看数据驱动,详细分析
范围聚焦特定瓶颈覆盖全栈(应用→中间件→基础设施)
产出问题解决基线、SLO、监控、优化策略
持续性一次性持续度量和管理

为什么 SRE 需要性能工程

没有性能工程的团队:
  用户投诉"慢" → 紧急排查 → 发现 SQL 慢 → 加索引
  → 一个月后又慢了 → 发现是缓存命中率低 → 加缓存
  → 又一个月后又慢了 → 发现是连接池不够 → 调连接池
  → 循环往复,系统越来越复杂,问题越来越多

有性能工程的团队:
  建立性能基线 → 持续监控 → 发现 P99 缓慢上升(用户还没感知)
  → 主动分析 → 定位到数据库查询模式变化 → 优化查询
  → 在用户感知之前解决问题

性能工程的价值:

  1. 提前发现:在用户感知之前发现性能劣化
  2. 系统优化:不是头痛医头,而是系统性提升
  3. 成本控制:合理的资源使用,而非盲目扩容
  4. 容量规划:基于性能数据做容量预测
  5. 架构改进:驱动架构层面的性能优化

二、性能分析的黄金信号

Google SRE 的四大黄金信号

Google SRE Book 定义了监控分布式系统的四个黄金信号:

信号含义关注点
延迟(Latency)请求处理时间区分成功和失败的请求延迟
流量(Traffic)请求量QPS、TPS、并发数
错误(Errors)错误率5xx、业务错误、超时
饱和度(Saturation)资源使用率CPU、内存、IO、网络、连接数
四大黄金信号的关系:

  流量 ↑ → 饱和度 ↑ → 延迟 ↑ → 错误 ↑
  
  性能问题的典型演化路径:
  1. 流量增长
  2. 资源饱和度上升
  3. 延迟开始劣化
  4. 超过阈值后开始报错

  理想的监控在 Step 2-3 就能发现问题,而不是等到 Step 4。

延迟的正确度量

# 延迟度量的常见陷阱
latency_measurement:
  wrong:
    - "只看平均延迟——平均值掩盖了长尾问题"
    - "成功和失败请求混在一起——失败的请求可能拉高平均延迟"
    - "只看 P50——50% 的用户体验可能不代表整体"

  correct:
    - "使用百分位:P50/P95/P99/P99.9"
    - "区分成功和失败的请求延迟"
    - "关注长尾:P99 比 P50 更能反映用户体验"
    - "使用直方图而非平均值——能看到分布形态"
# Prometheus 中的正确延迟度量

# ❌ 错误:平均值
avg(http_request_duration_seconds)

# ✅ 正确:百分位
histogram_quantile(0.99, 
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
)

# ✅ 正确:区分成功和失败
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds_bucket{status!~"5.."}[5m])) by (le)
)

延迟分布的秘密

典型的延迟分布:

  请求数
  │  ██
  │ ████
  │██████
  │████████
  │██████████
  │█████████████
  │████████████████████████████████  ████  ██
  └──────────────────────────────────────────────→ 延迟
  0ms  10ms  20ms  50ms  100ms  200ms  500ms  1s  5s

  大部分请求在 10-50ms,但有长尾在 500ms-5s。
  
  P50 = 30ms     ← 看起来很好
  P95 = 100ms    ← 还行
  P99 = 800ms    ← 1% 的用户体验很差
  P99.9 = 3s     ← 0.1% 的用户快超时了

  如果只看 P50,你不会知道有 1% 的用户等了 800ms。

三、USE 方法

方法概述

USE 方法由 Netflix 的 Brendan Gregg 提出,用于分析资源的性能:

USE = Utilization(使用率)× Saturation(饱和度)× Errors(错误)

对每种资源,检查这三个维度:

维度定义度量方式
Utilization资源被使用了多少时间CPU 使用率、带宽利用率
Saturation资源排队/等待的程度运行队列长度、等待 IO 的请求数
Errors资源的错误计数网络丢包、磁盘错误、OOM

资源清单与检查矩阵

服务器资源清单:
  ├── CPU
  ├── 内存
  ├── 网络接口
  ├── 存储设备(磁盘/SSD)
  ├── 存储控制器
  ├── 网络控制器
  ├── 互连(PCIe、NUMA)
  └── 内核资源(文件描述符、连接跟踪表)
资源UtilizationSaturationErrors
CPUCPU 使用率 %运行队列长度-
内存已用内存 %swap 使用、页面扫描OOM kill 次数
网络带宽利用率 %网卡队列深度丢包率、重传率
磁盘忙时间 %IO 等待队列长度IO 错误、坏块
存储容量使用率 %-文件系统错误

USE 方法的实践

# CPU 检查
# Utilization
top -bn1 | grep "Cpu(s)"
# Saturation(运行队列长度)
uptime  # load average > CPU 核数说明饱和

# 内存检查
# Utilization
free -m
# Saturation(页面扫描)
vmstat 1 | grep -E "si|so"  # si/so > 0 说明在 swap
# Errors
dmesg | grep -i "oom"

# 网络检查
# Utilization
sar -n DEV 1  # 带宽使用
# Saturation
ifconfig  # 看 drops/overruns
# Errors
ip -s link  # RX/TX errors

# 磁盘检查
# Utilization
iostat -xz 1  # %util
# Saturation
iostat -xz 1  # avgqu-sz(平均队列长度)
# Errors
dmesg | grep -i "error\|fail" | grep -i "disk\|scsi"

USE 方法的应用原则

USE 方法使用流程:

1. 列出所有资源
   → CPU、内存、网络、磁盘...

2. 对每种资源检查 U/S/E
   → 有没有使用率过高?
   → 有没有饱和?
   → 有没有错误?

3. 发现瓶颈
   → 第一个饱和的资源通常就是瓶颈

4. 深入分析
   → 为什么这个资源饱和?
   → 是哪个进程/请求在消耗?

5. 优化
   → 优化消耗最多的来源
   → 或扩容该资源

四、RED 方法

方法概述

RED 方法由 Tom Wilkie(Prometheus 作者之一)提出,用于分析服务的性能:

RED = Rate(请求速率)× Errors(错误)× Duration(延迟)

维度定义度量方式
Rate请求量(QPS)每秒请求数
Errors错误率失败请求占比
Duration响应时间P50/P95/P99 延迟

USE vs RED 的分工

USE 和 RED 的互补关系:

  RED 方法(服务视角)          USE 方法(资源视角)
  ┌───────────────┐            ┌───────────────┐
  │ Rate          │            │ CPU           │
  │ Errors        │ ────→ 为什么要看资源?──→ │ Memory        │
  │ Duration      │            │ Network       │
  └───────────────┘            │ Disk          │
   "服务表现如何?"              └───────────────┘
                                "资源够不够用?"

  分析流程:
  1. 先用 RED 发现服务问题(延迟高?错误多?)
  2. 再用 USE 定位资源瓶颈(哪个资源饱和了?)
  3. 结合两者找到根因

RED 方法的 Prometheus 实现

# Rate: 每秒请求数
sum(rate(http_requests_total[5m])) by (service)

# Errors: 错误率
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)

# Duration: P99 延迟
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds_bucket[5m])) by (service, le)
)

RED 仪表盘设计

RED 仪表盘布局(每个服务一行):

  服务名    | Rate (QPS) | Error Rate | P50 Latency | P99 Latency
  ----------|------------|------------|-------------|------------
  payment   | 2,500      | 0.05%      | 45ms        | 180ms
  order     | 5,000      | 0.02%      | 30ms        | 120ms
  search    | 8,000      | 0.10%      | 80ms        | 350ms  ← P99 偏高
  user      | 3,000      | 0.01%      | 25ms        | 90ms

  → 一眼看出哪个服务有性能问题

五、性能基线建立

为什么需要性能基线

性能基线是性能工程的基础。没有基线,你无法回答"现在的性能是正常还是异常":

没有基线:
  问:"P99 延迟 500ms 正常吗?"
  答:"不知道,没有历史数据对比。"

有基线:
  问:"P99 延迟 500ms 正常吗?"
  答:"基线 P99 是 200ms,当前 500ms 是基线的 2.5 倍,属于异常劣化。"

性能基线的内容

performance_baseline:
  service: "payment-service"
  baseline_period: "2026-06-01 ~ 2026-06-30"
  
  # 1. 流量基线
  traffic:
    avg_qps: 2500
    peak_qps: 5000
    daily_pattern: "9:00-22:00 为高峰,QPS 3000-5000"
    
  # 2. 延迟基线
  latency:
    p50: 45ms
    p95: 120ms
    p99: 200ms
    p999: 500ms
    
  # 3. 资源使用基线
  resource_usage:
    cpu_avg: 35%
    cpu_peak: 65%
    memory_avg: 4.2GB
    memory_peak: 5.1GB
    disk_io_avg: "500 IOPS"
    network_avg: "50Mbps"
    
  # 4. 错误率基线
  error_rate:
    avg: 0.03%
    peak: 0.1%
    
  # 5. 依赖性能基线
  dependencies:
    db_query_p99: "50ms"
    redis_p99: "5ms"
    downstream_api_p99: "100ms"
    
  # 6. 容量基线
  capacity:
    max_sustainable_qps: 8000  # 在 SLO 内的最大 QPS
    cpu_per_1000_qps: 12%      # 每 1000 QPS 消耗的 CPU
    memory_per_1000_qps: 0.8GB

基线建立方法

# 性能基线计算
def calculate_baseline(metrics_data, period_days=30):
    """
    从历史监控数据计算性能基线
    """
    baseline = {}
    
    # 1. 计算百分位延迟
    latencies = metrics_data['latency']
    baseline['latency'] = {
        'p50': percentile(latencies, 50),
        'p95': percentile(latencies, 95),
        'p99': percentile(latencies, 99),
        'p999': percentile(latencies, 99.9)
    }
    
    # 2. 计算流量模式
    qps_data = metrics_data['qps']
    baseline['traffic'] = {
        'avg_qps': mean(qps_data),
        'peak_qps': max(qps_data),
        'p95_qps': percentile(qps_data, 95),
    }
    
    # 3. 计算资源使用
    cpu_data = metrics_data['cpu_usage']
    baseline['resource_usage'] = {
        'cpu_avg': mean(cpu_data),
        'cpu_p95': percentile(cpu_data, 95),
        'cpu_peak': max(cpu_data),
    }
    
    # 4. 计算异常阈值
    # 使用 3-sigma 规则:超过 mean + 3*std 视为异常
    baseline['anomaly_thresholds'] = {
        'latency_p99': {
            'normal': baseline['latency']['p99'],
            'warning': baseline['latency']['p99'] * 1.5,
            'critical': baseline['latency']['p99'] * 2.0
        },
        'error_rate': {
            'normal': mean(metrics_data['error_rate']),
            'warning': mean(metrics_data['error_rate']) * 3,
            'critical': mean(metrics_data['error_rate']) * 10
        }
    }
    
    return baseline

基线更新策略

baseline_update:
  frequency: "每月更新一次"
  
  trigger:
    scheduled: "每月 1 号,基于上月数据更新基线"
    event_driven: "架构变更后重新建立基线"
  
  versioning:
    - "保留历史基线版本,用于对比"
    - "基线变更超过 20% 时需要分析原因"
    
  alerting_based_on_baseline:
    - alert: "LatencyAnomalyDetected"
      condition: "current_p99 > baseline_p99 * 1.5"
      message: "P99 延迟超过基线的 1.5 倍"
    
    - alert: "ResourceSaturationAnomaly"
      condition: "current_cpu > baseline_cpu_p95 * 1.3"
      message: "CPU 使用率超过基线 P95 的 1.3 倍"

六、瓶颈定位流程

系统性瓶颈定位方法

当发现性能问题时,按以下流程系统性定位瓶颈:

Step 1: 确认问题
  → 什么指标异常?延迟?错误率?资源使用率?
  → 是突然劣化还是渐进劣化?
  → 影响范围:所有用户?部分用户?特定接口?

Step 2: 黄金信号检查
  → 流量:是否异常增长?
  → 错误:错误类型是什么?
  → 延迟:是 P50 还是 P99 劣化?
  → 饱和度:哪个资源接近饱和?

Step 3: USE 方法定位资源瓶颈
  → CPU 饱和?(负载 > 核心数)
  → 内存饱和?(swap/OOM)
  → 磁盘饱和?(IO wait 高)
  → 网络饱和?(带宽/丢包)

Step 4: RED 方法定位服务瓶颈
  → 哪个服务的延迟/错误异常?
  → 是该服务自身的问题还是依赖的问题?

Step 5: 链路追踪定位具体节点
  → 用 Jaeger/Zipkin 追踪请求链路
  → 找到耗时最长的节点

Step 6: 深入分析
  → CPU profile(哪个函数消耗 CPU?)
  → 火焰图(代码级定位)
  → 慢查询日志(数据库层面)
  → GC 日志(内存/GC 问题)

Step 7: 验证假设
  → 基于分析结果提出假设
  → 用数据验证假设
  → 修复并验证效果

瓶颈定位工具箱

层面工具用途
系统层top/htopCPU/内存概览
系统层vmstat虚拟内存、CPU 调度
系统层iostat磁盘 IO
系统层sar历史性能数据
系统层perfCPU 性能分析
网络层tcpdump网络包分析
网络层ss/netstat连接状态
应用层pprof(Go)Go 应用 profile
应用层JProfiler(Java)Java 应用 profile
数据库EXPLAINSQL 执行计划
数据库slow query log慢查询
链路追踪Jaeger/Zipkin分布式链路追踪
可视化火焰图函数调用耗时可视化

火焰图分析

火焰图是性能分析的利器,能直观展示 CPU 时间花在哪里:

# Go 应用的火焰图生成
# 1. 启用 pprof
import _ "net/http/pprof"
go func() {
    http.ListenAndServe("localhost:6060", nil)
}()

# 2. 采集 CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30

# 3. 生成火焰图
(pprof) web  # 在浏览器中打开火焰图
火焰图示例(简化):

  ┌─────────────────────────────────────────────────────┐
  │                  main.main                           │
  ├──────────────┬──────────────────────────────────────┤
  │ http.Handle  │          db.Query                    │
  │              ├──────────┬───────────────────────────┤
  │              │ db.Exec  │   pgConn.Query             │
  │              │          ├──────────┬────────────────┤
  │              │          │  network │   parseResult   │
  │              │          │  200ms   │    50ms         │
  └──────────────┴──────────┴──────────┴────────────────┘

  → 一眼看出 db.Query 占了大部分时间
  → 其中 network(数据库网络往返)占 200ms
  → 优化方向:减少数据库查询次数或使用连接池

数据库性能分析

-- 1. 查看慢查询
SELECT * FROM pg_stat_statements 
ORDER BY mean_exec_time DESC 
LIMIT 10;

-- 2. 分析执行计划
EXPLAIN ANALYZE 
SELECT * FROM orders WHERE user_id = 12345;

-- 3. 检查索引使用情况
SELECT 
    schemaname,
    relname,
    seq_scan,        -- 全表扫描次数
    seq_tup_read,    -- 全表扫描读取的行数
    idx_scan,        -- 索引扫描次数
    idx_tup_fetch    -- 索引扫描获取的行数
FROM pg_stat_user_tables
ORDER BY seq_scan DESC;

-- 4. 检查锁等待
SELECT 
    pid,
    state,
    wait_event_type,
    wait_event,
    query
FROM pg_stat_activity
WHERE wait_event IS NOT NULL;

七、优化优先级矩阵

优化的 ROI 分析

不是所有性能优化都值得做。需要评估投入产出比:

优化 ROI = (性能提升幅度 × 影响范围 × 持续时间) / (开发成本 + 风险成本)

示例:
  优化A: 加索引
    性能提升:查询从 500ms → 50ms(10倍)
    影响范围:所有用户
    持续时间:永久
    开发成本:0.5 天
    风险成本:低
    → ROI 极高,优先做

  优化B: 重构数据访问层
    性能提升:P99 从 200ms → 150ms(25%)
    影响范围:所有用户
    持续时间:永久
    开发成本:2 周
    风险成本:中(重构可能引入 bug)
    → ROI 中等,排期做

  优化C: 换编程语言
    性能提升:预期 30% 但不确定
    影响范围:全系统
    开发成本:6 个月
    风险成本:高
    → ROI 极低,不建议

优化优先级矩阵

高影响低影响
低成本🔴 优先做
加索引、加缓存、调参数
🟡 有空做
代码微优化
高成本🟡 排期做
架构优化、数据库分片
🟢 不做
过度优化

常见优化策略及优先级

optimization_strategies:
  # 优先级 1:低改动高收益
  database:
    - strategy: "添加/优化索引"
      effort: "低"
      impact: "高"
      example: "给 WHERE 条件字段加索引"
    
    - strategy: "优化慢查询"
      effort: "低"
      impact: "高"
      example: "避免 SELECT *,用覆盖索引"
    
    - strategy: "连接池优化"
      effort: "低"
      impact: "中"
      example: "调整连接池大小和超时"

  # 优先级 2:中改动中收益
  application:
    - strategy: "缓存热点数据"
      effort: "中"
      impact: "高"
      example: "Redis 缓存商品信息"
    
    - strategy: "批量操作替代循环"
      effort: "低"
      impact: "中"
      example: "批量 INSERT 替代循环 INSERT"
    
    - strategy: "异步化"
      effort: "中"
      impact: "中"
      example: "非核心逻辑用消息队列异步处理"

  # 优先级 3:高改动高收益
  architecture:
    - strategy: "读写分离"
      effort: "高"
      impact: "高"
      example: "读请求走从库"
    
    - strategy: "数据库分片"
      effort: "高"
      impact: "高"
      example: "按用户 ID 分片"
    
    - strategy: "CDN 加速"
      effort: "中"
      impact: "高"
      example: "静态资源走 CDN"

  # 不建议
  anti_patterns:
    - "过早优化:没有基线数据就盲目优化"
    - "微优化:花一周时间把 1ms 优化到 0.9ms"
    - "过度设计:QPS 100 就考虑分库分表"
    - "只优化应用层:忽视数据库和基础设施"

优化效果验证

# 性能优化的验证流程
optimization_validation:
  before:
    - "记录优化前的性能基线(P50/P95/P99/错误率)"
    - "确保监控数据完整"
    
  during:
    - "灰度发布优化代码"
    - "对比优化前后的指标"
    
  after:
    - "验证性能提升幅度"
    - "确认无功能回归"
    - "观察至少 24 小时的稳定性"
    - "更新性能基线"

  # A/B 测试验证
  ab_test:
    control_group: "未优化版本"
    experiment_group: "优化版本"
    metrics: ["P50", "P95", "P99", "error_rate", "cpu_usage"]
    duration: "至少 1 小时高流量时段"

八、持续性能管理

性能回归检测

性能不是一次性的工作——代码变更可能引入性能回归。需要建立持续的性能回归检测机制:

# 性能回归检测
performance_regression_detection:
  ci_cd_integration:
    # 每次发布前做性能基准测试
    pre_deploy:
      - name: "运行性能基准测试"
        script: |
          # 对比当前版本与基线的性能
          ./benchmark.sh --compare baseline
          # 如果 P99 劣化超过 10%,阻止发布
          if [ $(echo "$P99_REGRESSION > 0.1" | bc) -eq 1 ]; then
            echo "Performance regression detected: P99 degraded by $P99_REGRESSION"
            exit 1
          fi          
  
  continuous_monitoring:
    # 持续监控性能指标
    - alert: "PerformanceRegressionDetected"
      expr: |
        histogram_quantile(0.99,
          sum(rate(http_request_duration_seconds_bucket[1h])) by (le)
        ) > 250        
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "P99 延迟超过基线阈值(250ms)"
        description: "当前 P99: {{ $value }}ms,基线 P99: 200ms"

性能预算

性能预算是把性能要求变成可管理的约束:

# 性能预算示例
performance_budget:
  service: "payment-service"
  
  latency_budget:
    total_p99: "500ms"       # 端到端 P99 预算
    breakdown:
      api_gateway: "20ms"    # 网关
      app_logic: "100ms"     # 应用逻辑
      db_query: "200ms"      # 数据库
      cache: "10ms"          # 缓存
      network: "20ms"        # 网络
      downstream: "150ms"    # 下游依赖
      # 注意:各部分预算之和不等于总预算
      # 因为不是所有部分都同时出现

  resource_budget:
    cpu_per_request: "10ms CPU time"
    memory_per_request: "5MB"
    db_connections: "max 20 concurrent"

  enforcement:
    # 在 CI 中检查性能预算
    - "单元测试中 mock 依赖,测量纯应用逻辑耗时"
    - "集成测试中测量端到端延迟"
    - "如果超出预算,CI 失败"

性能 Review

# 月度性能 Review 模板

## 概览
- 服务名称:payment-service
- 评审周期:2026 年 7 月
- 负责人:张三

## 性能趋势
| 指标 | 上月 | 本月 | 变化 | 状态 |
|------|------|------|------|------|
| P50 延迟 | 45ms | 42ms | -7% | ✅ 改善 |
| P99 延迟 | 200ms | 230ms | +15% | ⚠️ 劣化 |
| 错误率 | 0.03% | 0.04% | +33% | ⚠️ 劣化 |
| CPU 均值 | 35% | 42% | +20% | ⚠️ 上升 |
| QPS 均值 | 2500 | 3100 | +24% | 流量增长 |

## 分析
1. P99 延迟劣化 15%,主要原因是 QPS 增长 24% 导致 CPU 使用率上升
2. 错误率轻微上升,与延迟劣化相关(超时增加)
3. 当前 CPU 42%,尚在安全范围,但需要关注增长趋势

## 行动项
- [ ] 分析 P99 劣化的具体接口,是否可以优化
- [ ] 评估是否需要扩容(当前 CPU 接近 50% 预警线)
- [ ] 下周做一次数据库慢查询分析

性能文化与团队协作

performance_culture:
  principles:
    - "性能是所有人的责任,不只是 SRE 的"
    - "性能问题用数据说话,不凭感觉"
    - "建立基线,持续度量,主动发现"
    - "优化要有 ROI 分析,不做无意义优化"
  
  developer_practices:
    - "代码 review 时关注性能影响"
    - "新增 API 时设定延迟预算"
    - "数据库变更时检查执行计划"
    - "写单元测试时包含性能断言"
  
  sre_practices:
    - "维护性能基线和监控"
    - "定期做性能审计"
    - "驱动跨团队的性能优化"
    - "建立性能预算和回归检测"

九、性能优化的常见误区

误区一:“加机器解决一切”

误区:性能不好 → 加 CPU/加内存/加节点
问题:
  - 如果是 SQL 慢查询,加机器只是延缓问题
  - 如果是锁竞争,加机器可能更糟(分布式锁更慢)
  - 成本持续增长,不可持续

正确做法:
  → 先定位瓶颈
  → 如果是资源不足 → 扩容
  → 如果是代码/SQL 问题 → 优化代码
  → 如果是架构问题 → 改架构

误区二:“缓存解决一切”

误区:慢 → 加缓存
问题:
  - 缓存引入一致性复杂性
  - 缓存命中率低时无效
  - 缓存本身可能成为瓶颈

正确做法:
  → 先优化数据源(数据库/索引)
  → 再考虑缓存
  → 缓存是优化手段,不是掩盖问题的工具

误区三:“只看平均值”

误区:平均延迟 50ms,没问题!
问题:
  - 平均值掩盖了长尾
  - 1% 的用户可能等了 5 秒

正确做法:
  → 看 P95/P99
  → 看延迟分布
  → 关注长尾

误区四:“过早优化”

误区:系统还没上线,就开始纠结 1ms 的优化
问题:
  - 浪费时间在非瓶颈上
  - 增加代码复杂度
  - 优化可能基于错误的假设

正确做法:
  → 先让它工作
  → 再让它正确
  → 最后让它快速(基于数据优化)

总结

性能工程是 SRE 体系中最考验工程深度的领域之一。核心要点:

  1. 性能工程 ≠ 性能调优:性能工程是贯穿系统全生命周期的持续管理体系,不是问题驱动的临时优化
  2. 黄金信号是起点:延迟、流量、错误、饱和度——四个信号覆盖了性能监控的核心维度
  3. USE 方法看资源:对每种资源检查使用率、饱和度、错误,系统性发现资源瓶颈
  4. RED 方法看服务:请求速率、错误率、延迟——从服务视角发现性能问题
  5. 基线是基础:没有基线就没有"正常"和"异常"的判断标准
  6. 瓶颈定位有方法:黄金信号 → USE → RED → 链路追踪 → Profile,逐层深入
  7. 优化要算 ROI:低改动高收益优先做,高改动低收益不做
  8. 持续管理是关键:性能回归检测、性能预算、定期 Review——让性能持续可控

记住性能工程的核心原则:Measure, don’t guess(度量,不要猜测)。 所有性能优化决策都应该基于数据——先建立基线,再发现问题,然后定位瓶颈,最后优化验证。跳过度量直接优化,你很可能在优化一个不是瓶颈的地方。

最后引用 Donald Knuth 的名言:“过早优化是万恶之源。” 但要补充一句:“该优化时不优化,也是万恶之源。” 关键在于:基于数据判断什么时候该优化、优化什么、怎么优化——这正是性能工程的工程价值所在。

参考资料与致谢

本文在撰写过程中参考了以下资料,感谢原作者的贡献:

  1. Brendan Gregg - USE Method — Brendangregg,参考了Brendan Gregg - USE Method相关内容
  2. Tom Wilkie - RED Method — Grafana,参考了Tom Wilkie - RED Method相关内容