Caching-Strategien: Lazy Loading und Write-Through
Implementieren Sie Lazy Loading, um den Cache bei einem Cache-Miss zu befüllen, und Write-Through, um den Cache bei jedem Datenbank-Schreibvorgang konsistent zu halten.
Caching-Strategien: Lazy Loading und Write-Through ist eine kostenlose Cloud & IT Cert Prep-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Cloud & IT Cert Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Cloud & IT Cert Prep-Kurs umfasst insgesamt 4 Lektionen.
Warum Caching-Strategien wichtig sind
Wenn Sie einen Cache zwischen Ihre Anwendung und die Datenbank schalten, benötigen Sie eine Caching-Strategie – eine Reihe von Regeln, die festlegen, wann Daten in den Cache geschrieben, aus dem Cache gelesen und aus dem Cache entfernt werden. Die Wahl der falschen Strategie führt entweder zu veralteten Daten (der Cache gibt überholte Werte zurück), zu Cache Misses bei einem kalten Cache (der Cache ist leer und jede Anfrage greift auf die Datenbank zu) oder zu einem Cache Stampede (viele gleichzeitige Anfragen nach demselben fehlenden Schlüssel greifen gleichzeitig auf die Datenbank zu). Die beiden grundlegenden Strategien sind Lazy Loading und Write-Through.
Lazy Loading (Cache-Aside): Funktionsweise
Lazy Loading (auch Cache-Aside genannt) ist das am häufigsten verwendete Caching-Muster. Die Anwendung prüft zuerst den Cache. Bei einem Cache Hit werden die Daten direkt aus dem Cache zurückgegeben – der schnelle Pfad. Bei einem Cache Miss ruft die Anwendung die Daten aus der Datenbank ab, schreibt das Ergebnis mit einer TTL in den Cache und gibt es an den Aufrufer zurück. Der Cache wird nur mit tatsächlich angeforderten Daten gefüllt – daher „lazy“. Bei der nächsten Anfrage nach demselben Schlüssel befinden sich die Daten im Cache.
# Lazy loading pattern (Python with redis-py)
def get_user(user_id, redis_client, db):
cache_key = f'user:{user_id}'
# 1. Check cache
cached = redis_client.get(cache_key)
if cached:
return json.loads(cached) # Cache HIT
# 2. Cache MISS: fetch from DB
user = db.query('SELECT * FROM users WHERE id = %s', user_id)
# 3. Populate cache with TTL of 300 seconds
redis_client.setex(cache_key, 300, json.dumps(user))
return userLazy Loading: Vorteile
Lazy Loading bietet drei wesentliche Vorteile: Nur angeforderte Daten werden zwischengespeichert – der Cache wird nicht mit Daten gefüllt, die niemand liest, sodass der Speicher effizient genutzt wird. Ein kalter Cache legt die Anwendung nicht lahm – bei Cache Misses greift die Anwendung auf die Datenbank zurück. Selbst wenn ElastiCache neu gestartet wird oder ein Knoten ausfällt, funktioniert die Anwendung daher weiterhin, wenn auch mit höherer Latenz. Der Cache ist mit der Datenbank immer letztendlich konsistent, da veraltete Daten über die TTL ablaufen, selbst wenn Aktualisierungen übersehen wurden.
Lazy Loading: Nachteile
Lazy Loading hat drei wesentliche Nachteile: Cache Misses sind kostspielig – im Vergleich zu einem Cache Hit sind drei Vorgänge erforderlich (Cache-Prüfung, Datenbanklesevorgang und Schreiben in den Cache), was bei kalten Anfragen zu höherer Latenz führt. Veraltete Daten – nach einer Aktualisierung der Datenbank liefert der Cache weiterhin den alten Wert, bis die TTL abläuft oder der Schlüssel explizit invalidiert wird (Konsistenzfenster des Caches). Cache Stampede – wenn ein häufig verwendeter Schlüssel abläuft, erleben viele gleichzeitige Anfragen einen Cache Miss und greifen gleichzeitig auf die Datenbank zu, was diese möglicherweise überlastet.
# Mitigating cache stampede with a probabilistic early expiration
# (Refresh the key before it expires to avoid simultaneous misses)
def get_with_stampede_protection(key, redis_client, db_fetch_fn, ttl=300):
value = redis_client.get(key)
ttl_remaining = redis_client.ttl(key)
# Probabilistically refresh before expiry
if value is None or (ttl_remaining < 30 and random.random() < 0.1):
value = db_fetch_fn()
redis_client.setex(key, ttl, json.dumps(value))
return json.loads(value)Write-Through: Funktionsweise
Bei der Write-Through-Strategie wird jeder Schreibvorgang in der Datenbank gleichzeitig auch im Cache ausgeführt. Die Anwendung schreibt den Wert im Rahmen desselben Vorgangs sowohl in den Cache als auch in die Datenbank (oder die Datenbank löst eine Aktualisierung des Caches aus). Der Cache ist dadurch immer mit der Datenbank synchron – es gibt kein Zeitfenster mit veralteten Daten. Write-Through stellt sicher, dass die Daten im Cache immer aktuell sind, sodass nachfolgende Lesevorgänge für kürzlich geschriebene Daten stets Cache Hits sind.
# Write-through pattern (Python)
def update_user(user_id, user_data, redis_client, db):
# 1. Write to database FIRST
db.execute('UPDATE users SET name=%s WHERE id=%s',
(user_data['name'], user_id))
# 2. Update cache immediately (write-through)
cache_key = f'user:{user_id}'
redis_client.setex(cache_key, 3600, json.dumps(user_data))
return user_data
# Every read is now a cache hit for recently updated dataWrite-Through: Vorteile
Vorteile von Write-Through: Cache-Daten sind immer aktuell – es gibt keine veralteten Daten, da der Cache bei jedem Schreibvorgang aktualisiert wird. Lesevorgänge sind immer schnell – häufig verwendete Daten, die regelmäßig geschrieben werden, befinden sich stets im Cache. Kein Cache Stampede bei Lesevorgängen – da die Daten vor dem Lesen vorab im Cache gespeichert werden, gibt es für kürzlich geschriebene Daten keine Cache Misses bei einem kalten Cache. Diese Strategie eignet sich ideal für leseintensive Workloads mit häufigen Aktualisierungen, bei denen die Aktualität der Daten entscheidend ist, beispielsweise für Produktkataloge, Preissysteme oder Caches für Benutzerprofile.
Write-Through: Nachteile
Nachteile von Write-Through: Schreib-Overhead – jeder Schreibvorgang umfasst zwei Operationen (Datenbank und Cache), wodurch sich die Latenz von Schreibvorgängen erhöht. Cache-Verschmutzung – Daten werden auch dann zwischengespeichert, wenn sie nie wieder gelesen werden (einmal geschrieben, nie angefordert), wodurch Cache-Speicher verschwendet wird. Ein Neustart des Caches führt zu einem kalten Cache – beim Neustart des Cache-Clusters gehen alle proaktiv geschriebenen Daten verloren, und der Cache muss durch Schreibvorgänge oder einen Cache-Warm-up-Prozess neu gefüllt werden. Kombinieren Sie Write-Through mit einer TTL, um ein unbeschränktes Wachstum selten gelesener Cache-Daten zu verhindern.
Lazy Loading und Write-Through kombinieren
In der Praxis kombinieren viele Produktionssysteme beide Strategien: Verwenden Sie Write-Through für häufig aktualisierte und häufig gelesene Daten (beispielsweise Benutzersitzungen oder aktuelle Preise) und Lazy Loading für selten aktualisierte, aber häufig gelesene Daten (beispielsweise Produktbeschreibungen oder Artikelinhalte). Legen Sie für beide geeignete TTLs fest: Write-Through-Schlüssel erhalten eine lange TTL, da die Daten stets aktuell sind; Lazy-Loading-Schlüssel erhalten eine kürzere TTL, um das Zeitfenster für veraltete Daten zu begrenzen. Dieser hybride Ansatz maximiert die Cache-Trefferquote und minimiert gleichzeitig die Veraltung der Daten.
# Hybrid: write-through for sessions, lazy loading for product data
# Write-through for session data (always fresh, critical)
def save_session(session_id, data, redis_client, db):
db.upsert('sessions', session_id, data)
redis_client.setex(f'session:{session_id}', 3600, json.dumps(data))
# Lazy loading for product catalog (infrequent updates OK)
def get_product(product_id, redis_client, db):
cached = redis_client.get(f'product:{product_id}')
if cached:
return json.loads(cached)
product = db.query('SELECT * FROM products WHERE id=%s', product_id)
redis_client.setex(f'product:{product_id}', 86400, json.dumps(product))
return productGrundsätze für das TTL-Design
Die Time-to-Live (TTL) zwischengespeicherter Daten bestimmt das maximale Zeitfenster für veraltete Daten und den Speicherbedarf des Caches. Legen Sie TTLs anhand der folgenden Kriterien fest: Häufigkeit der Datenaktualisierung (Sitzungsdaten ändern sich häufig → kurze TTL; statische Inhalte ändern sich selten → lange TTL), Toleranz gegenüber veralteten Daten (Finanzkurse → sehr kurz; Blogbeitragstexte → Stunden oder Tage) und verfügbare Cache-Kapazität (wenig Speicher → kürzere TTL, damit veraltete Daten schneller entfernt werden). Legen Sie immer eine TTL fest – speichern Sie Daten niemals ohne Ablaufzeit zwischen, da sich der Cache sonst letztendlich mit veralteten Daten füllt.
# TTL examples by data type
# API rate limit counter: 60 seconds
redis_client.setex(f'ratelimit:{ip}', 60, count)
# User session: 30 minutes
redis_client.setex(f'session:{id}', 1800, json.dumps(session))
# Product catalog: 24 hours
redis_client.setex(f'product:{id}', 86400, json.dumps(product))
# Stock price: 10 seconds
redis_client.setex(f'price:{symbol}', 10, price)
# Static site content: 7 days
redis_client.setex(f'page:{slug}', 604800, html_content)Cache-Invalidierung bei Aktualisierungen
Statt sich ausschließlich auf den Ablauf der TTL zu verlassen, können Sie Cache-Schlüssel explizit invalidieren (löschen), wenn sich die zugrunde liegenden Daten ändern. Dadurch wird das Zeitfenster für veraltete Daten vollständig beseitigt. Häufige Muster sind: Delete-on-Write (den Cache-Schlüssel nach jeder Datenbankaktualisierung löschen – der nächste Lesevorgang füllt ihn über Lazy Loading erneut) und ereignisgesteuerte Invalidierung (DynamoDB Streams oder die Änderungsaufzeichnung von RDS lösen eine Lambda-Funktion aus, die betroffene Schlüssel löscht). Die Cache-Invalidierung gehört zu den schwierigsten Problemen in verteilten Systemen; je einfacher die Invalidierungslogik ist, desto zuverlässiger ist Ihr Cache.
# Delete-on-write invalidation pattern
def update_product(product_id, new_data, redis_client, db):
# Update the database
db.execute('UPDATE products SET ... WHERE id=%s', (product_id,))
# Invalidate the cache key
redis_client.delete(f'product:{product_id}')
# Also invalidate any list/search caches that may include this product
redis_client.delete('products:list:page:1')
redis_client.delete(f'products:category:{new_data["category_id"]}')
# Next read will trigger lazy loading with fresh dataWrite-Behind-(Write-Back)-Caching
Ein weniger verbreitetes, aber leistungsfähiges Muster ist Write-Behind (Write-Back): Die Anwendung schreibt nur in den Cache, und der Cache überträgt die Daten asynchron im Hintergrund in die Datenbank. Dies ermöglicht extrem schnelle Schreibvorgänge (ausschließlich im Arbeitsspeicher), birgt jedoch das Risiko eines Datenverlusts, wenn der Cache vor der Übertragung ausfällt. Write-Behind eignet sich für Schreibvorgänge mit hoher Frequenz und hohem Volumen, bei denen die Daten rekonstruiert werden können oder kleine Verluste akzeptabel sind – beispielsweise für Trefferzähler, Analyseereignisse oder Aktualisierungen von Spielepunktständen. ElastiCache unterstützt Write-Behind nicht nativ; das Muster muss auf Anwendungsebene implementiert werden.
# Write-behind pattern: write to cache, flush to DB asynchronously
# Application writes:
# redis_client.incr('post:42:views') # fast, in-memory only
# Background job (runs every 60 seconds):
def flush_view_counts(redis_client, db):
for key in redis_client.scan_iter('post:*:views'):
count = redis_client.getdel(key) # atomic get-and-delete
post_id = key.split(':')[1]
db.execute('UPDATE posts SET views = views + %s WHERE id = %s',
(int(count), post_id))Kurztest
Testen Sie Ihr Verständnis der Konzepte aus dieser Lektion für AWS Solutions Architect (SAA-C03).
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: Lazy Loading füllt den Cache bei Lesevorgängen nach Cache Misses und nutzt den Speicher effizient, kann jedoch bis zum Ablauf der TTL veraltete Daten liefern. Write-Through aktualisiert den Cache bei jedem Schreibvorgang und verhindert veraltete Daten, verschwendet jedoch Speicher für ungelesene Daten. Eine explizite Invalidierung löscht Cache-Schlüssel bei Aktualisierungen der Datenbank und beseitigt dadurch Zeitfenster mit veralteten Daten. Als Nächstes untersuchen wir Muster für Sitzungsspeicher und Bestenlisten mit ElastiCache.
Häufig gestellte Fragen
Ist die Lektion „Caching-Strategien: Lazy Loading und Write-Through“ kostenlos?
Ja — der vollständige Text von „Caching-Strategien: Lazy Loading und Write-Through“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Cloud & IT Cert Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Cloud & IT Cert Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Caching-Strategien: Lazy Loading und Write-Through“?
Implementieren Sie Lazy Loading, um den Cache bei einem Cache-Miss zu befüllen, und Write-Through, um den Cache bei jedem Datenbank-Schreibvorgang konsistent zu halten. Du übst Cloud & IT Cert Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Cloud & IT Cert Prep zu starten?
Keine Vorkenntnisse erforderlich. Cloud & IT Cert Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Caching-Strategien: Lazy Loading und Write-Through“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Cloud & IT Cert Prep-Lektion Code schreiben und ausführen?
Ja. Jede Cloud & IT Cert Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Redis im Vergleich zu Memcached: Die richtige Engine auswählen
- ElastiCache-Redis-Replikationsgruppen und Clustermodus
- Caching-Strategien: Lazy Loading und Write-Through
- Sitzungsspeicherung und Leaderboard-Muster