Skip to content
ExponaBLOG
PROMETHEUS, GRAFANA & MONITORING · DAY 032 / 100

Monitoring Redis: a practical guide for developers

Keep caches healthy.

Expona Admin5 min read

Monitoring Redis: a practical guide for developers

Redis powers caches, sessions, and real-time features across most production systems, yet teams often treat it as a black box until it breaks. A single poorly configured Redis instance can cascade into application timeouts, lost sessions, and degraded user experience—all preventable with the right monitoring. This guide walks you through implementing Redis monitoring in Prometheus and Grafana so you catch problems before they hit your users.

Why Redis monitoring matters

Redis operates in-memory, which means it has hard constraints: available RAM, connection limits, and eviction policies that directly impact application behavior. Unlike a database that can often recover gracefully or queue requests, a saturated Redis instance fails fast. When you're not watching memory pressure, hit rates, and client connections, you're flying blind into operational debt.

The good news is that Redis exposes detailed metrics through its built-in INFO command. By coupling that with Prometheus and Grafana, you get real-time visibility into cache health, can set meaningful alerts, and debug issues post-incident with historical data.

Setting up redis_exporter

Redis doesn't expose metrics in Prometheus format natively, so we use redis_exporter—a lightweight exporter that scrapes Redis's INFO output and transforms it into Prometheus-compatible metrics.

Deploy redis_exporter as a sidecar or separate service. Here's a Docker Compose setup for local development:

yaml
version: '3.8'
services:
  redis:
    image: redis:7-alpine
    ports:
      - '6379:6379'
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru

  redis-exporter:
    image: oliver006/redis_exporter:latest
    ports:
      - '9121:9121'
    environment:
      REDIS_ADDR: redis://redis:6379
    depends_on:
      - redis

  prometheus:
    image: prom/prometheus:latest
    ports:
      - '9090:9090'
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'

Configure Prometheus to scrape the exporter:

yaml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'redis'
    static_configs:
      - targets: ['localhost:9121']

Once running, visit http://localhost:9121/metrics and you'll see metrics like redis_memory_used_bytes, redis_connected_clients, and redis_keyspace_hits_total. The exporter runs continuously and updates metrics on each scrape interval—typically 15 seconds in development, 30–60 seconds in production.

Memory usage and evictions

Memory is Redis's most critical resource. Unlike disk-based storage, once Redis fills its maxmemory limit, it starts evicting keys according to its policy. If that policy is misconfigured or your traffic grows unexpectedly, you lose cached data silently—users see cache misses, and your database gets hammered.

Monitor three key metrics:

  • redis_memory_used_bytes: Total memory consumed by Redis. Track this against your configured maxmemory limit.
  • redis_evicted_keys_total: Count of keys evicted due to memory pressure. A steady climb indicates your cache is undersized or your retention policy is too aggressive.
  • redis_keyspace_size_bytes (approximate via key count): Helps estimate memory per key, useful for capacity planning.

In a real scenario: you run an e-commerce platform with a 2GB Redis cache. Your maxmemory-policy is set to allkeys-lru (evict least-recently used keys). You notice redis_evicted_keys_total increasing by 50,000 keys per hour during peak traffic. That's a signal: either upgrade to 3GB, implement smarter cache expiry on your application side, or reduce the TTL on less-critical keys.

Create a Grafana panel to alert when memory usage exceeds 80% of max:

yaml
redis_memory_used_bytes / 268435456 > 0.8

Here, 268435456 bytes = 256MB. Adjust the limit to match your Redis configuration. Set the alert to fire after 5 minutes of sustained high usage—transient spikes are normal, but sustained pressure means action.

Hit rate

A cache is only useful if it actually serves data. Hit rate tells you what percentage of requests found data in Redis versus requiring a backend lookup. A declining hit rate can signal evictions, misconfigured TTLs, or changing access patterns.

Calculate hit rate from two counters:

  • redis_keyspace_hits_total: Cumulative successful cache hits.
  • redis_keyspace_misses_total: Cumulative cache misses.

In Prometheus, compute the hit rate over a 5-minute window:

yaml
rate(redis_keyspace_hits_total[5m]) / (rate(redis_keyspace_hits_total[5m]) + rate(redis_keyspace_misses_total[5m]))

Real-world example: your session cache typically maintains a 92% hit rate. One morning, it drops to 78%. Investigation reveals a recent code change that sets session TTL to 5 minutes instead of 30 minutes. Users log out prematurely, create more database queries for re-authentication, and response times spike. With this metric visible in your dashboard, you spot the regression within minutes.

Set an alert threshold that makes sense for your workload. For critical caches like sessions, anything below 85% warrants investigation. For less critical caches (user preferences, feature flags), 60% might be acceptable. The key is knowing your baseline and reacting when it shifts.

Connected clients and blocked commands

Redis is single-threaded, so connection management and command blocking directly affect throughput. Too many idle connections waste memory; too many concurrent clients queue commands and cause latency spikes. Blocked commands (like BLPOP on empty lists) also tie up connections.

Monitor these metrics:

  • redis_connected_clients: Active connections to Redis. Compare against your configured maxclients limit (default 10,000).
  • redis_blocked_clients: Clients waiting on blocking operations. High values indicate contention or inefficient patterns.
  • redis_commands_processed_total: Total commands executed; use with rate() to see commands per second.

Scenario: your application server pool has 50 instances, each opening 3 Redis connections for a connection pool. That's 150 connections—well within typical limits. But during a deployment rollout, a misconfiguration causes each instance to open 20 connections instead. You hit 1,000 connections, which is still safe, but you're consuming more memory per connection than expected, and command latency rises because more clients are queued.

A redis_connected_clients graph makes this visible immediately. Set up an alert at 70% of your limit:

yaml
redis_connected_clients / 10000 > 0.7

For blocked clients, track this separately. A baseline of 0 blocked clients is ideal; 5–10 during heavy load is acceptable. A sustained climb to 50+ suggests a downstream issue: either a consumer is slow to process queued messages, or your queue-based architecture has a bottleneck. Investigating redis_blocked_clients often leads you to fix an N+1 query or an unresponsive microservice rather than a Redis problem itself.

Common mistakes

  • Forgetting to set maxmemory: Without it, Redis will eventually consume all available system RAM and crash or get OOM-killed. Always set maxmemory explicitly and monitor how close you get to it.
  • Not tuning eviction policy: noeviction (the default) rejects writes when full, blocking your application. Choose allkeys-lru or volatile-lru based on your use case, then verify it behaves as expected with metrics.
  • Ignoring hit rate trends: A hit rate of 85% last month and 75% today suggests a real change. Don't assume the drop is normal; investigate.
  • Over-provisioning connections**: Each connection costs memory. If you're opening 100 connections per application instance when 10 would suffice, you're wasting resources and making evictions more likely.
  • Alerting on raw metrics without context: An alert that fires when memory exceeds 200MB is useless if your maxmemory is 500MB and normal operating range is 450MB. Baseline your metrics first.

Key takeaways

  • Deploy redis_exporter to transform Redis INFO output into Prometheus metrics; it's a two-line addition to your stack.
  • Memory pressure drives evictions; track redis_memory_used_bytes and redis_evicted_keys_total to catch undersized instances early.
  • Hit rate is your signal that caching is working; set baselines and alert on significant deviations.
  • Client connections and blocked commands reveal architectural inefficiencies; use them to refine connection pools and message queue consumers.
  • Establish reasonable alert thresholds based on your workload, not arbitrary numbers; test them before a crisis.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles