Redis caching setup for web application

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1 servicesAll 2065 services
Redis caching setup for web application
Medium
from 1 business day to 3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Setting Up Redis for Web Application Data Caching

Redis as a cache works on a simple principle: reading from Redis is orders of magnitude faster than from PostgreSQL or recomputing. Redis latency — 0.1–1 ms vs 5–50 ms for simple SQL and 100–500 ms for heavy queries. The task isn't to cache everything, but to cache correctly: know what to cache, for how long, and how to invalidate.

Installation and Basic Configuration

apt install redis-server

/etc/redis/redis.conf — key parameters:

# Bind to localhost only if Redis on same server
bind 127.0.0.1

# Password (mandatory for production)
requirepass YourStrongRedisPassword

# Max memory
maxmemory 2gb

# Eviction policy when reaching limit
maxmemory-policy allkeys-lru

# Persistence: disable for pure cache
save ""
appendonly no

# Number of databases
databases 16

# Client timeout
timeout 300

# TCP keepalive
tcp-keepalive 300

maxmemory-policy:

  • allkeys-lru — evict rarely used keys from all DBs. Best for pure cache.
  • volatile-lru — evict only TTL-expired keys. Problematic if keys without TTL.
  • allkeys-lfu — Least Frequently Used — better LRU for Zipf distribution.
  • noeviction — return error on memory exhaustion. For non-cache (queues, sessions).

Basic Caching Patterns

Cache-Aside (Lazy Loading) — application manages cache: read from Redis first, miss means read from DB, store in Redis.

PHP example:

class ProductRepository
{
    private const CACHE_TTL = 3600; // 1 hour

    public function findById(int $id): ?Product
    {
        $cacheKey = "product:{$id}";

        $cached = $this->redis->get($cacheKey);
        if ($cached !== false) {
            return unserialize($cached);
        }

        $product = $this->db->find(Product::class, $id);
        if ($product) {
            $this->redis->setex($cacheKey, self::CACHE_TTL, serialize($product));
        }

        return $product;
    }

    public function save(Product $product): void
    {
        $this->db->persist($product);
        $this->db->flush();

        // Invalidate cache after save
        $this->redis->del("product:{$product->getId()}");
    }
}

Write-Through — write to DB and cache simultaneously. Plus: cache always fresh. Minus: writes slower, caching unused data.

Read-Through — cache fetches from DB on miss. Via Redis modules or libraries (RedisGears).

Laravel Cache

Laravel supports Redis as cache driver out of box:

// config/cache.php
'default' => env('CACHE_DRIVER', 'redis'),

'stores' => [
    'redis' => [
        'driver' => 'redis',
        'connection' => 'cache',
        'lock_connection' => 'default',
    ],
],

config/database.php:

'redis' => [
    'client' => env('REDIS_CLIENT', 'phpredis'), // phpredis faster than predis

    'options' => [
        'cluster' => env('REDIS_CLUSTER', 'redis'),
        'prefix' => env('REDIS_PREFIX', 'myapp_'),
    ],

    'default' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD'),
        'port' => env('REDIS_PORT', '6379'),
        'database' => env('REDIS_DB', '0'),
    ],

    'cache' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD'),
        'port' => env('REDIS_PORT', '6379'),
        'database' => env('REDIS_CACHE_DB', '1'), // Separate DB for cache
    ],
],

Usage:

// Cache with automatic computation on miss
$products = Cache::remember('products:featured', 3600, function () {
    return Product::where('is_featured', true)->with('category')->get();
});

// Tags for group invalidation
$product = Cache::tags(['products', 'category:5'])->remember(
    "product:{$id}",
    3600,
    fn() => Product::find($id)
);

// Invalidate group
Cache::tags(['products'])->flush();

Tags require redis or memcached driver — don't work with file/database cache.

Database Query Caching

For heavy aggregation queries rarely changing:

$stats = Cache::remember('dashboard:stats', 300, function () {
    return DB::table('orders')
        ->selectRaw('
            COUNT(*) as total_orders,
            SUM(total_amount) as revenue,
            AVG(total_amount) as avg_order
        ')
        ->whereDate('created_at', today())
        ->first();
});

5 minute TTL for dashboard stats is reasonable compromise between freshness and load.

Cache Monitoring

# Redis stats
redis-cli -a password INFO stats | grep -E "keyspace_hits|keyspace_misses|used_memory_human"

# Hit rate = hits / (hits + misses)
# Good: > 90%

# Active keys and TTL
redis-cli -a password SCAN 0 MATCH "product:*" COUNT 100

# Size of each group
redis-cli -a password --bigkeys

# Top commands
redis-cli -a password MONITOR  # Warning: loads server, debug only

Production monitoring — Redis Exporter + Grafana:

docker run -d \
  --name redis_exporter \
  -p 9121:9121 \
  oliver006/redis_exporter \
  --redis.addr=redis://localhost:6379 \
  --redis.password=YourPassword

Key Grafana metrics (ID 11835): redis_keyspace_hits_total, redis_keyspace_misses_total, redis_memory_used_bytes, redis_connected_clients.

Data Serialization

Serialized PHP objects use more space than JSON. For simple structs — JSON is faster and more readable:

// Slow and bulky
$this->redis->set($key, serialize($object));
$object = unserialize($this->redis->get($key));

// Faster for simple DTO
$this->redis->set($key, json_encode($data));
$data = json_decode($this->redis->get($key), true);

// For large objects — igbinary (PHP extension)
$this->redis->set($key, igbinary_serialize($object));
$object = igbinary_unserialize($this->redis->get($key));

igbinary gives ~50% compression vs serialize and works faster.

Timeline

Basic Redis installation with Laravel cache driver setup — 4–6 hours. Implementing caching in specific controllers/repositories with proper invalidation — 1–2 days depending on scope. Setting up monitoring — half day.