Sofortantwort
Redis einfach erklärt
Blitzschnelle In-Memory-Datenbank für Caching und Echtzeit-Daten.
- Kurz gesagt
- In-Memory: Daten im RAM statt auf Festplatte – extrem schnell
- Typischer Einsatz
- Caching, Session Management, Rate Limiting
- Wichtig zu wissen
- Datenstrukturen: Strings, Lists, Sets, Hashes, Sorted Sets
Redis im Überblick
Redis ist eine In-Memory-Datenbank – alle Daten liegen im RAM statt auf der Festplatte. Das macht Redis extrem schnell: Microsekunden statt Millisekunden.
Warum ist das wichtig?
Ohne Cache:
User → API → Datenbank (50ms) → API → User
↑
Jedes Mal
Mit Redis Cache:
User → API → Redis (0.5ms) → API → User
↑
Aus dem RAM
Datenbank nur bei Cache-Miss
Redis-Datenstrukturen:
| Typ | Beschreibung | Use Case |
|---|---|---|
| String | Einfacher Wert | Cache, Counter |
| List | Geordnete Liste | Message Queue, Timeline |
| Set | Ungeordnete Menge | Tags, Unique Visitors |
| Hash | Key-Value in Key | User-Profile, Objekte |
| Sorted Set | Set mit Score | Leaderboards, Rankings |
| Stream | Event Log | Event Sourcing |
Beispiel – Caching:
# Ohne Cache: 50ms Datenbank-Query
SELECT * FROM users WHERE id = 123;
# Mit Redis: 0.5ms
GET user:123
→ Cache Hit: Daten sofort
→ Cache Miss: DB-Query, dann SET user:123
Technisch betrachtet
Redis-Befehle
Strings:
SET user:123:name "Max"
GET user:123:name
→ "Max"
INCR page:views
→ 1, 2, 3, ... (atomar)
SETEX session:abc 3600 "user_data"
→ Läuft nach 1 Stunde ab
Hashes:
HSET user:123 name "Max" email "max@example.com"
HGET user:123 name
→ "Max"
HGETALL user:123
→ {"name": "Max", "email": "max@example.com"}
Sorted Sets (Leaderboards):
ZADD leaderboard 1000 "player1"
ZADD leaderboard 1500 "player2"
ZADD leaderboard 800 "player3"
ZREVRANGE leaderboard 0 2 WITHSCORES
→ 1) "player2" 2) "1500"
3) "player1" 4) "1000"
5) "player3" 6) "800"
Caching-Strategien
Cache-Aside (Lazy Loading):
def get_user(user_id):
# 1. Cache prüfen
cached = redis.get(f"user:{user_id}")
if cached:
return json.loads(cached)
# 2. Cache Miss: DB-Query
user = db.query(f"SELECT * FROM users WHERE id = {user_id}")
# 3. In Cache schreiben
redis.setex(f"user:{user_id}", 3600, json.dumps(user))
return user
Write-Through:
def update_user(user_id, data):
# 1. DB updaten
db.update(user_id, data)
# 2. Cache updaten
redis.setex(f"user:{user_id}", 3600, json.dumps(data))
Cache Invalidation:
def delete_user(user_id):
db.delete(user_id)
redis.delete(f"user:{user_id}") # Cache invalidieren
Redis für Rate Limiting
def is_rate_limited(user_id, limit=100, window=60):
key = f"ratelimit:{user_id}"
current = redis.incr(key)
if current == 1:
redis.expire(key, window) # 60 Sekunden
return current > limit
Pub/Sub für Echtzeit
# Publisher
redis.publish("notifications", json.dumps({
"user_id": 123,
"message": "Neue Nachricht"
}))
# Subscriber
pubsub = redis.pubsub()
pubsub.subscribe("notifications")
for message in pubsub.listen():
handle_notification(message)
Persistenz-Optionen
| Option | Beschreibung | Trade-off |
|---|---|---|
| Keine | Nur RAM | Schnellste, Datenverlust bei Crash |
| RDB | Periodische Snapshots | Gut für Backups, Datenverlust möglich |
| AOF | Jede Operation loggen | Sicherer, etwas langsamer |
| RDB + AOF | Beides | Beste Sicherheit |
Redis Cluster
Für Skalierung über einen Server hinaus:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Master 1│ │ Master 2│ │ Master 3│
│ Slots │ │ Slots │ │ Slots │
│ 0-5460 │ │5461-10922│ │10923-16383│
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Replica │ │ Replica │ │ Replica │
└─────────┘ └─────────┘ └─────────┘
Keys werden auf Slots verteilt (Hash-basiert).