Two frameworks that actually work
After monitoring production systems for years, we've learned that having good metrics is only half the battle—knowing which metrics to look at is the other half. The RED and USE methods represent two simple monitoring frameworks that align your instrumentation with how your systems actually fail. In this article, we'll explore RED and USE methods: monitoring best practices explained, and show you how to apply each framework to the right parts of your infrastructure.
Understanding the RED method for services
RED stands for Rate, Errors, and Duration. It's designed for monitoring the health of user-facing services—anything that handles requests. The premise is straightforward: if you can answer these three questions about every service, you have visibility into whether users are having a good experience.
Rate is the number of requests per second (or per minute, depending on your scale). It tells you whether traffic is normal, spiking, or dropping unexpectedly. A sudden drop in rate often signals that a dependency is failing and requests aren't reaching your service at all.
Errors is the count of failed requests. Not just HTTP 500s—also 4xx errors that matter to your business. A spike in errors is usually your first signal that something broke. The critical insight is to express errors as a ratio of total requests, so you catch problems even when traffic is low.
Duration (latency) is how long requests take. This is where users feel pain. A service returning 200 responses in 10 seconds is broken from a user perspective, even if technically successful. Measure this at percentiles—p50, p95, p99—because the average hides the suffering of your worst-off users.
RED method in practice: an API endpoint
Let's say you have a payment processing API. Here's what you'd instrument with RED metrics:
# Prometheus scrape config for your payment service
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'payment-api'
static_configs:
- targets: ['localhost:9090']
In your application code (Node.js example), you'd track:
const promClient = require('prom-client');
// Rate: counter for total requests
const httpRequestsTotal = new promClient.Counter({
name: 'http_requests_total',
help: 'Total HTTP requests',
labelNames: ['method', 'route', 'status_code']
});
// Errors: calculated from status_code label
// A Prometheus query: rate(http_requests_total{status_code=~"5.."}[5m])
// Duration: histogram for response times
const httpRequestDuration = new promClient.Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP request latency',
labelNames: ['method', 'route'],
buckets: [0.1, 0.5, 1, 2, 5]
});
// In your middleware:
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestsTotal.inc({
method: req.method,
route: req.route.path,
status_code: res.statusCode
});
httpRequestDuration.observe(
{ method: req.method, route: req.route.path },
duration
);
});
next();
});
Your Grafana dashboard would then show:
- Request rate:
rate(http_requests_total[5m]) - Error rate:
rate(http_requests_total{status_code=~"5.."}[5m])divided by the total rate - Latency percentiles:
histogram_quantile(0.95, http_request_duration_seconds_bucket)
This gives you the complete picture: are requests flowing, are they succeeding, and are they fast?
Understanding the USE method for resources
USE stands for Utilization, Saturation, and Errors. While RED focuses on the request path, USE focuses on the infrastructure that handles those requests. It's essential for understanding why your services slow down.
Utilization is the percentage of time a resource is busy. For CPU, it's the percentage of time doing work. For disk, it's the percentage of capacity used. For memory, it's the percentage allocated. Utilization alone is tricky—you can run at 80% CPU utilization and be fine, or it can be a disaster depending on saturation.
Saturation measures how much work is waiting. It's the queue building up behind the resource. A CPU at 90% utilization but with queued processes waiting is far more concerning than 90% utilization with nothing queued. For databases, saturation might be lock wait time or query queue depth. This is where performance actually degrades.
Errors (in USE) typically means hardware errors, dropped packets, or failed I/O operations. These are less common but critical to catch.
USE method in practice: monitoring a host
You're running a PostgreSQL database on a Linux host. Here's what the USE method tells you to watch:
# Node Exporter metrics (already collected on your host)
# Utilization
node_cpu_seconds_total # CPU usage
node_memory_MemAvailable_bytes # Free memory
node_filesystem_avail_bytes # Free disk space
# Saturation
node_load1 # Load average (queued work)
node_procs_running # Runnable processes
node_disk_io_now # Concurrent I/O operations
# Errors
node_network_transmit_errors_total
node_disk_io_errs_total
A practical Grafana query setup for saturation on CPU:
# CPU saturation: load average relative to core count
node_load1 / count(count by (cpu) (node_cpu_seconds_total))
# Disk saturation: I/O operations waiting
node_disk_io_now
The key insight: when a user reports "the database is slow," the USE method guides you to check saturation first. If CPU utilization is 60% but load average is 8 on a 4-core machine, your problem is queued work, not lack of resources. You might need to optimize queries or scale horizontally.
USE method in practice: monitoring a database
For PostgreSQL, the metrics shift slightly but the framework holds:
- Utilization: percentage of connections used, cache hit ratio (how much data comes from memory vs. disk)
- Saturation: transaction queue depth, lock wait times, bloat in tables
- Errors: failed transactions, replication lag, WAL segment issues
In practice, you'd query:
# Connection utilization
pg_stat_activity_count / max_connections
# Cache saturation (low hit ratio = saturation)
sum(heap_blks_read) / (sum(heap_blks_read) + sum(heap_blks_hit))
# Lock contention (saturation)
SELECT count(*) FROM pg_locks WHERE NOT granted;
RED for services, USE for resources
The division of labor is important. RED is a user-centric framework—it answers "are users getting what they need?" USE is infrastructure-centric—it answers "are my resources the bottleneck?"
In a real system, you use both. When an alert fires, you move down the stack:
- RED tells you that requests are failing or slow
- You check your service logs and traces to narrow the cause
- USE on the database or cache tells you if infrastructure is saturated
- You either optimize the service code, or provision more resources
A payment service using both frameworks might look like this in your monitoring:
| Framework | What you measure | Example alert |
|---|---|---|
| RED | Requests per second, error rate, p99 latency | Error rate above 1%, or p99 latency above 500ms |
| USE | DB CPU utilization, connection saturation, lock wait times | Load average above 8, or queries waiting for locks |
Common mistakes
Monitoring only utilization without saturation: Many teams watch CPU or memory percentage but ignore load average or queue depth. You can hit 95% utilization and still be responsive if nothing is queued. Conversely, 40% utilization with high saturation means users are suffering.
Not measuring error ratios: Counting absolute errors is less useful than the ratio of errors to total requests. If you have 100 errors per second but 1 million requests per second, that's 0.01% error rate—usually acceptable. But 100 errors when you only see 1,000 requests per second is 10% error rate—critical.
Ignoring latency percentiles: Average latency hides the pain. If your p50 is 10ms but p99 is 5 seconds, users at the tail are having a bad time, and your average number doesn't reflect that. Always monitor p95 and p99.
Mixing frameworks inconsistently: Don't apply RED to your database and USE to your API. Pick the right framework for each component, and your alerting becomes clearer and more actionable.
Setting alerts without context: A CPU alert at 80% might be normal for your batch processing job but critical for your web service. Label your alerts and thresholds by component type and expected workload.
Key takeaways
- RED (Rate, Errors, Duration) is your framework for monitoring request-based services. It directly reflects user experience.
- USE (Utilization, Saturation, Errors) is your framework for monitoring infrastructure and resources. It explains why services are slow.
- Always measure errors as a ratio of total requests, not absolute counts.
- Saturation (queued work) often matters more than utilization (busy time) for predicting degradation.
- Use latency percentiles (p95, p99) instead of averages to catch tail latency issues.
- Combine both frameworks in production: RED alerts signal a problem, USE metrics help you diagnose and fix it.
- Instrument both your application code (RED) and your infrastructure (USE) from day one, not after problems surface.






Comments
Loading comments…