und gezielt beheben
Memory-Fragmentation entsteht, wenn der Allokator jemalloc mehr physischen Speicher belegt, als Redis für die eigentlichen Daten tatsächlich braucht, und lässt sich präzise über mem_fragmentation_ratio messen. Wer versteht, wie jemalloc Speicherblöcke verwaltet, kann Active Defrag gezielt konfigurieren und weiß, wann ein kontrollierter Neustart die bessere Wahl gegenüber Defragmentierung im laufenden Betrieb ist.
Inhaltsverzeichnis
- 1. Was Memory-Fragmentation eigentlich bedeutet
- 2. mem_fragmentation_ratio richtig lesen
- 3. Wie jemalloc Speicher tatsächlich allokiert
- 4. Typische Ursachen für steigende Fragmentation
- 5. Active Defrag: Mechanik und Konfiguration
- 6. Active-Defrag-Parameter im Detail abstimmen
- 7. Fragmentation überwachen und Alarme setzen
- 8. Defrag versus Neustart: die richtige Entscheidung treffen
- 9. Typische Fehler bei der Fragmentation-Behebung
- 10. Zusammenfassung
- 11. FAQ
1. Was Memory-Fragmentation eigentlich bedeutet
Memory-Fragmentation beschreibt die Differenz zwischen dem physischen Speicher, den das Betriebssystem einem Redis-Prozess zuweist, und dem Speicher, den Redis tatsächlich für die gespeicherten Daten benötigt. Diese Differenz entsteht nicht durch einen Fehler in Redis selbst, sondern durch die Funktionsweise des zugrunde liegenden Speicher-Allokators: Wenn Objekte unterschiedlicher Größe wiederholt angelegt und wieder freigegeben werden, entstehen Lücken im Speicher, die zu klein für neue, größere Objekte sind, aber nicht zusammengelegt werden, solange sie nicht zusammenhängend frei liegen.
Der Effekt ist real und messbar: Ein Redis-Prozess mit 10 GB tatsächlichem Datenbestand kann durchaus 15 GB oder mehr physischen Speicher vom Betriebssystem belegen, ohne dass ein Speicherleck im klassischen Sinn vorliegt. Diese zusätzlichen 5 GB sind nicht verloren, sondern liegen als fragmentierte, für den Allokator schwer wiederverwendbare Blöcke vor. Für den Betrieb bedeutet das konkret höhere RAM-Anforderungen, als der reine Datenbestand vermuten lässt, was bei der Kapazitätsplanung häufig übersehen wird.
Wichtig ist die Abgrenzung zu einem echten Speicherleck: Bei Fragmentation bleibt der von Redis selbst gemeldete used_memory-Wert stabil oder wächst proportional zum Datenbestand, während der vom Betriebssystem tatsächlich belegte used_memory_rss-Wert überproportional steigt. Ein echtes Leck hingegen zeigt sich durch kontinuierlich wachsenden used_memory, unabhängig vom tatsächlichen Datenvolumen. Diese Unterscheidung ist der erste Schritt jeder Diagnose.
2. mem_fragmentation_ratio richtig lesen
Der zentrale Messwert für Memory-Fragmentation ist mem_fragmentation_ratio, abrufbar über redis-cli INFO memory. Er berechnet sich als Quotient aus used_memory_rss, dem tatsächlich vom Betriebssystem zugewiesenen physischen Speicher, und used_memory, dem von Redis selbst als benötigt gemeldeten Speicher. Ein Wert von 1.0 würde bedeuten, dass beide Werte exakt übereinstimmen, praktisch kommt das kaum vor.
Werte zwischen 1.0 und etwa 1.5 gelten allgemein als normal und unbedenklich, weil ein moderater Overhead durch Allokator-Metadaten und übliche Fragmentierungseffekte unvermeidbar ist. Werte deutlich über 1.5, insbesondere über 2.0, deuten auf signifikante Fragmentation hin, die Aufmerksamkeit verdient. Besonders aufschlussreich ist nicht der absolute Wert an einem einzelnen Zeitpunkt, sondern der Trend über Zeit: Ein stetig steigender mem_fragmentation_ratio, korreliert mit bestimmten Workload-Mustern wie häufigen Größenänderungen von Werten, ist ein deutlich verlässlicheres Signal als eine einmalige Momentaufnahme.
Ein oft übersehener Sonderfall ist ein mem_fragmentation_ratio unter 1.0. Das bedeutet, dass Redis mehr Speicher als benötigt anfordert, aber Teile davon vom Betriebssystem in den Swap-Speicher ausgelagert wurden, ein deutlich ernsteres Problem als reguläre Fragmentation, weil Swap-Zugriffe die Latenz von Redis-Operationen um Größenordnungen erhöhen können. Ein Wert unter 1.0 sollte daher sofort als Alarmsignal für unzureichenden physischen Speicher behandelt werden.
# Read the core fragmentation metrics
redis-cli INFO memory | grep -E "used_memory:|used_memory_human|used_memory_rss|mem_fragmentation_ratio|mem_allocator"
# Example output:
# used_memory:10737418240 (10.0 GB actually needed by Redis)
# used_memory_human:10.00G
# used_memory_rss:16106127360 (15.0 GB physically resident)
# mem_fragmentation_ratio:1.50
# mem_allocator:jemalloc-5.3.0
# A ratio below 1.0 signals swapping, not fragmentation - check immediately
redis-cli INFO memory | grep -E "mem_fragmentation_ratio"
free -h
3. Wie jemalloc Speicher tatsächlich allokiert
Redis nutzt standardmäßig jemalloc als Speicher-Allokator, statt des Standard-glibc-Allokators, gerade weil jemalloc für genau dieses Fragmentation-Problem entwickelt wurde. jemalloc organisiert Speicher in sogenannten Size Classes: fest definierte Größenklassen, in die jede Allokation aufgerundet wird. Eine Anfrage nach 130 Bytes landet beispielsweise in einer Size Class von 144 Bytes, statt exakt 130 Bytes zu allokieren, was internen Overhead erzeugt, aber die Wiederverwendung freigegebener Blöcke innerhalb derselben Size Class massiv vereinfacht.
Diese Size-Class-Strategie reduziert externe Fragmentation erheblich, weil freigegebene Blöcke einer Größenklasse direkt für neue Allokationen derselben Klasse wiederverwendet werden können, ohne dass der Allokator komplexe Speicherbereiche zusammenlegen muss. Das Problem verlagert sich dadurch von externer zu interner Fragmentation: Speicher, der innerhalb einer zu großen Size Class für einen kleineren tatsächlichen Wert reserviert bleibt. Bei Workloads mit stark schwankenden Wertgrößen, insbesondere bei häufigem Überschreiben von Strings mit unterschiedlicher Länge, kann diese interne Fragmentation dennoch spürbar werden.
jemalloc organisiert Speicher zusätzlich in Arenas, unabhängige Speicherbereiche, die parallele Allokationen aus mehreren Threads ohne gegenseitige Sperren ermöglichen. Für Redis, das primär single-threaded arbeitet, ist die Multi-Arena-Eigenschaft weniger relevant als für stark parallele Anwendungen, aber sie beeinflusst dennoch, wie Speicher intern organisiert und beim Freigeben tatsächlich an das Betriebssystem zurückgegeben wird, was wiederum den gemessenen mem_fragmentation_ratio beeinflusst.
# Ask Redis for a human-readable memory diagnosis
redis-cli MEMORY DOCTOR
# "High allocator fragmentation" or "Peak memory: OK" etc.
# Inspect allocator-level stats directly (jemalloc-specific)
redis-cli MEMORY STATS | grep -E "allocator.allocated|allocator.active|allocator.resident"
# allocator.allocated -> bytes jemalloc has handed out to Redis
# allocator.active -> bytes in active jemalloc pages (includes internal frag)
# allocator.resident -> bytes physically resident (includes unreturned pages)
4. Typische Ursachen für steigende Fragmentation
Der häufigste Auslöser für steigende Memory-Fragmentation ist ein Workload mit häufigen Größenänderungen bestehender Werte, etwa wenn ein String-Wert wiederholt mit unterschiedlich langem Inhalt überschrieben wird. Jede Größenänderung kann eine neue Allokation in einer anderen Size Class erfordern, während der alte Speicherblock freigegeben wird, aber möglicherweise nicht sofort für andere Zwecke wiederverwendet werden kann, wenn keine passende neue Allokation derselben Größe folgt.
Ein zweiter häufiger Auslöser ist eine hohe TTL-Churn-Rate: viele Keys mit kurzer Lebensdauer, die kontinuierlich erstellt und durch Expiration wieder gelöscht werden. Bei sehr hoher Rate kann der Allokator nicht schnell genug hinterherkommen, zusammenhängende freie Bereiche zu identifizieren und zusammenzulegen, was die Fragmentation über die Zeit ansteigen lässt, selbst wenn der Nettodatenbestand stabil bleibt.
Ein dritter, seltener diskutierter Faktor ist ein großzügig dimensioniertes maxmemory in Kombination mit einer aggressiven Eviction-Policy. Wenn Redis häufig nahe an der Speichergrenze operiert und ständig Keys evictet, um Platz für neue zu schaffen, entsteht ein permanentes Muster aus Freigeben und Neuallozieren, das die Fragmentation strukturell begünstigt, verglichen mit einem Setup mit ausreichend Headroom zwischen tatsächlichem Datenbestand und konfiguriertem Limit.
5. Active Defrag: Mechanik und Konfiguration
Seit Redis 4 existiert mit Active Defrag ein eingebauter Mechanismus, der fragmentierte Speicherblöcke im laufenden Betrieb reorganisiert, ohne dass ein Neustart nötig ist. Aktiviert über activedefrag yes, läuft Active Defrag als Hintergrundprozess, der zyklisch Keys prüft, ihre aktuelle Speicherposition mit einer idealeren Position vergleicht und bei signifikanter Verbesserung den Wert an die neue Position verschiebt, während der alte, fragmentierte Speicher freigegeben wird.
Der entscheidende Designaspekt von Active Defrag ist die inkrementelle, ressourcenschonende Arbeitsweise: Statt den kompletten Datenbestand in einem Rutsch zu reorganisieren, was den Hauptprozess blockieren würde, arbeitet Active Defrag in kleinen Zeitscheiben zwischen der Verarbeitung regulärer Client-Kommandos. Dadurch bleibt die Latenz für reguläre Operationen weitgehend unbeeinflusst, während die Fragmentation über einen längeren Zeitraum graduell sinkt, statt in einem einzigen, potenziell störenden Vorgang.
# redis.conf - Enable and configure Active Defrag
# Enable the background defragmentation process
activedefrag yes
# Minimum fragmentation ratio before defrag starts working
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
# Maximum fragmentation ratio: defrag runs at full configured effort
active-defrag-threshold-upper 100
# CPU usage bounds for the defrag cycle (percent of one core)
active-defrag-cycle-min 5
active-defrag-cycle-max 75
6. Active-Defrag-Parameter im Detail abstimmen
active-defrag-threshold-lower definiert, ab welchem Fragmentation-Prozentsatz Active Defrag überhaupt zu arbeiten beginnt, standardmäßig 10 Prozent über dem theoretischen Idealwert. Unterhalb dieser Schwelle bleibt Active Defrag inaktiv, weil der Aufwand einer Reorganisation den Nutzen bei geringer Fragmentation nicht rechtfertigt. active-defrag-threshold-upper definiert den Punkt, ab dem Active Defrag mit maximaler konfigurierter Intensität arbeitet, weil die Fragmentation dann als kritisch genug gilt, um mehr Ressourcen zu rechtfertigen.
Die beiden CPU-Parameter active-defrag-cycle-min und active-defrag-cycle-max begrenzen den Anteil einer CPU-Kernzeit, den Active Defrag beanspruchen darf, als unterer und oberer Prozentsatz. Ein zu niedriger active-defrag-cycle-max-Wert lässt Defragmentierung bei stark fragmentiertem Speicher unnötig langsam voranschreiten, ein zu hoher Wert kann spürbare Latenz-Auswirkungen auf reguläre Client-Anfragen haben, weil Defrag und reguläre Kommandos um dieselbe CPU-Zeit konkurrieren.
active-defrag-ignore-bytes verhindert, dass Active Defrag bei sehr kleinen absoluten Speichermengen aktiv wird, selbst wenn der prozentuale Fragmentation-Wert hoch erscheint. Bei einem winzigen Datenbestand von wenigen Megabyte kann ein hoher Prozentwert trotzdem eine vernachlässigbare absolute Speichermenge bedeuten, weshalb dieser Schwellenwert unnötige Defrag-Zyklen bei irrelevanten Datenmengen vermeidet.
| mem_fragmentation_ratio | Einschätzung | Empfohlene Maßnahme |
|---|---|---|
| unter 1.0 | Swapping, kritisch | Sofort physischen Speicher erhöhen oder maxmemory senken |
| 1.0 bis 1.5 | Normal | Keine Aktion nötig, regulär überwachen |
| 1.5 bis 2.0 | Erhöht | activedefrag aktivieren, Trend beobachten |
| über 2.0 | Signifikant | Active Defrag prüfen, Neustart in Wartungsfenster erwägen |
7. Fragmentation überwachen und Alarme setzen
Kontinuierliches Monitoring von mem_fragmentation_ratio gehört in jedes produktive Redis-Setup, idealerweise mit Alarmierung bei Überschreiten definierter Schwellenwerte über einen anhaltenden Zeitraum, nicht bei einer einzelnen Momentaufnahme, die durch kurzfristige Lastspitzen verzerrt sein kann. Ein Alarm bei einmaligem Überschreiten von 1.5 für wenige Sekunden erzeugt unnötiges Rauschen, während ein anhaltend hoher Wert über mehrere Stunden ein echtes betriebliches Signal darstellt.
Zusätzlich zu mem_fragmentation_ratio lohnt sich die Beobachtung von allocator_frag_ratio, das seit neueren Redis-Versionen zwischen jemalloc-interner Fragmentation und der durch Prozess-Overhead insgesamt gemessenen RSS-Differenz unterscheidet. Diese feinere Aufschlüsselung hilft, zwischen einem tatsächlichen jemalloc-Fragmentation-Problem und anderen Ursachen für erhöhten RSS-Verbrauch, etwa Fork-bedingtem Copy-on-Write während eines BGSAVE, zu unterscheiden, was sonst fälschlich als reguläre Fragmentation interpretiert werden könnte.
#!/usr/bin/env bash
# check_fragmentation.sh - Alert on sustained high fragmentation
set -euo pipefail
RATIO=$(redis-cli INFO memory | grep mem_fragmentation_ratio | cut -d: -f2 | tr -d '\r')
THRESHOLD=1.5
if (( $(echo "$RATIO < 1.0" | bc -l) )); then
echo "[CRITICAL] Fragmentation ratio ${RATIO} below 1.0, possible swapping" >&2
exit 2
fi
if (( $(echo "$RATIO > $THRESHOLD" | bc -l) )); then
echo "[WARN] Fragmentation ratio ${RATIO} exceeds ${THRESHOLD}" >&2
exit 1
fi
echo "[OK] Fragmentation ratio: ${RATIO}"
8. Defrag versus Neustart: die richtige Entscheidung treffen
Active Defrag löst nicht jedes Fragmentation-Problem vollständig. Bei extremer, langjährig aufgebauter Fragmentation, etwa nach Monaten wechselhafter Workloads ohne jemals einen Neustart, kann Active Defrag zwar Verbesserungen erzielen, aber unter Umständen nicht bis auf ein ideales Niveau reduzieren, weil bestimmte Speicherstrukturen mit dem inkrementellen Ansatz nur begrenzt reorganisierbar sind. In solchen Fällen bleibt ein kontrollierter Neustart, bei dem Redis den Datenbestand komplett neu aus einer RDB- oder AOF-Datei lädt und frischen, unfragmentierten Speicher belegt, die zuverlässigere Lösung.
Die Entscheidung zwischen Active Defrag und Neustart hängt vom akzeptablen Wartungsfenster ab: Active Defrag arbeitet ohne Downtime, aber graduell über Stunden bis Tage, abhängig von der konfigurierten CPU-Intensität. Ein Neustart ist sofort wirksam, erfordert aber ein Wartungsfenster oder ein Failover auf eine Replica, um Downtime zu vermeiden. Für Setups mit Replikation ist ein rollierender Neustart, erst die Replica, dann Failover, dann den ehemaligen Primary neu starten, häufig der pragmatischste Weg, um Fragmentation ohne spürbare Downtime vollständig zu beseitigen.
#!/usr/bin/env bash
# rolling_restart_defrag.sh - Clear fragmentation without downtime
set -euo pipefail
REPLICA_HOST="redis-replica-01"
PRIMARY_HOST="redis-primary-01"
echo "Step 1: restart the replica (loads a fresh, defragmented copy)"
ssh "$REPLICA_HOST" "systemctl restart redis"
sleep 10
echo "Step 2: promote the replica to primary"
redis-cli -h "$REPLICA_HOST" REPLICAOF NO ONE
echo "Step 3: point application traffic to the new primary (external step)"
echo "Step 4: restart the old primary, now safe to reload as fresh replica"
ssh "$PRIMARY_HOST" "systemctl restart redis"
redis-cli -h "$PRIMARY_HOST" REPLICAOF "$REPLICA_HOST" 6379
echo "[OK] Rolling restart complete, fragmentation cleared on both nodes"
Mironsoft
Redis-Betrieb, Memory-Tuning und Kapazitätsplanung
Speicherbedarf im Griff statt Überraschungen bei Fragmentation?
Wir analysieren eure mem_fragmentation_ratio-Trends, stimmen Active-Defrag-Parameter auf euren Workload ab und planen rollierende Neustart-Strategien für nachhaltig stabilen Speicherverbrauch.
Memory-Diagnose
Fragmentation von echten Speicherlecks zuverlässig unterscheiden
Active-Defrag-Tuning
Threshold- und CPU-Parameter an euren Workload anpassen
Kapazitätsplanung
Realistischen RAM-Bedarf inklusive Fragmentation-Overhead kalkulieren
9. Typische Fehler bei der Fragmentation-Behebung
Ein häufiger Fehler ist, activedefrag mit maximalen CPU-Werten zu aktivieren, ohne den Effekt auf die Latenz regulärer Anfragen vorher zu messen. Auf Instanzen mit ohnehin hoher CPU-Auslastung kann ein zu aggressiv konfiguriertes Active Defrag spürbare Latenz-Spitzen erzeugen, die den ursprünglichen Zweck, stabile Performance, konterkarieren. Eine schrittweise Erhöhung von active-defrag-cycle-max unter Beobachtung der Latenz ist der sicherere Weg als ein sofortiger Sprung auf hohe Werte.
Ein zweiter Fehler ist, einen hohen mem_fragmentation_ratio vorschnell als Speicherleck zu interpretieren und in Panik einen ungeplanten Neustart durchzuführen, ohne vorher zwischen Fragmentation und echtem Leck zu unterscheiden. Diese Verwechslung führt zu unnötiger Downtime, während das eigentliche Problem, sofern es tatsächlich ein Leck ist, durch den Neustart nur temporär kaschiert, aber nicht behoben wird und typischerweise erneut auftritt.
Ein dritter Fehler betrifft die Kapazitätsplanung: Wird maxmemory exakt auf die Größe des erwarteten Datenbestands gesetzt, ohne Headroom für Fragmentation-Overhead einzuplanen, kann Redis unter Speicherdruck geraten, obwohl der reine Datenbestand innerhalb des Limits liegt, weil der tatsächliche RSS-Verbrauch durch Fragmentation deutlich höher ausfällt als used_memory allein.
10. Zusammenfassung
Memory-Fragmentation ist die Differenz zwischen physisch belegtem und tatsächlich benötigtem Speicher, gemessen über mem_fragmentation_ratio. Werte zwischen 1.0 und 1.5 sind normal, Werte unter 1.0 signalisieren kritisches Swapping, Werte über 2.0 rechtfertigen aktives Eingreifen. Der Allokator jemalloc reduziert externe Fragmentation durch Size Classes, verschiebt das Problem aber teilweise zu interner Fragmentation bei stark schwankenden Wertgrößen.
Active Defrag, aktiviert über activedefrag yes, reorganisiert fragmentierten Speicher im laufenden Betrieb ressourcenschonend, ohne Downtime, aber graduell über Zeit. Bei extremer, langjähriger Fragmentation bleibt ein kontrollierter, idealerweise rollierender Neustart über eine Replica die zuverlässigere Lösung. Kontinuierliches Monitoring mit Alarmierung bei anhaltend hohen Werten, statt einzelner Momentaufnahmen, ist die Grundlage jeder nachhaltigen Memory-Fragmentation-Strategie.
Memory-Fragmentation verstehen und beheben: Das Wichtigste auf einen Blick
Messwert
mem_fragmentation_ratio: 1.0-1.5 normal, unter 1.0 kritisches Swapping, über 2.0 signifikant.
Ursache
jemalloc-Size-Classes plus häufige Größenänderungen von Werten und hohe TTL-Churn-Rate.
Active Defrag
activedefrag yes mit abgestimmten Threshold- und CPU-Parametern, ohne Downtime.
Bei Extremfällen
Rollierender Neustart über Replica-Failover für vollständige Bereinigung ohne Downtime.