Tutorial
Redis Cache: Cara Meningkatkan Performa Website 10x Lipat
Baca juga
Redis (Remote Dictionary Server) adalah in-memory data store yang bisa digunakan sebagai caching layer, message broker, atau database primer. Dengan response time dalam mikrodetik, Redis bisa meningkatkan performa website secara dramatis — dari response time beberapa detik menjadi di bawah 10ms.
## Mengapa Redis?
**In-Memory Speed.** Redis menyimpan data di RAM, bukan disk. Akses data dari RAM sekitar 100.000x lebih cepat dari disk SSD. Ini artinya cache lookup yang biasanya memakan waktu 50-200ms bisa selesai dalam <1ms.
**Lebih dari Sekedar Caching.** Redis mendukung berbagai data structures: strings, hashes, lists, sets, sorted sets, dan hyperloglogs. Ini membuatnya versatile untuk berbagai use case.
**Built-in Persistence.** Berbeda dari Memcached, Redis bisa persist data ke disk sehingga tidak hilang saat server restart.
**Pub/Sub dan Streams.** Redis bisa digunakan sebagai message broker untuk microservices atau real-time notifications.
## Install Redis
### Ubuntu/Debian
```bash
apt update && apt install -y redis-server
systemctl enable redis-server
systemctl start redis-server
```
### Docker
```bash
docker run -d --name redis \
-p 6379:6379 \
-v redis-data:/data \
--restart unless-stopped \
redis:7-alpine redis-server --appendonly yes
```
### Verifikasi
```bash
redis-cli ping
# PONG
```
## Konfigurasi Dasar
Edit `/etc/redis/redis.conf`:
### Memory Limit
```
maxmemory 256mb
maxmemory-policy allkeys-lru
```
**allkeys-lru** artinya Redis akan menghapus key yang paling jarang digunakan ketika memory penuh. Policy lain:
- `volatile-lru`: Hanya hapus key yang punya expiry time
- `allkeys-random`: Hapus key random
- `noeviction`: Jangan hapus apapun, return error jika memory penuh
### Security
```
requirepass your-strong-password-here
bind 127.0.0.1 ::1
```
**Penting:** Redis default tidak punya password. Jika Redis exposed ke internet tanpa password, itu celah keamanan kritis.
### Persistence (Opsional)
```
# RDB snapshots
save 900 1
save 300 10
save 60 10000
# AOF (Append Only File)
appendonly yes
appendfsync everysec
```
## Use Cases untuk Website
### 1. Page Cache
Simpan HTML output yang sudah di-render di Redis. request berikutnya langsung ambil dari Redis tanpa proses PHP/Python/Node.
**PHP dengan Redis:**
```php
connect('127.0.0.1', 6379);
$redis->auth('password');
$cacheKey = 'page_' . md5($_SERVER['REQUEST_URI']);
$cached = $redis->get($cacheKey);
if ($cached) {
echo $cached;
exit;
}
ob_start();
// render page...
$html = ob_get_contents();
ob_end_clean();
$redis->setex($cacheKey, 3600, $html); // cache 1 jam
echo $html;
```
### 2. Session Store
Alih-alih simpan session di file (lambat untuk multi-server), simpan di Redis:
**PHP Session Handler:**
```ini
; php.ini
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=password"
```
**Express.js (Node):**
```javascript
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');
const redisClient = createClient({ url: 'redis://:password@localhost:6379' });
redisClient.connect();
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: 'your-secret',
resave: false,
saveUninitialized: false,
}));
```
### 3. Database Query Cache
Cache hasil query database yang sering diakses:
```python
import redis
import json
r = redis.Redis(host='localhost', port=6379, password='password', decode_responses=True)
def get_popular_posts():
cache_key = 'popular_posts'
cached = r.get(cache_key)
if cached:
return json.loads(cached)
# Query database
posts = db.query("SELECT * FROM posts ORDER BY views DESC LIMIT 10")
# Cache selama 5 menit
r.setex(cache_key, 300, json.dumps(posts))
return posts
```
### 4. Rate Limiting
Batasi jumlah request dari IP tertentu:
```python
def is_rate_limited(ip, limit=100, window=60):
key = f"rate:{ip}"
current = r.incr(key)
if current == 1:
r.expire(key, window)
return current > limit
```
### 5. Real-time Counter
Hitung views, likes, atau activity secara real-time:
```python
# Increment view count
r.incr(f"post:{post_id}:views")
# Get trending posts (sorted set)
r.zincrby("trending", 1, post_id)
# Get top 10 trending
trending = r.zrevrange("trending", 0, 9, withscores=True)
```
## Monitoring Redis
### Redis Info
```bash
redis-cli info memory
redis-cli info stats
redis-cli info clients
```
### Key Metrics
- **used_memory:** RAM yang digunakan
- **connected_clients:** Jumlah koneksi aktif
- **ops_per_sec:** Operasi per detik
- **hit_rate:** Cache hit ratio (target: >95%)
```bash
# Hit rate calculation
redis-cli info stats | grep -E "(keyspace_hits|keyspace_misses)"
```
### Redis Commander (Web UI)
```bash
docker run -d --name redis-commander \
-p 8081:8081 \
-e REDIS_HOSTS=local:redis:6379 \
rediscommander/redis-commander
```
## Best Practices
**Gunakan Expiry Time.** Selalu set TTL pada cache keys untuk mencegah memory leak:
```
redis.setex("key", 3600, "value") # 1 jam
```
**Cache Invalidation.** Strategy untuk invalidate cache saat data berubah:
- **TTL-based:** Set expiry time dan biarkan expired
- **Event-based:** Invalidate cache saat data di-update
- **Version-based:** Sertakan version number di cache key
**Connection Pool.** Jangan buka-buka koneksi Redis. Gunakan connection pool:
```python
pool = redis.ConnectionPool(host='localhost', port=6379, max_connections=20)
r = redis.Redis(connection_pool=pool)
```
**Jangan Simpan Semua di Redis.** Redis ada di RAM. Simpan hanya data yang benar-benar sering diakses. Data archival sebaiknya di database disk.
Redis bukan sekedar tool caching — ini adalah Swiss Army Knife untuk performa dan real-time data. Dengan implementasi yang benar, Redis bisa menjadi game-changer untuk website kamu.