Introduction
Redis is an in-memory key/value database, extremely fast (often < 1ms per operation). It's used as:
- Application cache: API responses, HTML fragments, costly SQL queries
- Session store: distributed PHP/Node sessions
- Queue / Pub-Sub: async tasks
- Rate limiting: distributed counters
This guide focuses on the cache use case, the most immediate one: turning a 200ms SQL query into a 0.5ms Redis read.
Prerequisites
- Linux VPS (Debian 12 / Ubuntu 22.04+)
- 512 MB RAM minimum (1 GB recommended)
- A web app to accelerate
Step 1: Installation
sudo apt update
sudo apt install -y redis-server
sudo systemctl enable --now redis-server
sudo systemctl status redis-server
Test:
redis-cli ping
# PONG
Step 2: Secure Redis
By default, Redis listens only on 127.0.0.1 (localhost). It's safe if your app is on the same VPS. Otherwise, you absolutely must set a password and restrict bind addresses.
sudo nano /etc/redis/redis.conf
Edit:
# Bind addresses (keep localhost if app on same VPS)
bind 127.0.0.1 ::1
# Strong password
requirepass AVeryLongPassword_WithNumbers_42_AndSpecials!
# Protected mode (disable auth-less access)
protected-mode yes
# Rename dangerous commands (optional but recommended)
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command KEYS ""
rename-command CONFIG "CONFIG_zP9aXkLm"
Restart:
sudo systemctl restart redis-server
Test with auth:
redis-cli -a AVeryLongPassword_WithNumbers_42_AndSpecials! ping
Step 3: Configure max memory and eviction policy
sudo nano /etc/redis/redis.conf
# Redis memory limit (adapt to available RAM)
maxmemory 1gb
# Strategy when memory is full
# allkeys-lru: removes least recently used keys
maxmemory-policy allkeys-lru
Available strategies:
noeviction: refuses writes when full (DB)allkeys-lru: LRU on all keys ⭐ recommended for cachevolatile-lru: LRU on keys with TTLallkeys-random: randomvolatile-ttl: expires keys with shortest TTL
Step 4: Disable persistence for pure cache
If Redis is purely cache (rebuildable data), disable persistence for perf gains:
# Disable RDB snapshots
save ""
# Disable AOF
appendonly no
⚠️ If Redis is a session store or holds critical data, keep persistence active (save 900 1, appendonly yes).
Step 5: System optimizations for Redis
Redis warns on install:
WARNING: The TCP backlog setting of 511 cannot be enforced
WARNING: overcommit_memory is set to 0
WARNING: Transparent Huge Pages enabled
Fix:
sudo nano /etc/sysctl.conf
net.core.somaxconn = 1024
vm.overcommit_memory = 1
sudo sysctl -p
Disable Transparent Huge Pages:
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
To persist:
sudo nano /etc/rc.local
#!/bin/bash
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
exit 0
sudo chmod +x /etc/rc.local
Restart Redis:
sudo systemctl restart redis-server
Step 6: Test performance
# Included benchmark
redis-benchmark -a AVeryLongPassword... -q
Typical output:
SET: 95238 req/s
GET: 103626 req/s
INCR: 102040 req/s
LPUSH: 99009 req/s
100k req/s on a standard VPS. Compared to MySQL (5-10k req/s on simple SELECT), that's 10-20x faster.
Step 7: Cache-Aside Pattern (most common)
Here's how to use it in a PHP app:
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('AVeryLongPassword...');
function getUser($id) {
global $redis, $pdo;
$cacheKey = "user:$id";
// 1. Check cache
$cached = $redis->get($cacheKey);
if ($cached) {
return json_decode($cached, true);
}
// 2. Cache miss: go to DB
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
// 3. Store in cache (TTL 1h)
$redis->setex($cacheKey, 3600, json_encode($user));
return $user;
}
// Invalidate cache on update
function updateUser($id, $data) {
global $redis, $pdo;
$stmt = $pdo->prepare("UPDATE users SET ... WHERE id = ?");
$stmt->execute([...]);
// Invalidation
$redis->del("user:$id");
}
Step 8: WordPress integration
Install the Redis Object Cache plugin:
- Plugins → Add New → "Redis Object Cache" → Activate
- Settings → Redis:
- Host:
127.0.0.1 - Port:
6379 - Password: your Redis password
- Database:
0
- Host:
- Click Enable Object Cache
Typical benefit: -50 to -70% load time.
Step 9: Symfony integration
In config/packages/cache.yaml:
framework:
cache:
app: cache.adapter.redis
default_redis_provider: 'redis://default:[email protected]:6379'
And use in code:
public function show(CacheInterface $cache, int $id): Response
{
$product = $cache->get('product_' . $id, function (ItemInterface $item) use ($id) {
$item->expiresAfter(3600);
return $this->productRepo->find($id);
});
// ...
}
Step 10: Laravel integration
In .env:
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=AVeryLongPassword_WithNumbers_42_AndSpecials!
REDIS_PORT=6379
And:
Cache::remember('users:list', 3600, function () {
return User::all();
});
Step 11: Monitor Redis
CLI
redis-cli -a AVeryLongPassword... INFO stats
redis-cli -a AVeryLongPassword... INFO memory
redis-cli -a AVeryLongPassword... MONITOR # ⚠️ live traffic
Live (top-like)
sudo apt install -y redis-tools
redis-cli -a AVeryLongPassword... --stat
With Grafana
Install redis_exporter and create a Redis dashboard. See the Prometheus + Grafana tutorial.
Step 12: Sentinel for high availability
If Redis becomes critical, set up Redis Sentinel (automatic failover) or Redis Cluster (sharding + HA). Out of scope here, but worth knowing for prod projects.
Troubleshooting
"OOM command not allowed when used memory > 'maxmemory'"
Redis hit its memory limit. Either increase maxmemory, or check maxmemory-policy = allkeys-lru (otherwise it refuses writes).
Connection refused
sudo systemctl status redis-server
sudo journalctl -u redis-server -n 50
Often an invalid config file issue after edit.
Persistence takes too long (Redis blocks)
On large databases (10+ GB), RDB snapshot can block. Solutions:
- Migrate to AOF (
appendonly yes+appendfsync everysec) - Disable persistence if pure cache
- Use Redis Sentinel/Cluster for failover
Keys expire too fast
Check TTL:
TTL user:42
# 3599
No TTL? setex or expire not used. Or LRU eviction too aggressive (increase maxmemory).
Useful commands
# CLI connection
redis-cli -a PASSWORD
# Count keys
DBSIZE
# List keys (DEV only, slow)
KEYS *
# Scan keys (PROD)
SCAN 0 MATCH user:* COUNT 100
# Detailed info
INFO
# Memory stats
INFO memory
# Flush current DB (⚠️)
FLUSHDB
# View key TTL
TTL my_key
# Set with TTL
SETEX my_key 3600 "value"
# Slow query log
SLOWLOG GET 10
Conclusion
Redis is the most cost-effective tool to speed up an app. Benefits:
- Response latency 10-100x lower on cached data
- MySQL/PostgreSQL load reduced by 80-90%
- Ability to handle 10x more traffic without adding resources
Going further:
- Use Redis Streams for persistent queues
- Set up Pub/Sub for inter-microservice communication
- Migrate to KeyDB (Redis fork, multi-threaded, drop-in replacement)
Resources
- Official site: https://redis.io
- Documentation: https://redis.io/docs/
- redis-cli: https://redis.io/docs/ui/cli/


















