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

MerkmalMemcachedRedis
DatenstrukturenKey-ValueVielfältig
PersistenzNeinJa (optional)
ReplikationNeinJa
ClusteringClient-seitigNative
SpeicherverwaltungSlab AllocatorJemalloc
ThreadingMulti-threadedSingle-threaded
Pub/SubNeinJa

Wann Memcached?

- Einfaches Key-Value-Caching
- Horizontale Skalierung über mehrere Server
- Maximale Einfachheit gewünscht
- Session-Storage ohne Persistenz
- Multi-threaded Performance nötig

Wann Redis?

- Komplexe Datenstrukturen (Listen, Sets, Hashes)
- Persistenz erforderlich
- Pub/Sub-Messaging
- Atomare Operationen
- Lua-Scripting
- Replikation und Clustering

Memcached Installation

Debian/Ubuntu

apt install memcached libmemcached-tools

systemctl enable memcached
systemctl start memcached

CentOS/RHEL

dnf install memcached

systemctl enable memcached
systemctl start memcached

Konfiguration

# /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 2m

Verbindungstest

# Telnet
telnet localhost 11211
stats
quit

# Mit memcstat
memcstat --servers=localhost

Redis Installation

Debian/Ubuntu

apt install redis-server

systemctl enable redis-server
systemctl start redis-server

CentOS/RHEL

dnf install redis

systemctl enable redis
systemctl start redis

Konfiguration

# /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 everysec

Verbindungstest

redis-cli
> AUTH sicheres_passwort
> PING
PONG
> INFO

Datenstrukturen

Memcached (nur Strings)

# Telnet-Befehle
set key 0 3600 5
value
STORED

get key
VALUE key 0 5
value
END

delete key
DELETED

Redis (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 visitors

PHP-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 50

Typische Ergebnisse

OperationMemcachedRedis
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 memory

Hochverfü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 1
redis-sentinel /etc/redis/sentinel.conf

Redis 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 1

Monitoring

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 MONITOR

Prometheus/Grafana

# Redis Exporter
docker run -d --name redis_exporter \
    -p 9121:9121 \
    oliver006/redis_exporter \
    --redis.addr redis://localhost:6379

Sicherheit

Memcached absichern

# /etc/memcached.conf

# Nur localhost
-l 127.0.0.1

# SASL-Auth aktivieren
-S

Redis 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 6379

Anwendungsfälle

Session-Caching

Empfehlung: Redis
- Persistenz möglich
- Automatisches Expire
- Bessere Datentypen

Object Cache (WordPress)

Empfehlung: Redis
- Unterstützt komplexe Objekte
- Bessere Plugin-Unterstützung

Page Cache

Empfehlung: Beide geeignet
- Einfache Key-Value-Speicherung
- Memcached bei sehr hohem Durchsatz

Leaderboards/Rankings

Empfehlung: Redis
- Sorted Sets ideal für Rankings
- ZADD, ZRANK, ZRANGE

Message Queue

Empfehlung: Redis
- LPUSH/BRPOP für Queues
- Pub/Sub für Real-time

Rate Limiting

Empfehlung: Redis
- INCR mit EXPIRE
- Atomare Operationen

Zusammenfassung

KriteriumMemcachedRedis
Einfachheit★★★★★★★★☆☆
Datenstrukturen★☆☆☆☆★★★★★
Persistenz☆☆☆☆☆★★★★★
Skalierung★★★★☆★★★★★
Speichereffizienz★★★★☆★★★☆☆
Multi-Threading★★★★★★★☆☆☆
AnwendungsfallEmpfehlung
Einfaches CachingBeide
SessionsRedis
Object CacheRedis
Message QueueRedis
AnalyticsRedis
Nur Cache, keine PersistenzMemcached

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.