Arbeitsspeicher und Eviction
Clustron Zaris ist ein In-Memory-Store: Jeder Node hält seine Daten im RAM, und jeder Node ist durch eine Speichergrenze (Memory Ceiling) begrenzt. Dieser Artikel erklärt, wie diese Grenze funktioniert, was geschieht, wenn sich ein Node füllt, und wie die Eviction einen Node innerhalb seines Limits hält.
Der Store ist ein begrenzter Puffer
Ein Zaris-Node wächst nicht unbegrenzt. Jeder Node bilanziert fortlaufend die Größe der Daten, die er aktiv besitzt, und hält diese Summe unter einer konfigurierten Grenze. Die Bilanzierung ist nie optional — ein Node ist stets ein begrenzter Puffer, und konfigurieren können Sie nur die Größe der Grenze und das Verhalten des Nodes, wenn er sie erreicht.
Die Standardgrenze beträgt 1 GiB aktiv besessener Daten pro Node. Eine „unbegrenzte“ Einstellung gibt es bewusst nicht: Wenn Sie keine Grenze setzen, gilt der Default.
Die Grenze bezieht sich auf die Daten, die ein Node aktiv besitzt — die Primary-Kopien, die er bedient. Replikatkopien, die ein Node für andere Partitionen hält, werden separat erfasst und zählen nicht zur Zulassungsprüfung der Active-Owner-Grenze.
Was passiert, wenn sich ein Node füllt
Ein Node hält seine Grenze auf eine von zwei Arten ein, je nachdem, ob Eviction aktiviert ist:
| Modus | Verhalten an der Grenze | Ergebnis eines Schreibvorgangs, der sie überschreiten würde |
|---|---|---|
| Eviction aktiviert (Default) | Der Node verdrängt ältere Daten, um Platz zu schaffen | Der Schreibvorgang wird angenommen; andere Daten werden verdrängt |
| Eviction deaktiviert | Der Node lehnt neue Daten ab | Der Schreibvorgang wird mit KvStatus.CapacityExceeded abgelehnt |
Ein Zaris-Node verhält sich wie ein begrenzter Cache: Unter Speicherdruck verdrängt er Daten, um innerhalb der Grenze zu bleiben, sodass Schreibvorgänge weiter erfolgreich sind und die am wenigsten wertvollen Daten zuerst verworfen werden. Die Alternative — ein Store, der bei Erreichen der Kapazität neue Schreibvorgänge ablehnt, statt ältere Daten zu verwerfen — ist der unten beschriebene Modus ohne Eviction.
Im aktuellen Release läuft ein Node stets mit aktivierter Eviction und der LRU-Richtlinie. Der Modus ohne Eviction sowie die LFU- und TTL-aware-Richtlinien existieren in der Engine, sind aber noch nicht über die Konfiguration wählbar — die Speichergrenze (memory.maxSizeBytes) ist die Einstellung, die Sie steuern.
Eviction-Richtlinien
Ist Eviction aktiviert, entscheidet eine Richtlinie, welche Elemente zuerst verworfen werden. Im aktuellen Release ist die Richtlinie stets LRU — die übrigen unten aufgeführten Richtlinien beschreiben das Modell, sind aber noch nicht über die Konfiguration wählbar. Zaris zieht eine kleine Stichprobe von Kandidaten und verdrängt die mit der niedrigsten Bewertung, statt eine strikte globale Ordnung zu pflegen — derselbe stichprobenbasierte Ansatz, den Redis verwendet.
| Richtlinie | Verdrängt zuerst | Einsatz, wenn |
|---|---|---|
| LRU (Default) | Die am längsten nicht genutzten Elemente | Der Zugriff ist aktualitätsbetont — aktuelle Daten werden wahrscheinlich erneut gelesen |
| LFU | Die am seltensten genutzten Elemente | Ein stabiles Hot Set davon profitiert, gegenüber einmaligen Spitzen behalten zu werden |
| TTL-aware | Die Elemente, die ihrem TTL-Ablauf am nächsten sind | Die meisten Daten bereits eine TTL haben und Sie die natürliche Ablaufreihenfolge wünschen |
| Keine Eviction | Nichts — der Node lehnt stattdessen an der Kapazitätsgrenze ab | Sie nie wollen, dass Daten implizit verworfen werden |
Aktualität und Häufigkeit werden als näherungsweise, direkt am Element vermerkte Signale auf dem Lesepfad erfasst, sodass ihre Pflege fast nichts kostet und nie einen separaten Index erfordert.
Wie ein Eviction-Lauf funktioniert
Die Eviction wird von einer Hintergrundschleife gesteuert, nicht von jedem einzelnen Schreibvorgang. Die Schleife nutzt Hysterese — einen hohen Auslöser und ein niedrigeres Ziel — damit sie nicht fortwährend am Rand der Grenze feuert:
- Auslöser: Ein Lauf beginnt, wenn die aktive Nutzung über 80 % der Grenze steigt.
- Ziel: Einmal ausgelöst, läuft der Lauf weiter, bis wieder etwa 30 % der Grenze frei sind — das heißt, bis die Nutzung auf etwa 70 % sinkt.
- Taktung: Die Schleife wacht in einem festen Intervall auf (standardmäßig eine Sekunde) und zieht in jedem Zyklus eine begrenzte Stichprobe von Kandidatenelementen.
Da das Ziel nach der Eviction (70 %) strikt unter dem Auslöser (80 %) liegt, senkt ein Lauf die Nutzung in ein ruhiges Band, statt genau an dem Punkt zu stoppen, der ihn sofort erneut auslösen würde.
Das Größenlimit pro Element
Unabhängig von der Gesamtgrenze darf ein einzelnes Element eine maximale Elementgröße nicht überschreiten — standardmäßig 4 MiB. Dieses Limit wird bei jedem Schreibvorgang unabhängig vom Eviction-Modus geprüft: Ein übergroßer Value wird nie angenommen, und keine noch so große Eviction schafft dafür Platz. Ein Schreibvorgang, der das Limit überschreitet, wird mit KvStatus.ItemTooLarge abgelehnt.
Das schützt einen Node vor einem einzelnen pathologischen Value und hält die Bilanzierung pro Element günstig.
Kapazitätssignale in Ihrem Code behandeln
Beide Kapazitätsergebnisse erscheinen als typisierte Status im Ergebnis, das Sie ohnehin prüfen — sie sind keine Exceptions und voneinander unterscheidbar, sodass Sie auf jedes richtig reagieren können:
var result = await client.PutAsync("report:2026-07", payload);
if (!result.IsSuccess)
{
switch (result.Status)
{
case KvStatus.ItemTooLarge:
// The value itself is too big — split it or store a reference instead.
break;
case KvStatus.CapacityExceeded:
// The node is full and eviction is disabled — retry later or shed load.
break;
}
}
CapacityExceeded tritt nur im Modus ohne Eviction auf, der im aktuellen Release nicht wählbar ist, sodass Sie ihm normalerweise nicht begegnen — ein voller Node verdrängt unter der stets aktiven LRU-Richtlinie, statt abzulehnen. ItemTooLarge hingegen ist ein tatsächlich erreichbares Ergebnis und kann in jedem Modus auftreten.
Konfiguration
Die Speichergrenze des Nodes ist Teil der Store-Konfiguration, im Abschnitt memory:
{
"memory": {
"maxSizeBytes": 2147483648
}
}
Wird maxSizeBytes auf null gesetzt (oder weggelassen), gilt der Default von 1 GiB. Im aktuellen Release ist maxSizeBytes die einzige konfigurierbare Speichereinstellung: Die Eviction-Richtlinie (LRU), die Schwellenwerte für Auslöser/Ziel und das oben beschriebene Limit pro Element sind feste Defaults, keine Konfigurationsparameter. Das vollständige Speicherschema finden Sie in der Konfigurationsreferenz.
Was das für die Kapazitätsplanung bedeutet
Da jeder Node ein begrenzter Puffer ist, entspricht die Gesamtkapazität eines Stores ungefähr der Grenze pro Node multipliziert mit der Anzahl der Partitionen, die ein Node besitzt, angepasst um den Replikationsfaktor (Replikate halten zusätzliche Kopien). Ein Node betreibt heute den stets aktiven LRU-Cache. Dimensionieren Sie die Grenze daher passend zu Ihrem Working Set plus Reserve für das Eviction-Band; kalte Daten werden unter Druck verworfen, statt abgelehnt zu werden.