Memcached und Redis sind die beiden führenden In-Memory-Datenspeicher für Caching. Beide beschleunigen Anwendungen erheblich, haben aber unterschiedliche Stärken und Einsatzgebiete.
Grundlegender Vergleich
Übersicht
| Merkmal | Memcached | Redis | |---------|-----------|-------| | Datenstrukturen | Key-Value | Vielfältig | | Persistenz | Nein | Ja (optional) | | Replikation | Nein | Ja | | Clustering | Client-seitig | Native | | Speicherverwaltung | Slab Allocator | Jemalloc | | Threading | Multi-threaded | Single-threaded | | Pub/Sub | Nein | Ja |
Wann Memcached?
- Einfaches Key-Value-Caching
- Horizontale Skalierung über mehrere Server
- Maximale Einfachheit gewünscht
- Session-Storage ohne Persistenz
- Multi-threaded Performance nötigWann Redis?
- Komplexe Datenstrukturen (Listen, Sets, Hashes)
- Persistenz erforderlich
- Pub/Sub-Messaging
- Atomare Operationen
- Lua-Scripting
- Replikation und ClusteringMemcached Installation
Debian/Ubuntu
apt install memcached libmemcached-tools
systemctl enable memcached
systemctl start memcachedCentOS/RHEL
dnf install memcached
systemctl enable memcached
systemctl start memcachedKonfiguration
# /etc/memcached.conf
# Port
-p 11211
# Speicher (MB)
-m 512
# Maximale Verbindungen
-c 1024
# Benutzer
-u memcache
# Listen-Adresse
-l 127.0.0.1
# Threads
-t 4
# Maximale Item-Größe
-I 2mVerbindungstest
# Telnet
telnet localhost 11211
stats
quit
# Mit memcstat
memcstat --servers=localhostRedis Installation
Debian/Ubuntu
apt install redis-server
systemctl enable redis-server
systemctl start redis-serverCentOS/RHEL
dnf install redis
systemctl enable redis
systemctl start redisKonfiguration
# /etc/redis/redis.conf
# Bind
bind 127.0.0.1
# Port
port 6379
# Passwort
requirepass sicheres_passwort
# Speicherlimit
maxmemory 512mb
maxmemory-policy allkeys-lru
# Persistenz (optional)
save 900 1
save 300 10
save 60 10000
# AOF (Append Only File)
appendonly yes
appendfsync everysecVerbindungstest
redis-cli
> AUTH sicheres_passwort
> PING
PONG
> INFODatenstrukturen
Memcached (nur Strings)
# Telnet-Befehle
set key 0 3600 5
value
STORED
get key
VALUE key 0 5
value
END
delete key
DELETEDRedis (vielfältig)
# Strings
SET user:1 "John"
GET user:1
# Hashes
HSET user:1 name "John" email "john@example.com"
HGET user:1 name
HGETALL user:1
# Listen
LPUSH queue:jobs "job1"
RPUSH queue:jobs "job2"
LPOP queue:jobs
# Sets
SADD tags:article:1 "php" "redis" "cache"
SMEMBERS tags:article:1
SINTER tags:article:1 tags:article:2
# Sorted Sets
ZADD leaderboard 100 "player1"
ZADD leaderboard 150 "player2"
ZRANGE leaderboard 0 -1 WITHSCORES
# HyperLogLog (Unique Counts)
PFADD visitors "user1" "user2" "user1"
PFCOUNT visitorsPHP-Integration
Memcached mit PHP
# Extension installieren
apt install php-memcached
systemctl restart php8.2-fpm<?php
$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);
// Setzen
$memcached->set('key', 'value', 3600);
// Lesen
$value = $memcached->get('key');
// Löschen
$memcached->delete('key');
// Multi-Get
$keys = ['key1', 'key2', 'key3'];
$values = $memcached->getMulti($keys);
// Atomic Increment
$memcached->set('counter', 0);
$memcached->increment('counter');Redis mit PHP
# Extension installieren
apt install php-redis
systemctl restart php8.2-fpm<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('sicheres_passwort');
// Strings
$redis->set('key', 'value');
$redis->setex('key', 3600, 'value'); // Mit TTL
$value = $redis->get('key');
// Hashes
$redis->hSet('user:1', 'name', 'John');
$redis->hSet('user:1', 'email', 'john@example.com');
$user = $redis->hGetAll('user:1');
// Listen
$redis->lPush('queue', 'job1', 'job2');
$job = $redis->rPop('queue');
// Sets
$redis->sAdd('tags', 'php', 'redis');
$tags = $redis->sMembers('tags');
// Sorted Sets
$redis->zAdd('leaderboard', 100, 'player1');
$top = $redis->zRevRange('leaderboard', 0, 9, true);
// Pipelines (Batching)
$pipe = $redis->multi(Redis::PIPELINE);
$pipe->set('key1', 'value1');
$pipe->set('key2', 'value2');
$pipe->get('key1');
$results = $pipe->exec();Session-Handling
Memcached Sessions (PHP)
; /etc/php/8.2/fpm/conf.d/20-sessions.ini
session.save_handler = memcached
session.save_path = "127.0.0.1:11211"Redis Sessions (PHP)
; /etc/php/8.2/fpm/conf.d/20-sessions.ini
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=sicheres_passwort"WordPress Object Cache
// Memcached: wp-content/object-cache.php
// Plugin: W3 Total Cache oder Memcached Object Cache
// Redis: wp-content/object-cache.php
// Plugin: Redis Object Cache
// wp-config.php
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_PASSWORD', 'sicheres_passwort');Caching-Patterns
Cache-Aside (Lazy Loading)
<?php
function getUser($id, $redis) {
$key = "user:{$id}";
// Versuche aus Cache
$cached = $redis->get($key);
if ($cached !== false) {
return json_decode($cached, true);
}
// Aus Datenbank laden
$user = loadUserFromDatabase($id);
// Im Cache speichern
$redis->setex($key, 3600, json_encode($user));
return $user;
}Write-Through
<?php
function updateUser($id, $data, $redis, $db) {
// In Datenbank schreiben
$db->update('users', $data, ['id' => $id]);
// Cache aktualisieren
$key = "user:{$id}";
$redis->setex($key, 3600, json_encode($data));
}Cache Invalidation
<?php
// Einzelnen Key löschen
$redis->del("user:{$id}");
// Pattern löschen (mit SCAN)
$iterator = null;
while ($keys = $redis->scan($iterator, ['match' => 'user:*', 'count' => 100])) {
foreach ($keys as $key) {
$redis->del($key);
}
}
// Tags-basierte Invalidierung
$redis->sAdd('cache:tags:users', "user:1", "user:2");
$keys = $redis->sMembers('cache:tags:users');
$redis->del($keys);Performance-Vergleich
Benchmarking
# Redis Benchmark
redis-benchmark -h 127.0.0.1 -p 6379 -n 100000 -c 50 -q
# Memcached mit memtier_benchmark
apt install memtier-benchmark
memtier_benchmark -s 127.0.0.1 -p 11211 -P memcache_binary -n 100000 -c 50Typische Ergebnisse
| Operation | Memcached | Redis | |-----------|-----------|-------| | SET | ~180.000/s | ~150.000/s | | GET | ~200.000/s | ~180.000/s | | INCR | ~180.000/s | ~160.000/s |
Speichereffizienz
# Memcached Stats
memcstat --servers=localhost
# Redis Info
redis-cli INFO memoryHochverfügbarkeit
Memcached (Client-seitig)
<?php
// Consistent Hashing über mehrere Server
$memcached = new Memcached();
$memcached->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$memcached->addServers([
['server1', 11211],
['server2', 11211],
['server3', 11211],
]);Redis Sentinel
# /etc/redis/sentinel.conf
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1redis-sentinel /etc/redis/sentinel.confRedis Cluster
# Cluster erstellen
redis-cli --cluster create \
192.168.1.1:6379 192.168.1.2:6379 192.168.1.3:6379 \
192.168.1.4:6379 192.168.1.5:6379 192.168.1.6:6379 \
--cluster-replicas 1Monitoring
Memcached
# Statistiken
echo "stats" | nc localhost 11211
# Wichtige Metriken
memcstat --servers=localhost | grep -E "curr_items|bytes|get_hits|get_misses"
# Hit-Rate berechnen
# hit_rate = get_hits / (get_hits + get_misses)Redis
# Allgemeine Info
redis-cli INFO
# Memory
redis-cli INFO memory
# Stats
redis-cli INFO stats
# Langsame Queries
redis-cli SLOWLOG get 10
# Echtzeit-Monitor
redis-cli MONITORPrometheus/Grafana
# Redis Exporter
docker run -d --name redis_exporter \
-p 9121:9121 \
oliver006/redis_exporter \
--redis.addr redis://localhost:6379Sicherheit
Memcached absichern
# /etc/memcached.conf
# Nur localhost
-l 127.0.0.1
# SASL-Auth aktivieren
-SRedis absichern
# /etc/redis/redis.conf
# Passwort
requirepass sicheres_passwort
# Nur localhost
bind 127.0.0.1
# Protected Mode
protected-mode yes
# Gefährliche Befehle umbenennen
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command DEBUG ""
rename-command CONFIG "ADMIN_CONFIG"Firewall
# UFW
ufw deny 11211
ufw deny 6379
# Nur bei Bedarf öffnen (intern)
ufw allow from 192.168.1.0/24 to any port 6379Anwendungsfälle
Session-Caching
Empfehlung: Redis
- Persistenz möglich
- Automatisches Expire
- Bessere DatentypenObject Cache (WordPress)
Empfehlung: Redis
- Unterstützt komplexe Objekte
- Bessere Plugin-UnterstützungPage Cache
Empfehlung: Beide geeignet
- Einfache Key-Value-Speicherung
- Memcached bei sehr hohem DurchsatzLeaderboards/Rankings
Empfehlung: Redis
- Sorted Sets ideal für Rankings
- ZADD, ZRANK, ZRANGEMessage Queue
Empfehlung: Redis
- LPUSH/BRPOP für Queues
- Pub/Sub für Real-timeRate Limiting
Empfehlung: Redis
- INCR mit EXPIRE
- Atomare OperationenZusammenfassung
| Kriterium | Memcached | Redis | |-----------|-----------|-------| | Einfachheit | ★★★★★ | ★★★☆☆ | | Datenstrukturen | ★☆☆☆☆ | ★★★★★ | | Persistenz | ☆☆☆☆☆ | ★★★★★ | | Skalierung | ★★★★☆ | ★★★★★ | | Speichereffizienz | ★★★★☆ | ★★★☆☆ | | Multi-Threading | ★★★★★ | ★★☆☆☆ |
| Anwendungsfall | Empfehlung | |----------------|------------| | Einfaches Caching | Beide | | Sessions | Redis | | Object Cache | Redis | | Message Queue | Redis | | Analytics | Redis | | Nur Cache, keine Persistenz | Memcached |
Fazit
Für die meisten Anwendungsfälle ist Redis die bessere Wahl aufgrund seiner vielfältigen Datenstrukturen, Persistenzoptionen und Features wie Pub/Sub. Memcached eignet sich für einfaches Caching mit höchsten Performance-Anforderungen und Multi-Threading. Beide können auch kombiniert werden: Memcached für Session-Caching und Redis für komplexere Datenstrukturen.