Memcached ist ein leistungsstarkes In-Memory Key-Value-Store. Es beschleunigt Webanwendungen durch Caching von Datenbank-Abfragen, Sessions und berechneten Daten.

Warum Memcached?

Vorteile

- Extrem schnell (In-Memory)
- Einfaches Protokoll
- Horizontal skalierbar
- Bewährt (seit 2003)
- Geringer Ressourcenverbrauch

Memcached vs. Redis

| Feature | Memcached | Redis | |---------|-----------|-------| | Datentypen | Key-Value | Viele (Lists, Sets, etc.) | | Persistenz | Nein | Ja | | Replikation | Nein | Ja | | Komplexität | Einfach | Mittel | | Speichereffizienz | Besser | Gut | | Use Case | Caching | Caching + mehr |

Installation

Debian/Ubuntu

apt update
apt install memcached libmemcached-tools

# Status prüfen
systemctl status memcached

CentOS/RHEL

dnf install memcached

systemctl enable --now memcached

Version prüfen

memcached -h | head -1

Konfiguration

Hauptkonfiguration

# /etc/memcached.conf (Debian/Ubuntu)
# /etc/sysconfig/memcached (CentOS/RHEL)

Wichtige Optionen

# /etc/memcached.conf

# Speicher (MB)
-m 256

# Port
-p 11211

# Benutzer
-u memcache

# Binding (nur lokal!)
-l 127.0.0.1

# Max. Verbindungen
-c 1024

# Verbose-Logging (für Debugging)
# -v

# Max. Item-Größe (Standard: 1MB)
-I 2m

Produktions-Konfiguration

# /etc/memcached.conf

# Speicher großzügig bemessen
-m 512

# Nur lokal erreichbar
-l 127.0.0.1

# Standard-Port
-p 11211

# Mehr Verbindungen
-c 2048

# Als Daemon
-d

# Log-Datei
logfile /var/log/memcached.log

# Benutzer
-u memcache

# PID-Datei
-P /var/run/memcached/memcached.pid

# Größere Items erlauben
-I 4m

Änderungen übernehmen

systemctl restart memcached

Grundlegende Verwendung

telnet-Test

telnet localhost 11211
# Wert setzen (set key flags exptime bytes)
set test 0 300 11
Hello World
STORED

# Wert abrufen
get test
VALUE test 0 11
Hello World
END

# Wert löschen
delete test
DELETED

# Statistiken
stats
stats items
stats slabs

# Beenden
quit

memcached-tool

# Statistiken anzeigen
memcached-tool localhost:11211 stats

# Slab-Verteilung
memcached-tool localhost:11211 display

# Dump aller Keys
memcached-tool localhost:11211 dump

PHP-Integration

PHP-Extension installieren

# Debian/Ubuntu
apt install php-memcached

# Oder php-memcache (ältere Extension)
apt install php-memcache

# PHP-FPM neu starten
systemctl restart php8.2-fpm

Einfaches Beispiel

<?php
// Verbindung herstellen
$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);

// Wert setzen (Key, Value, Ablaufzeit in Sekunden)
$memcached->set('user_1', ['name' => 'Max', 'email' => 'max@example.com'], 3600);

// Wert abrufen
$user = $memcached->get('user_1');

if ($user !== false) {
    echo "Name: " . $user['name'];
} else {
    echo "Nicht im Cache";
}

// Wert löschen
$memcached->delete('user_1');

// Cache leeren
$memcached->flush();

Cache-Aside Pattern

<?php
class DatabaseCache
{
    private $memcached;
    private $pdo;
    private $ttl = 3600;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
        $this->memcached = new Memcached();
        $this->memcached->addServer('127.0.0.1', 11211);
    }

    public function getUser(int $id): ?array
    {
        $cacheKey = "user_{$id}";

        // Im Cache suchen
        $user = $this->memcached->get($cacheKey);

        if ($user !== false) {
            return $user;  // Cache-Hit
        }

        // Aus Datenbank laden
        $stmt = $this->pdo->prepare("SELECT * FROM users WHERE id = ?");
        $stmt->execute([$id]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($user) {
            // In Cache speichern
            $this->memcached->set($cacheKey, $user, $this->ttl);
        }

        return $user ?: null;
    }

    public function invalidateUser(int $id): void
    {
        $this->memcached->delete("user_{$id}");
    }
}

Session-Handler

// php.ini oder in Code
ini_set('session.save_handler', 'memcached');
ini_set('session.save_path', '127.0.0.1:11211');

session_start();
$_SESSION['user_id'] = 123;

Python-Integration

Installation

pip install pymemcache

Beispiel

from pymemcache.client import base

# Verbindung
client = base.Client(('127.0.0.1', 11211))

# Setzen
client.set('key', 'value', expire=3600)

# Abrufen
result = client.get('key')
print(result.decode('utf-8'))  # 'value'

# JSON speichern
import json

def json_serializer(key, value):
    if isinstance(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'))
    return value

client = base.Client(
    ('127.0.0.1', 11211),
    serializer=json_serializer,
    deserializer=json_deserializer
)

client.set('user', {'name': 'Max', 'age': 30})
user = client.get('user')
print(user['name'])  # 'Max'

WordPress mit Memcached

Plugin installieren

cd /var/www/wordpress/wp-content
wget https://raw.githubusercontent.com/memcached/memcached/master/plugins/wordpress/object-cache.php

wp-config.php

// Memcached-Server definieren
$memcached_servers = array(
    'default' => array(
        '127.0.0.1:11211'
    )
);

Alternativ: W3 Total Cache

Plugins → W3 Total Cache → General Settings
→ Object Cache: Memcached
→ Save

Laravel mit Memcached

Konfiguration

// config/cache.php

'memcached' => [
    'driver' => 'memcached',
    'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
    'sasl' => [
        env('MEMCACHED_USERNAME'),
        env('MEMCACHED_PASSWORD'),
    ],
    'options' => [
        // Memcached::OPT_CONNECT_TIMEOUT => 2000,
    ],
    'servers' => [
        [
            'host' => env('MEMCACHED_HOST', '127.0.0.1'),
            'port' => env('MEMCACHED_PORT', 11211),
            'weight' => 100,
        ],
    ],
],

.env

CACHE_DRIVER=memcached
MEMCACHED_HOST=127.0.0.1

Verwendung

// Cachen
Cache::put('key', 'value', $seconds);

// Abrufen
$value = Cache::get('key');

// Remember (abrufen oder berechnen)
$users = Cache::remember('users', 3600, function () {
    return DB::table('users')->get();
});

Verteiltes Caching

Mehrere Server

<?php
$memcached = new Memcached();

// Mehrere Server hinzufügen
$memcached->addServers([
    ['192.168.1.10', 11211, 33],  // 33% Gewichtung
    ['192.168.1.11', 11211, 33],
    ['192.168.1.12', 11211, 34],
]);

// Konsistentes Hashing aktivieren
$memcached->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

Netzwerk-Konfiguration

# /etc/memcached.conf

# Auf Netzwerk-Interface binden
-l 192.168.1.10

# ODER alle Interfaces (vorsichtig!)
# -l 0.0.0.0

Firewall

# UFW
ufw allow from 192.168.1.0/24 to any port 11211

Monitoring

Statistiken abfragen

echo "stats" | nc localhost 11211

Wichtige Metriken:

STAT curr_items 12345        # Aktuelle Items
STAT bytes 123456789         # Speicherverbrauch
STAT get_hits 1000000        # Cache-Hits
STAT get_misses 50000        # Cache-Misses
STAT evictions 100           # Verdrängte Items

Hit Rate berechnen

Hit Rate = get_hits / (get_hits + get_misses) * 100

Monitoring-Skript

#!/bin/bash
# memcached-stats.sh

STATS=$(echo "stats" | nc -w 1 localhost 11211)

HITS=$(echo "$STATS" | grep "get_hits" | awk '{print $3}')
MISSES=$(echo "$STATS" | grep "get_misses" | awk '{print $3}')
EVICTIONS=$(echo "$STATS" | grep "evictions" | awk '{print $3}')

if [ -n "$HITS" ] && [ -n "$MISSES" ]; then
    TOTAL=$((HITS + MISSES))
    if [ $TOTAL -gt 0 ]; then
        HITRATE=$(echo "scale=2; $HITS * 100 / $TOTAL" | bc)
        echo "Hit Rate: ${HITRATE}%"
    fi
fi

echo "Evictions: $EVICTIONS"

Prometheus-Exporter

# memcached_exporter installieren
docker run -d -p 9150:9150 \
    prom/memcached-exporter \
    --memcached.address=host.docker.internal:11211

Sicherheit

Nur lokal binden

# /etc/memcached.conf
-l 127.0.0.1

SASL-Authentifizierung

# /etc/memcached.conf
-S  # SASL aktivieren
# SASL-Benutzer erstellen
saslpasswd2 -a memcached -c username

Firewall

# Nur von bestimmten IPs
iptables -A INPUT -p tcp --dport 11211 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 11211 -j DROP

Troubleshooting

Verbindung testen

# Telnet
telnet localhost 11211

# Netcat
echo "stats" | nc localhost 11211

# PHP
php -r "var_dump((new Memcached())->addServer('127.0.0.1', 11211));"

Service läuft nicht

systemctl status memcached
journalctl -u memcached

# Manuell starten (Debug)
memcached -u memcache -m 64 -p 11211 -l 127.0.0.1 -vv

Hohe Eviction-Rate

# Mehr Speicher zuweisen
# /etc/memcached.conf
-m 512  # 512 MB

# Oder größere Items erlauben
-I 4m   # Max 4 MB pro Item

Cache wird nicht genutzt

// Verbindung prüfen
$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);

var_dump($memcached->getStats());
// Array mit Statistiken = OK
// false/empty = Problem

Zusammenfassung

| Befehl | Funktion | |--------|----------| | stats | Statistiken anzeigen | | set key 0 ttl bytes | Wert setzen | | get key | Wert abrufen | | delete key | Wert löschen | | flush_all | Cache leeren | | version | Version anzeigen |

| Metrik | Bedeutung | |--------|-----------| | get_hits | Cache-Treffer | | get_misses | Cache-Fehlschläge | | evictions | Verdrängte Items | | bytes | Speicherverbrauch |

Fazit

Memcached ist eine bewährte Caching-Lösung für Webanwendungen. Die einfache API und hohe Performance machen es ideal für Session-Storage und Datenbank-Caching. Für komplexere Anwendungsfälle mit Persistenz oder speziellen Datenstrukturen ist Redis die bessere Wahl. Achten Sie auf ausreichend Speicher und überwachen Sie die Hit-Rate für optimale Performance.