Overview

Performance issues are among the most common scenarios every SRE encounters: users report “it’s slow,” alerts say “P99 latency exceeds threshold,” monitoring shows “CPU is almost maxed.” But many teams handle performance issues with a “tune wherever it’s high” approach — add machines when CPU is high, add indexes when SQL is slow, add cache when latency is high. This symptomatic treatment may work short-term, but over time it makes the system increasingly complex, costs keep rising, and problems become harder to troubleshoot.

Performance Engineering and Performance Tuning are fundamentally different. Performance tuning is a reactive process of “find problem → optimize”; performance engineering is an engineering system of “establish baseline → continuously measure → proactively discover → systematically optimize.” The SRE perspective isn’t “make one API 10ms faster” but “build a systematic performance management framework that discovers and resolves performance issues before users notice them.”

This article systematically covers performance engineering from the SRE perspective — covering methodology, analysis frameworks, baseline establishment, bottleneck identification, optimization strategies, and continuous management.

For systematic approaches to performance analysis, see Brendan Gregg - USE Method and Tom Wilkie - RED Method.

1. Performance Engineering vs Performance Tuning

Concept Distinction

DimensionPerformance TuningPerformance Engineering
TimingAfter performance problems occurThroughout the system lifecycle
GoalSolve the current performance problemBuild a continuous performance management system
MethodExperience-driven, trial and errorData-driven, systematic analysis
ScopeFocus on specific bottlenecksFull-stack coverage (application → middleware → infrastructure)
OutputProblem solvedBaselines, SLOs, monitoring, optimization strategies
ContinuityOne-timeContinuous measurement and management

Why SREs Need Performance Engineering

Team without performance engineering:
  User complains "slow" → Emergency investigation → Find slow SQL → Add index
  → A month later, slow again → Find low cache hit rate → Add cache
  → Another month later, slow again → Find connection pool insufficient → Tune pool
  → Repeat endlessly, system gets more complex, problems keep multiplying

Team with performance engineering:
  Establish performance baseline → Continuous monitoring → Detect P99 slowly rising (before users notice)
  → Proactive analysis → Identify database query pattern change → Optimize query
  → Resolve the issue before users are affected

Value of performance engineering:

  1. Early detection: Discover performance degradation before users notice
  2. Systematic optimization: Not symptomatic treatment, but systematic improvement
  3. Cost control: Reasonable resource usage instead of blind scaling
  4. Capacity planning: Data-driven capacity forecasting
  5. Architecture improvement: Drive architecture-level performance optimization

2. The Golden Signals of Performance

Google SRE’s Four Golden Signals

The Google SRE Book defines four golden signals for monitoring distributed systems:

SignalMeaningFocus
LatencyRequest processing timeDistinguish between successful and failed request latency
TrafficRequest volumeQPS, TPS, concurrency
ErrorsError rate5xx, business errors, timeouts
SaturationResource utilizationCPU, memory, IO, network, connections
Relationship of the four golden signals:

  Traffic   Saturation   Latency   Errors 
  
  Typical evolution path of performance issues:
  1. Traffic growth
  2. Resource saturation rises
  3. Latency starts degrading
  4. Errors begin after exceeding threshold

  Ideal monitoring catches issues at Step 2-3, not Step 4.

Correct Latency Measurement

# Common pitfalls in latency measurement
latency_measurement:
  wrong:
    - "Only looking at average latency — averages mask long-tail problems"
    - "Mixing successful and failed requests — failed requests may inflate average"
    - "Only looking at P50 — 50th percentile may not represent the overall picture"

  correct:
    - "Use percentiles: P50/P95/P99/P99.9"
    - "Separate successful and failed request latency"
    - "Focus on the long tail: P99 reflects user experience better than P50"
    - "Use histograms instead of averages — reveals distribution shape"
# Correct latency measurement in Prometheus

# ❌ Wrong: Average
avg(http_request_duration_seconds)

# ✅ Correct: Percentile
histogram_quantile(0.99, 
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
)

# ✅ Correct: Separate success and failure
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds_bucket{status!~"5.."}[5m])) by (le)
)

The Secret of Latency Distribution

Typical latency distribution:

  Request count
  │  ██
  │ ████
  │██████
  │████████
  │██████████
  │█████████████
  │██████████████████████████████████  ████  ██
  └──────────────────────────────────────────────→ Latency
  0ms  10ms  20ms  50ms  100ms  200ms  500ms  1s  5s

  Most requests are 10-50ms, but there's a long tail at 500ms-5s.
  
  P50 = 30ms     ← Looks good
  P95 = 100ms    ← OK
  P99 = 800ms    ← 1% of users have a bad experience
  P99.9 = 3s     ← 0.1% of users are about to timeout

  If you only look at P50, you won't know that 1% of users waited 800ms.

3. The USE Method

Method Overview

The USE Method was proposed by Brendan Gregg of Netflix for analyzing resource performance:

USE = Utilization × Saturation × Errors

For each resource, check these three dimensions:

DimensionDefinitionMeasurement
UtilizationHow much time the resource is being usedCPU utilization %, bandwidth utilization %
SaturationDegree of queuing/waiting on the resourceRun queue length, number of IO-waiting requests
ErrorsError count for the resourceNetwork packet loss, disk errors, OOM

Resource Inventory and Check Matrix

Server resource inventory:
  ├── CPU
  ├── Memory
  ├── Network interface
  ├── Storage devices (disk/SSD)
  ├── Storage controller
  ├── Network controller
  ├── Interconnects (PCIe, NUMA)
  └── Kernel resources (file descriptors, connection tracking table)
ResourceUtilizationSaturationErrors
CPUCPU utilization %Run queue length-
MemoryUsed memory %Swap usage, page scanningOOM kill count
NetworkBandwidth utilization %NIC queue depthPacket loss rate, retransmit rate
DiskBusy time %IO wait queue lengthIO errors, bad blocks
StorageCapacity utilization %-Filesystem errors

USE Method in Practice

# CPU check
# Utilization
top -bn1 | grep "Cpu(s)"
# Saturation (run queue length)
uptime  # load average > CPU core count indicates saturation

# Memory check
# Utilization
free -m
# Saturation (page scanning)
vmstat 1 | grep -E "si|so"  # si/so > 0 indicates swapping
# Errors
dmesg | grep -i "oom"

# Network check
# Utilization
sar -n DEV 1  # Bandwidth usage
# Saturation
ifconfig  # Check drops/overruns
# Errors
ip -s link  # RX/TX errors

# Disk check
# Utilization
iostat -xz 1  # %util
# Saturation
iostat -xz 1  # avgqu-sz (average queue length)
# Errors
dmesg | grep -i "error\|fail" | grep -i "disk\|scsi"

USE Method Application Principles

USE Method workflow:

1. List all resources
   → CPU, memory, network, disk...

2. Check U/S/E for each resource
   → Is utilization too high?
   → Is it saturated?
   → Are there errors?

3. Identify the bottleneck
   → The first saturated resource is usually the bottleneck

4. Deep dive
   → Why is this resource saturated?
   → Which process/request is consuming it?

5. Optimize
   → Optimize the largest consumer
   → Or scale up that resource

4. The RED Method

Method Overview

The RED Method was proposed by Tom Wilkie (one of the Prometheus creators) for analyzing service performance:

RED = Rate × Errors × Duration

DimensionDefinitionMeasurement
RateRequest rate (QPS)Requests per second
ErrorsError rateFailed request percentage
DurationResponse timeP50/P95/P99 latency

USE vs RED Division of Labor

Complementary relationship between USE and RED:

   RED Method (service perspective)        USE Method (resource perspective)
   ┌───────────────┐                      ┌───────────────┐
   │ Rate          │                      │ CPU           │
   │ Errors        │ ──── why look at resources? ──→       │ Memory        │
   │ Duration      │                      │ Network       │
   └───────────────┘                      │ Disk          │
    "How is the service performing?"       └───────────────┘
                                          "Are resources sufficient?"

   Analysis workflow:
   1. First use RED to discover service issues (high latency? many errors?)
   2. Then use USE to locate resource bottlenecks (which resource is saturated?)
   3. Combine both to find the root cause

RED Method Prometheus Implementation

# Rate: Requests per second
sum(rate(http_requests_total[5m])) by (service)

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

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

RED Dashboard Design

RED dashboard layout (one row per service):

  Service    | 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 is high
  user      | 3,000      | 0.01%      | 25ms        | 90ms

  → Instantly see which service has performance issues

5. Performance Baseline Establishment

Why Performance Baselines Are Needed

A performance baseline is the foundation of performance engineering. Without a baseline, you can’t answer “is current performance normal or abnormal”:

Without a baseline:
  Q: "Is P99 latency of 500ms normal?"
  A: "Don't know, no historical data to compare against."

With a baseline:
  Q: "Is P99 latency of 500ms normal?"
  A: "Baseline P99 is 200ms; current 500ms is 2.5x the baseline, which is abnormal degradation."

Contents of a Performance Baseline

performance_baseline:
  service: "payment-service"
  baseline_period: "2026-06-01 ~ 2026-06-30"
  
  # 1. Traffic baseline
  traffic:
    avg_qps: 2500
    peak_qps: 5000
    daily_pattern: "9:00-22:00 is peak, QPS 3000-5000"
    
  # 2. Latency baseline
  latency:
    p50: 45ms
    p95: 120ms
    p99: 200ms
    p999: 500ms
    
  # 3. Resource usage baseline
  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 baseline
  error_rate:
    avg: 0.03%
    peak: 0.1%
    
  # 5. Dependency performance baseline
  dependencies:
    db_query_p99: "50ms"
    redis_p99: "5ms"
    downstream_api_p99: "100ms"
    
  # 6. Capacity baseline
  capacity:
    max_sustainable_qps: 8000  # Max QPS within SLO
    cpu_per_1000_qps: 12%      # CPU consumed per 1000 QPS
    memory_per_1000_qps: 0.8GB

Baseline Calculation Method

# Performance baseline calculation
def calculate_baseline(metrics_data, period_days=30):
    """
    Calculate performance baseline from historical monitoring data
    """
    baseline = {}
    
    # 1. Calculate percentile latencies
    latencies = metrics_data['latency']
    baseline['latency'] = {
        'p50': percentile(latencies, 50),
        'p95': percentile(latencies, 95),
        'p99': percentile(latencies, 99),
        'p999': percentile(latencies, 99.9)
    }
    
    # 2. Calculate traffic patterns
    qps_data = metrics_data['qps']
    baseline['traffic'] = {
        'avg_qps': mean(qps_data),
        'peak_qps': max(qps_data),
        'p95_qps': percentile(qps_data, 95),
    }
    
    # 3. Calculate resource usage
    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. Calculate anomaly thresholds
    # Using 3-sigma rule: values exceeding mean + 3*std are considered anomalous
    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 Strategy

baseline_update:
  frequency: "Update monthly"
  
  trigger:
    scheduled: "Update on the 1st of each month, based on previous month's data"
    event_driven: "Re-establish baseline after architecture changes"
  
  versioning:
    - "Keep historical baseline versions for comparison"
    - "Investigate when baseline changes exceed 20%"
    
  alerting_based_on_baseline:
    - alert: "LatencyAnomalyDetected"
      condition: "current_p99 > baseline_p99 * 1.5"
      message: "P99 latency exceeds 1.5x the baseline"
    
    - alert: "ResourceSaturationAnomaly"
      condition: "current_cpu > baseline_cpu_p95 * 1.3"
      message: "CPU usage exceeds 1.3x the baseline P95"

6. Bottleneck Identification Workflow

Systematic Bottleneck Identification Method

When a performance issue is identified, follow this workflow to systematically locate the bottleneck:

Step 1: Confirm the problem
   Which metric is abnormal? Latency? Error rate? Resource usage?
   Is it sudden degradation or gradual degradation?
   Scope: All users? Some users? Specific APIs?

Step 2: Golden signal check
   Traffic: Abnormal growth?
   Errors: What type of errors?
   Latency: Is P50 or P99 degraded?
   Saturation: Which resource is near saturation?

Step 3: USE method to locate resource bottleneck
   CPU saturated? (load > core count)
   Memory saturated? (swap/OOM)
   Disk saturated? (high IO wait)
   Network saturated? (bandwidth/packet loss)

Step 4: RED method to locate service bottleneck
   Which service has abnormal latency/errors?
   Is it the service itself or a dependency issue?

Step 5: Distributed tracing to locate specific node
   Use Jaeger/Zipkin to trace request paths
   Find the slowest node

Step 6: Deep dive
   CPU profile (which function consumes CPU?)
   Flame graph (code-level identification)
   Slow query log (database level)
   GC log (memory/GC issues)

Step 7: Validate hypothesis
   Form hypothesis based on analysis
   Validate hypothesis with data
   Fix and verify the effect

Bottleneck Identification Toolkit

LayerToolPurpose
Systemtop/htopCPU/memory overview
SystemvmstatVirtual memory, CPU scheduling
SystemiostatDisk IO
SystemsarHistorical performance data
SystemperfCPU performance analysis
NetworktcpdumpNetwork packet analysis
Networkss/netstatConnection states
Applicationpprof (Go)Go application profiling
ApplicationJProfiler (Java)Java application profiling
DatabaseEXPLAINSQL execution plan
Databaseslow query logSlow queries
TracingJaeger/ZipkinDistributed tracing
VisualizationFlame graphFunction call time visualization

Flame Graph Analysis

Flame graphs are a powerful tool for performance analysis, visually showing where CPU time is spent:

# Flame graph generation for Go applications
# 1. Enable pprof
import _ "net/http/pprof"
go func() {
    http.ListenAndServe("localhost:6060", nil)
}()

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

# 3. Generate flame graph
(pprof) web  # Opens flame graph in browser
Flame graph example (simplified):

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

  → Instantly see that db.Query takes most of the time
  → Of which network (DB network round-trip) takes 200ms
  → Optimization direction: reduce database queries or use connection pooling

Database Performance Analysis

-- 1. Check slow queries
SELECT * FROM pg_stat_statements 
ORDER BY mean_exec_time DESC 
LIMIT 10;

-- 2. Analyze execution plan
EXPLAIN ANALYZE 
SELECT * FROM orders WHERE user_id = 12345;

-- 3. Check index usage
SELECT 
    schemaname,
    relname,
    seq_scan,        -- Full table scan count
    seq_tup_read,    -- Rows read by full table scan
    idx_scan,        -- Index scan count
    idx_tup_fetch    -- Rows fetched by index scan
FROM pg_stat_user_tables
ORDER BY seq_scan DESC;

-- 4. Check lock waits
SELECT 
    pid,
    state,
    wait_event_type,
    wait_event,
    query
FROM pg_stat_activity
WHERE wait_event IS NOT NULL;

7. Optimization Priority Matrix

ROI Analysis of Optimization

Not all performance optimizations are worth doing. You need to evaluate the return on investment:

Optimization ROI = (Performance improvement × Impact scope × Duration) / (Development cost + Risk cost)

Examples:
  Optimization A: Add index
    Performance improvement: Query from 500ms → 50ms (10x)
    Impact scope: All users
    Duration: Permanent
    Development cost: 0.5 days
    Risk cost: Low
    → ROI is very high, do first

  Optimization B: Refactor data access layer
    Performance improvement: P99 from 200ms → 150ms (25%)
    Impact scope: All users
    Duration: Permanent
    Development cost: 2 weeks
    Risk cost: Medium (refactoring may introduce bugs)
    → ROI is medium, schedule it

  Optimization C: Change programming language
    Performance improvement: Expected 30% but uncertain
    Impact scope: Entire system
    Development cost: 6 months
    Risk cost: High
    → ROI is very low, not recommended

Optimization Priority Matrix

High ImpactLow Impact
Low Cost🔴 Do first
Add indexes, add cache, tune parameters
🟡 Do when free
Code micro-optimizations
High Cost🟡 Schedule it
Architecture optimization, database sharding
🟢 Don’t do
Over-optimization

Common Optimization Strategies and Priorities

optimization_strategies:
  # Priority 1: Low effort, high return
  database:
    - strategy: "Add/optimize indexes"
      effort: "Low"
      impact: "High"
      example: "Add index on WHERE clause fields"
    
    - strategy: "Optimize slow queries"
      effort: "Low"
      impact: "High"
      example: "Avoid SELECT *, use covering indexes"
    
    - strategy: "Connection pool optimization"
      effort: "Low"
      impact: "Medium"
      example: "Tune pool size and timeout"

  # Priority 2: Medium effort, medium return
  application:
    - strategy: "Cache hot data"
      effort: "Medium"
      impact: "High"
      example: "Cache product info in Redis"
    
    - strategy: "Batch operations instead of loops"
      effort: "Low"
      impact: "Medium"
      example: "Batch INSERT instead of loop INSERT"
    
    - strategy: "Async processing"
      effort: "Medium"
      impact: "Medium"
      example: "Use message queue for non-critical logic"

  # Priority 3: High effort, high return
  architecture:
    - strategy: "Read-write separation"
      effort: "High"
      impact: "High"
      example: "Route reads to replica"
    
    - strategy: "Database sharding"
      effort: "High"
      impact: "High"
      example: "Shard by user ID"
    
    - strategy: "CDN acceleration"
      effort: "Medium"
      impact: "High"
      example: "Serve static assets via CDN"

  # Not recommended
  anti_patterns:
    - "Premature optimization: optimizing without baseline data"
    - "Micro-optimization: spending a week to improve 1ms to 0.9ms"
    - "Over-engineering: considering sharding at 100 QPS"
    - "Only optimizing application layer: ignoring database and infrastructure"

Optimization Effect Validation

# Performance optimization validation process
optimization_validation:
  before:
    - "Record pre-optimization performance baseline (P50/P95/P99/error rate)"
    - "Ensure monitoring data is complete"
    
  during:
    - "Canary release the optimized code"
    - "Compare metrics before and after optimization"
    
  after:
    - "Verify performance improvement magnitude"
    - "Confirm no functional regression"
    - "Observe stability for at least 24 hours"
    - "Update performance baseline"

  # A/B test validation
  ab_test:
    control_group: "Unoptimized version"
    experiment_group: "Optimized version"
    metrics: ["P50", "P95", "P99", "error_rate", "cpu_usage"]
    duration: "At least 1 hour during high-traffic period"

8. Continuous Performance Management

Performance Regression Detection

Performance is not a one-time effort — code changes can introduce performance regressions. You need a continuous performance regression detection mechanism:

# Performance regression detection
performance_regression_detection:
  ci_cd_integration:
    # Run performance benchmarks before each release
    pre_deploy:
      - name: "Run performance benchmark"
        script: |
          # Compare current version with baseline performance
          ./benchmark.sh --compare baseline
          # Block deployment if P99 degrades by more than 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:
    # Continuously monitor performance metrics
    - 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 latency exceeds baseline threshold (250ms)"
        description: "Current P99: {{ $value }}ms, baseline P99: 200ms"

Performance Budget

Performance budgets turn performance requirements into manageable constraints:

# Performance budget example
performance_budget:
  service: "payment-service"
  
  latency_budget:
    total_p99: "500ms"       # End-to-end P99 budget
    breakdown:
      api_gateway: "20ms"    # Gateway
      app_logic: "100ms"     # Application logic
      db_query: "200ms"      # Database
      cache: "10ms"          # Cache
      network: "20ms"        # Network
      downstream: "150ms"    # Downstream dependencies
      # Note: Parts don't sum to the total budget
      # because not all parts peak simultaneously

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

  enforcement:
    # Check performance budget in CI
    - "In unit tests, mock dependencies and measure pure application logic time"
    - "In integration tests, measure end-to-end latency"
    - "If budget is exceeded, CI fails"

Performance Review

# Monthly Performance Review Template

## Overview
- Service name: payment-service
- Review period: July 2026
- Owner: Zhang San

## Performance Trends
| Metric | Last Month | This Month | Change | Status |
|------|------|------|------|------|
| P50 latency | 45ms | 42ms | -7% | ✅ Improved |
| P99 latency | 200ms | 230ms | +15% | ⚠️ Degraded |
| Error rate | 0.03% | 0.04% | +33% | ⚠️ Degraded |
| CPU avg | 35% | 42% | +20% | ⚠️ Increased |
| QPS avg | 2500 | 3100 | +24% | Traffic growth |

## Analysis
1. P99 latency degraded 15%, primarily due to 24% QPS growth causing CPU usage to rise
2. Error rate slightly increased, correlated with latency degradation (more timeouts)
3. Current CPU at 42%, still in safe range, but growth trend needs attention

## Action Items
- [ ] Analyze which specific APIs have P99 degradation, see if they can be optimized
- [ ] Evaluate if capacity expansion is needed (current CPU approaching 50% warning line)
- [ ] Do a database slow query analysis next week

Performance Culture and Team Collaboration

performance_culture:
  principles:
    - "Performance is everyone's responsibility, not just SRE's"
    - "Performance issues should be data-driven, not based on feelings"
    - "Establish baselines, continuously measure, proactively discover"
    - "Optimization needs ROI analysis, don't do meaningless optimizations"
  
  developer_practices:
    - "Pay attention to performance impact during code reviews"
    - "Set latency budgets when adding new APIs"
    - "Check execution plans when making database changes"
    - "Include performance assertions in unit tests"
  
  sre_practices:
    - "Maintain performance baselines and monitoring"
    - "Conduct regular performance audits"
    - "Drive cross-team performance optimization"
    - "Establish performance budgets and regression detection"

9. Common Performance Optimization Pitfalls

Pitfall 1: “Adding Machines Solves Everything”

Myth: Poor performance → Add CPU/memory/nodes
Problems:
  - If it's a slow SQL query, adding machines only delays the problem
  - If it's lock contention, adding machines may make it worse (distributed locks are slower)
  - Costs keep growing, unsustainable

Correct approach:
  → First identify the bottleneck
  → If resources are insufficient → Scale up
  → If it's a code/SQL issue → Optimize code
  → If it's an architecture issue → Change architecture

Pitfall 2: “Caching Solves Everything”

Myth: Slow  Add cache
Problems:
  - Cache introduces consistency complexity
  - Ineffective when cache hit rate is low
  - Cache itself can become a bottleneck

Correct approach:
   First optimize the data source (database/indexes)
   Then consider caching
   Cache is an optimization technique, not a tool to mask problems

Pitfall 3: “Only Looking at Averages”

Myth: Average latency is 50ms, no problem!
Problems:
  - Averages mask the long tail
  - 1% of users may have waited 5 seconds

Correct approach:
  → Look at P95/P99
  → Look at latency distribution
  → Focus on the long tail

Pitfall 4: “Premature Optimization”

Myth: System hasn't launched yet, but already obsessing over 1ms optimizations
Problems:
  - Wasting time on non-bottlenecks
  - Increasing code complexity
  - Optimizations may be based on wrong assumptions

Correct approach:
  → First make it work
  → Then make it correct
  → Finally make it fast (based on data)

Summary

Performance engineering is one of the areas in the SRE framework that tests engineering depth the most. Key points:

  1. Performance Engineering ≠ Performance Tuning: Performance engineering is a continuous management system throughout the system lifecycle, not problem-driven temporary optimization
  2. Golden signals are the starting point: Latency, traffic, errors, saturation — four signals cover the core dimensions of performance monitoring
  3. USE method for resources: Check utilization, saturation, and errors for each resource to systematically discover resource bottlenecks
  4. RED method for services: Rate, errors, duration — discover performance issues from the service perspective
  5. Baselines are foundational: Without a baseline, there’s no standard for “normal” vs “abnormal”
  6. Bottleneck identification has a method: Golden signals → USE → RED → distributed tracing → profiling, going deeper layer by layer
  7. Optimization needs ROI: Low-effort high-impact first, high-effort low-impact don’t do
  8. Continuous management is key: Performance regression detection, performance budgets, regular reviews — keep performance continuously controllable

Remember the core principle of performance engineering: Measure, don’t guess. All performance optimization decisions should be data-driven — first establish baselines, then discover problems, then identify bottlenecks, and finally optimize and validate. Skipping measurement and jumping straight to optimization, you’re likely optimizing something that isn’t even a bottleneck.

Finally, quoting Donald Knuth: “Premature optimization is the root of all evil.” But adding: “Not optimizing when you should is also the root of all evil.” The key is: use data to determine when to optimize, what to optimize, and how to optimize — this is the engineering value of performance engineering.

References & Acknowledgments

This article referenced the following materials during writing. We thank the original authors for their contributions:

  1. Brendan Gregg - USE Method — Brendangregg, referenced for Brendan Gregg - USE Method
  2. Tom Wilkie - RED Method — Grafana Labs, referenced for Tom Wilkie - RED Method