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
| Dimension | Performance Tuning | Performance Engineering |
|---|---|---|
| Timing | After performance problems occur | Throughout the system lifecycle |
| Goal | Solve the current performance problem | Build a continuous performance management system |
| Method | Experience-driven, trial and error | Data-driven, systematic analysis |
| Scope | Focus on specific bottlenecks | Full-stack coverage (application → middleware → infrastructure) |
| Output | Problem solved | Baselines, SLOs, monitoring, optimization strategies |
| Continuity | One-time | Continuous 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:
- Early detection: Discover performance degradation before users notice
- Systematic optimization: Not symptomatic treatment, but systematic improvement
- Cost control: Reasonable resource usage instead of blind scaling
- Capacity planning: Data-driven capacity forecasting
- 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:
| Signal | Meaning | Focus |
|---|---|---|
| Latency | Request processing time | Distinguish between successful and failed request latency |
| Traffic | Request volume | QPS, TPS, concurrency |
| Errors | Error rate | 5xx, business errors, timeouts |
| Saturation | Resource utilization | CPU, 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:
| Dimension | Definition | Measurement |
|---|---|---|
| Utilization | How much time the resource is being used | CPU utilization %, bandwidth utilization % |
| Saturation | Degree of queuing/waiting on the resource | Run queue length, number of IO-waiting requests |
| Errors | Error count for the resource | Network 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)
| Resource | Utilization | Saturation | Errors |
|---|---|---|---|
| CPU | CPU utilization % | Run queue length | - |
| Memory | Used memory % | Swap usage, page scanning | OOM kill count |
| Network | Bandwidth utilization % | NIC queue depth | Packet loss rate, retransmit rate |
| Disk | Busy time % | IO wait queue length | IO errors, bad blocks |
| Storage | Capacity 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
| Dimension | Definition | Measurement |
|---|---|---|
| Rate | Request rate (QPS) | Requests per second |
| Errors | Error rate | Failed request percentage |
| Duration | Response time | P50/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
| Layer | Tool | Purpose |
|---|---|---|
| System | top/htop | CPU/memory overview |
| System | vmstat | Virtual memory, CPU scheduling |
| System | iostat | Disk IO |
| System | sar | Historical performance data |
| System | perf | CPU performance analysis |
| Network | tcpdump | Network packet analysis |
| Network | ss/netstat | Connection states |
| Application | pprof (Go) | Go application profiling |
| Application | JProfiler (Java) | Java application profiling |
| Database | EXPLAIN | SQL execution plan |
| Database | slow query log | Slow queries |
| Tracing | Jaeger/Zipkin | Distributed tracing |
| Visualization | Flame graph | Function 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 Impact | Low 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:
- Performance Engineering ≠ Performance Tuning: Performance engineering is a continuous management system throughout the system lifecycle, not problem-driven temporary optimization
- Golden signals are the starting point: Latency, traffic, errors, saturation — four signals cover the core dimensions of performance monitoring
- USE method for resources: Check utilization, saturation, and errors for each resource to systematically discover resource bottlenecks
- RED method for services: Rate, errors, duration — discover performance issues from the service perspective
- Baselines are foundational: Without a baseline, there’s no standard for “normal” vs “abnormal”
- Bottleneck identification has a method: Golden signals → USE → RED → distributed tracing → profiling, going deeper layer by layer
- Optimization needs ROI: Low-effort high-impact first, high-effort low-impact don’t do
- 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:
- Brendan Gregg - USE Method — Brendangregg, referenced for Brendan Gregg - USE Method
- Tom Wilkie - RED Method — Grafana Labs, referenced for Tom Wilkie - RED Method