Skip to content
Pro Analyzer — Available with ShieldCI Pro

Redis Eviction Policy Analyzer ​

Analyzer IDCategorySeverityTime To Fix
redis-eviction-policy✅ ReliabilityHigh10 minutes

What This Checks ​

  • Queries the live Redis server for the current maxmemory-policy via CONFIG GET
  • Validates the eviction policy is appropriate based on how your application uses Redis (cache, queue, session, Horizon)
  • Detects when a cache-only Redis server uses noeviction (causes write errors when memory is full)
  • Detects when Redis stores persistent data (queues, sessions, Horizon) with an eviction policy that could delete jobs or sessions
  • Detects when multiple named connections (e.g. cache and default) resolve to the same host:port — since eviction policy is server-level, a cache-only connection is not flagged if its server also serves persistent data (changing the policy there would be dangerous)
  • Checks whether maxmemory is configured (warns if unlimited)
  • Monitors memory usage and warns when consumption exceeds 90% of the configured limit
  • Only runs in production and staging environments (skipped in CI and local)

Why It Matters ​

  • Data loss: If Redis stores queue jobs or sessions and uses an LRU/LFU eviction policy, pending jobs can be silently deleted when memory pressure occurs
  • Write failures: The default noeviction policy returns errors on writes when memory is full -- if Redis is only used for caching, this causes application errors instead of gracefully evicting stale entries
  • Silent degradation: Users get logged out unexpectedly when session data is evicted, or background jobs disappear without any error in application logs
  • Memory exhaustion: Without a maxmemory limit, Redis can consume all available system memory, causing OOM kills in containerized environments
  • Production outages: Memory-related Redis failures cascade to every part of the application that depends on it

How to Fix ​

Quick Fix (2 minutes) ​

Check and set the eviction policy directly on your Redis server:

bash
# Check current policy
redis-cli CONFIG GET maxmemory-policy

# For cache-only servers: allow eviction of least-frequently-used keys
redis-cli CONFIG SET maxmemory-policy allkeys-lfu

# For servers storing persistent data (queues, sessions): prevent eviction
redis-cli CONFIG SET maxmemory-policy noeviction

# Set a memory limit (required for eviction policies to work)
redis-cli CONFIG SET maxmemory 2gb

# Persist changes to redis.conf
redis-cli CONFIG REWRITE

Proper Fix (10 minutes) ​

1: Separate Redis Instances by Workload ​

The best practice is to use different Redis servers (different host or port) for cache vs persistent data. Different logical databases on the same server (database: 0 vs database: 1) are not sufficient — maxmemory-policy is a server-level setting and applies to all databases on the instance simultaneously.

php
// config/database.php
'redis' => [
    'client' => env('REDIS_CLIENT', 'phpredis'),

    // Cache instance - use allkeys-lfu eviction
    'cache' => [
        'host' => env('REDIS_CACHE_HOST', '127.0.0.1'),
        'port' => env('REDIS_CACHE_PORT', 6380),
        'database' => env('REDIS_CACHE_DB', 0),
    ],

    // Queue/Session instance - use noeviction
    'persistent' => [
        'host' => env('REDIS_PERSISTENT_HOST', '127.0.0.1'),
        'port' => env('REDIS_PERSISTENT_PORT', 6381),
        'database' => env('REDIS_PERSISTENT_DB', 0),
    ],
],
php
// config/cache.php
'redis' => [
    'driver' => 'redis',
    'connection' => 'cache',  // Uses cache Redis instance
],
php
// config/queue.php
'redis' => [
    'driver' => 'redis',
    'connection' => 'persistent',  // Uses persistent Redis instance
    'queue' => 'default',
    'retry_after' => 90,
],
php
// config/session.php
'driver' => 'redis',
'connection' => 'persistent',  // Uses persistent Redis instance

2: Configure Redis Server Settings ​

For the cache Redis instance (redis-cache.conf):

ini
maxmemory 2gb
maxmemory-policy allkeys-lfu

For the persistent Redis instance (redis-persistent.conf):

ini
maxmemory 1gb
maxmemory-policy noeviction
appendonly yes

3: Environment-Specific Configuration ​

bash
# .env (production)
REDIS_CACHE_HOST=redis-cache.internal
REDIS_CACHE_PORT=6379
REDIS_PERSISTENT_HOST=redis-persistent.internal
REDIS_PERSISTENT_PORT=6379

4: Monitor Memory Usage ​

Set up monitoring to alert before Redis reaches its memory limit:

bash
# Check memory usage
redis-cli INFO memory | grep used_memory_human
redis-cli INFO memory | grep maxmemory_human

# Check eviction stats
redis-cli INFO stats | grep evicted_keys

Eviction Policy Reference ​

PolicyBehaviorBest For
noevictionReturns error on write when fullQueues, sessions, persistent data
allkeys-lfuEvicts least frequently used keysGeneral-purpose cache (Redis 4+)
allkeys-lruEvicts least recently used keysGeneral-purpose cache
volatile-lfuEvicts LFU keys with TTL setMixed cache + persistent on same instance
volatile-lruEvicts LRU keys with TTL setMixed cache + persistent on same instance
volatile-ttlEvicts keys closest to expiryTime-sensitive cache entries
allkeys-randomEvicts random keysUniform access patterns

ShieldCI Configuration ​

This analyzer is automatically skipped in CI environments ($runInCI = false) and only runs in production and staging environments.

Why skip in CI and development?

  • Eviction policy checks require a live Redis connection with access to the CONFIG GET command
  • CI and local Redis instances are typically ephemeral and not configured to reflect production settings
  • Eviction policy mismatches only matter when Redis is under real memory pressure

Environment Detection: The analyzer checks your Laravel APP_ENV setting and only runs when it maps to production or staging. Custom environment names can be mapped in config/shieldci.php:

php
// config/shieldci.php
'environment_mapping' => [
    'production-us' => 'production',
    'production-blue' => 'production',
    'staging-preview' => 'staging',
],

Examples:

  • APP_ENV=production → Runs (no mapping needed)
  • APP_ENV=production-us → Maps to production → Runs
  • APP_ENV=local → Skipped (not production/staging)

Managed Redis (ElastiCache, Upstash, Memorystore, Redis Cloud): Many managed Redis providers restrict the CONFIG GET command via ACL. The analyzer detects this and skips analysis for those connections rather than emitting false positives — no action required on your part.

References ​