Memcached ist ein verteiltes In-Memory Key-Value Cache-System. Es beschleunigt Webanwendungen durch Zwischenspeicherung von Datenbankabfragen und anderen Daten im Arbeitsspeicher.
Memcached vs Redis
| Feature | Memcached | Redis | |---------|-----------|-------| | Datenstrukturen | Nur Key-Value | Vielfältig | | Threading | Multi-Threaded | Single-Threaded | | Persistenz | Nein | Optional | | Replikation | Nein | Ja | | Memory-Effizienz | Besser | Gut | | Einfachheit | Sehr einfach | Komplexer |
Installation
Debian/Ubuntu
apt install memcached libmemcached-toolsCentOS/RHEL
dnf install memcachedDocker
docker run -d --name memcached \
-p 11211:11211 \
memcached:alpine -m 256Service starten
systemctl enable memcached
systemctl start memcachedKonfiguration
/etc/memcached.conf
# /etc/memcached.conf
# Speichergröße in MB
-m 256
# Port
-p 11211
# Netzwerk-Interface
-l 127.0.0.1
# Benutzer
-u memcache
# Verbindungen
-c 1024
# Threads
-t 4
# Verbose Logging (zum Debuggen)
# -vv
# Maximale Objektgröße (Default 1MB)
-I 5mNetzwerk-Zugriff
# Nur localhost (Standard, sicher)
-l 127.0.0.1
# Mehrere IPs
-l 127.0.0.1,192.168.1.10
# Alle Interfaces (unsicher!)
-l 0.0.0.0Nach Änderungen
systemctl restart memcachedGrundlegende Befehle
Verbinden
# Telnet
telnet localhost 11211
# Netcat
nc localhost 11211Daten speichern
# set key flags exptime bytes
set mykey 0 3600 5
hello
STORED
# add (nur wenn nicht existiert)
add newkey 0 3600 5
world
STORED
# replace (nur wenn existiert)
replace mykey 0 3600 6
hello2
STOREDDaten abrufen
# get
get mykey
VALUE mykey 0 6
hello2
END
# Mehrere Keys
get key1 key2 key3Daten löschen
delete mykey
DELETED
# Alle löschen
flush_all
OKStatistiken
stats
stats items
stats slabs
stats settingsPHP-Integration
PHP-Extension installieren
# Debian/Ubuntu
apt install php-memcached
# Prüfen
php -m | grep memcachedBasis-Verwendung
<?php
$memcached = new Memcached();
$memcached->addServer('localhost', 11211);
// Speichern
$memcached->set('user:1', ['name' => 'Max', 'email' => 'max@example.de'], 3600);
// Abrufen
$user = $memcached->get('user:1');
// Prüfen ob gefunden
if ($memcached->getResultCode() === Memcached::RES_NOTFOUND) {
echo "Nicht im Cache";
}
// Löschen
$memcached->delete('user:1');
?>Cache-Aside Pattern
<?php
class UserRepository {
private $memcached;
private $db;
public function __construct() {
$this->memcached = new Memcached();
$this->memcached->addServer('localhost', 11211);
$this->db = new PDO('mysql:host=localhost;dbname=app', 'user', 'pass');
}
public function getUser($id) {
$cacheKey = "user:$id";
// Versuche aus Cache
$user = $this->memcached->get($cacheKey);
if ($user !== false) {
return $user;
}
// Aus Datenbank laden
$stmt = $this->db->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user) {
// In Cache speichern (1 Stunde)
$this->memcached->set($cacheKey, $user, 3600);
}
return $user;
}
public function updateUser($id, $data) {
// Datenbank aktualisieren
$stmt = $this->db->prepare('UPDATE users SET name = ?, email = ? WHERE id = ?');
$stmt->execute([$data['name'], $data['email'], $id]);
// Cache invalidieren
$this->memcached->delete("user:$id");
}
}
?>Session-Storage
<?php
// php.ini
// session.save_handler = memcached
// session.save_path = "localhost:11211"
// Oder zur Laufzeit
ini_set('session.save_handler', 'memcached');
ini_set('session.save_path', 'localhost:11211');
session_start();
$_SESSION['user_id'] = 123;
?>Python-Integration
Installation
pip install pymemcacheVerwendung
from pymemcache.client import base
import json
# Verbinden
client = base.Client(('localhost', 11211))
# JSON-Serialisierung
def json_serializer(key, value):
if type(value) == str:
return value, 1
return json.dumps(value), 2
def json_deserializer(key, value, flags):
if flags == 1:
return value.decode('utf-8')
if flags == 2:
return json.loads(value.decode('utf-8'))
raise Exception("Unknown flags")
client = base.Client(
('localhost', 11211),
serializer=json_serializer,
deserializer=json_deserializer
)
# Speichern
client.set('user:1', {'name': 'Max', 'age': 30}, expire=3600)
# Abrufen
user = client.get('user:1')
print(user)
# Löschen
client.delete('user:1')Node.js-Integration
Installation
npm install memcachedVerwendung
const Memcached = require('memcached');
const memcached = new Memcached('localhost:11211');
// Speichern
memcached.set('key', 'value', 3600, (err) => {
if (err) console.error(err);
console.log('Gespeichert');
});
// Abrufen
memcached.get('key', (err, data) => {
if (err) console.error(err);
console.log(data);
});
// Mit Promises
const util = require('util');
const getAsync = util.promisify(memcached.get).bind(memcached);
const setAsync = util.promisify(memcached.set).bind(memcached);
async function example() {
await setAsync('user:1', { name: 'Max' }, 3600);
const user = await getAsync('user:1');
console.log(user);
}Verteilter Cache
Mehrere Server
<?php
$memcached = new Memcached();
$memcached->addServers([
['server1.example.de', 11211, 33], // Weight 33%
['server2.example.de', 11211, 33],
['server3.example.de', 11211, 34]
]);
// Consistent Hashing
$memcached->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
?>Failover
<?php
$memcached = new Memcached();
$memcached->setOptions([
Memcached::OPT_CONNECT_TIMEOUT => 100,
Memcached::OPT_RETRY_TIMEOUT => 1,
Memcached::OPT_DEAD_TIMEOUT => 10,
Memcached::OPT_REMOVE_FAILED_SERVERS => true
]);
?>Monitoring
memcached-tool
# Statistiken
memcached-tool localhost:11211 stats
# Slab-Info
memcached-tool localhost:11211 display
# Dump Keys
memcached-tool localhost:11211 dumpWichtige Metriken
# Via telnet
echo "stats" | nc localhost 11211
# Wichtige Werte
# get_hits / (get_hits + get_misses) = Hit Ratio
# bytes / limit_maxbytes = Memory Usage
# curr_connections = Aktive VerbindungenPrometheus
# memcached_exporter
docker run -d -p 9150:9150 \
prom/memcached-exporter \
--memcached.address=memcached:11211Cache-Strategien
Key-Naming
<?php
// Struktur: prefix:entity:id:version
$key = "app:user:123:v1";
// Mit Namespace für Invalidierung
$namespace = $memcached->get('user_namespace') ?: 1;
$key = "user:{$namespace}:123";
// Alle User-Cache invalidieren
$memcached->increment('user_namespace');
?>Cache Stampede Prevention
<?php
function getWithLock($key, $callback, $ttl = 3600) {
global $memcached;
$value = $memcached->get($key);
if ($value !== false) {
return $value;
}
// Lock setzen
$lockKey = "lock:$key";
if (!$memcached->add($lockKey, 1, 10)) {
// Warten und erneut versuchen
usleep(50000);
return getWithLock($key, $callback, $ttl);
}
// Wert berechnen
$value = $callback();
// Speichern und Lock freigeben
$memcached->set($key, $value, $ttl);
$memcached->delete($lockKey);
return $value;
}
?>Sicherheit
Netzwerk absichern
# Nur localhost
-l 127.0.0.1
# Mit Firewall
ufw allow from 192.168.1.0/24 to any port 11211SASL-Authentifizierung
# memcached.conf
-S # SASL aktivieren
# /etc/sasl2/memcached.conf
mech_list: plain
sasldb_path: /etc/memcached-sasldb2# Benutzer erstellen
saslpasswd2 -a memcached -c -f /etc/memcached-sasldb2 username<?php
$memcached = new Memcached();
$memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$memcached->setSaslAuthData('username', 'password');
$memcached->addServer('localhost', 11211);
?>Troubleshooting
Häufige Probleme
# Verbindung fehlgeschlagen
# → Service läuft?
systemctl status memcached
# → Port offen?
netstat -tlnp | grep 11211
# Memory voll
# → Stats prüfen
echo "stats" | nc localhost 11211 | grep bytes
# Evictions hoch
# → Mehr Memory oder kürzere TTLDebug-Modus
# Verbose starten
memcached -vv -m 64 -p 11211Zusammenfassung
| Befehl | Funktion | |--------|----------| | set | Wert speichern | | get | Wert abrufen | | delete | Wert löschen | | flush_all | Alles löschen | | stats | Statistiken |
| Parameter | Beschreibung | |-----------|--------------| | -m | Speicher in MB | | -p | Port | | -l | Listen-Adresse | | -c | Max. Verbindungen | | -t | Threads |
| Datei | Funktion | |-------|----------| | /etc/memcached.conf | Konfiguration | | /var/run/memcached/ | Runtime-Daten |
Fazit
Memcached ist ideal für einfaches, schnelles Caching. Die Multi-Threading-Architektur skaliert gut auf mehrere CPU-Kerne. Für komplexe Datenstrukturen oder Persistenz ist Redis besser geeignet. Die Integration in PHP, Python und Node.js ist unkompliziert. Für verteilte Setups sorgt Consistent Hashing für gleichmäßige Lastverteilung. Memcached bleibt die erste Wahl für reines Session- und Query-Caching.