Gecachten Preisen eine klare Identität und Lebensdauer geben

RedisBeginner
Jetzt üben

Einführung

Ein kleines Geschäft speichert seine maßgeblichen Preise in einer vorbereiteten Primärdatenbank und verwendet Redis, um sich bereits von Kunden angesehene Preise zu merken. Wiederholte Ansichten sollten diesen gemerkten Wert verwenden. Eine SKU kann jedoch in verschiedenen Geschäften oder Währungen unterschiedliche Preise haben, und ein gemerkter Preis muss irgendwann ablaufen.

Du lieferst eine kurze policy.py, die die vollständige Cache-Identität auswählt und jeder Befüllung eine endliche Lebensdauer gibt. Du benötigst grundlegende Terminalnavigation und Redis-GET/SET-Kenntnisse. Die Python-Vorlage und jeder Ausdruck, den du änderst, werden hier erklärt; ein vorheriger Python-Kurs ist nicht erforderlich. Die Primärquelle ist eine vorbereitete SQLite-Datenbank, keine zweite Aufgabe zur Datenbankimplementierung. Diese unabhängige Einheit verwendet nur Terminal mit eigenen neuen Daten.

Bearbeite nur /home/labex/project/cache-desk/policy.py. Bewahre die bereitgestellten Werkzeuge, die Quelltabelle, alle Quellidentitäten und Preise sowie die unbeteiligte Katalognotiz. Verwende in den drei Funktionen nur die dokumentierte Quell-/Cache-API und gewöhnliche Policy-Ausdrücke; lass Importe, Shell-Ausführung und unbeteiligte Ressourcen aus der Policy heraus. Deaktiviere das Caching nicht, leere Redis nicht umfassend und ändere keine globale Konfiguration. Wir testen kontrollierte sequenzielle Anfragen ohne Latenzgarantie im Produktivbetrieb oder Garantie starker Konsistenz. Die vom Autor geschätzte Zeit umfasst Lesen und gewöhnliche Fehler; sie wurde nicht mit Anfängern gemessen.

Tatsächlich angefragte Preise unterscheiden

In diesem Schritt beobachtest du einen tatsächlichen Cache-Treffer, findest eine Schlüsselkollision und machst die vollständige Identität jedes Preises zum Bestandteil seines Schlüssels.

Beginne in Terminal an der Shell-Eingabeaufforderung. cd ändert das aktuelle Verzeichnis; dieser absolute Pfad funktioniert aus jedem Verzeichnis. ./desk führt ein vorbereitetes Programm aus diesem Verzeichnis aus. Jeder folgende Befehl ist ein separater Shell-Befehl, keine Eingabe für eine interaktive Redis-Eingabeaufforderung.

cd /home/labex/project/cache-desk
./desk status

Lies die Spaltenreihenfolge: shop / sku / currency / integer cents. North MUG USD kostet 1200 Cent, South MUG USD 1500, North MUG EUR 1100 und North FREE USD 0. Die Statusanzeige liest maßgebliche Preise; sie befüllt niemals den Cache.

Ein Cache-Miss bedeutet, dass Redis keinen Wert für den angeforderten Schlüssel hat. Ein Cache-Hit bedeutet, dass es einen hat. Diese vorbereitete Anwendung verwendet Cache-aside: zuerst Redis lesen, nur bei einem Miss die Primärquelle lesen und sich dann das Ergebnis merken. Probiere dieselbe normale Anfrage zweimal:

./desk view north MUG USD
./desk view north MUG USD

Das erste Ergebnis sollte "cents": 1200, "origin": "source", "primary_selects": 1 zeigen; das zweite zeigt "origin": "cache", "primary_selects": 0. Die Anzahl stammt aus nativen SQLite-SELECT-Traces für diese Anfrage, nicht aus einer geschätzten Beschleunigung. JSON-Ausgaben verwenden Feldnamen in Anführungszeichen; diese drei Felder kennzeichnen Preis, Herkunft und Primärlesezugriffe.

Frage nun ein anderes Geschäft an und prüfe den tatsächlichen Redis-Schlüssel:

./desk view south MUG USD
./desk inspect south MUG USD
./desk policy

Der unvollständige Schlüssel verwendet nur MUG. Er kann Norths 1200 für South zurückgeben, obwohl die Primärquelle weiterhin 1500 speichert. inspect liest den Schlüssel und seinen tatsächlichen Wert; es repariert den Preis nicht. Das bereitgestellte Präfix catalog begrenzt die Schlüssel dieses Kurses. Jeder Schlüssel muss mit dem bereitgestellten Präfix beginnen, gefolgt von einem Doppelpunkt, etwa catalog:. Das Suffix muss alle drei Identitätsfelder unterscheiden, nicht nur die SKU; gleichwertige Suffixkodierungen werden akzeptiert.

Die Vorlage ist Python. def definiert eine Funktion; die Namen in Klammern sind ihre Argumente. Ein eingerückter Rumpf gehört zu dieser Funktion. return liefert ihr Ergebnis. identity ist ein dreiteiliges Tupel in der angezeigten Feldreihenfolge: identity[0] ist das Geschäft, [1] die SKU, [2] die Währung. Die Indizierung beginnt bei null. f"...{name}..." fügt einen Ausdruck in eine Zeichenfolge ein; Doppelpunkte sind hier gewöhnliche Trennzeichen. Kurskennungen enthalten nur Buchstaben, Ziffern, Bindestriche und Unterstriche und können dieses Trennzeichen daher nicht enthalten. Dieses Schlüsselformat ist keine allgemeine Kodierung für beliebigen Benutzertext.

In read_price weist = einen Wert zu. cache.command("GET", key) sendet einen tatsächlichen Redis-Befehl. None bedeutet keinen gecachten Wert; if value is not None: verzweigt nur, wenn ein Wert vorhanden ist. Dieser ausdrückliche Test bewahrt einen Preis von null. Redis gibt seinen Zeichenfolgenwert zurück, daher wandelt int(value) ihn in ganzzahlige Centbeträge um. Das Komma in return cents, "source" gibt ein Paar zurück. source.read(identity) führt das vorbereitete Primär-SELECT aus und löst bei einer unbekannten Identität einen Nachschlagefehler aus. Es gibt keinen ersatzweisen Referenzpreis.

Speichere eine vollständige Datei mit einem vollständigen Schlüssel. cat > policy.py ersetzt diese Datei; die Here-Dokument-Markierung 'POLICY' in Anführungszeichen lässt die Shell jede folgende Zeile wörtlich bis zur alleinstehenden Zeile POLICY kopieren. Kopiere den gesamten Block und bewahre vier Leerzeichen Einrückung. Die wiederholten Funktionen behalten das vorbereitete Leseverhalten bei; nur die Schlüsselentscheidung ändert sich in diesem Schritt.

cat > policy.py <<'POLICY'
def cache_key(prefix, identity):
    return f"{prefix}:{identity[0]}:{identity[1]}:{identity[2]}"


def read_price(source, cache, prefix, identity):
    key = cache_key(prefix, identity)
    value = cache.command("GET", key)
    if value is not None:
        return int(value), "cache"
    cents = source.read(identity)
    cache.command("SET", key, cents)
    return cents, "source"


def change_price(source, cache, prefix, identity, cents):
    source.write(identity, cents)
POLICY

Sieh jede Identität zweimal an:

./desk view north MUG USD
./desk view north MUG USD
./desk view south MUG USD
./desk view south MUG USD
./desk view north MUG EUR
./desk view north MUG EUR
./desk view north FREE USD
./desk view north FREE USD

Jeder erste Lesezugriff auf einen neuen vollständigen Schlüssel stammt aus der Quelle und sein zweiter aus Redis. Die Preise sind jeweils 1200, 1500, 1100 und 0. Ein Cache-Treffer mit falschem Preis ist kein Erfolg. Der alte entbehrliche Schlüssel catalog:MUG wird nicht mehr verwendet; umfassendes Löschen ist nicht erforderlich.

Gibst du ./deskk ein, meldet die Shell, dass die Datei fehlt. ls listet die tatsächlichen Werkzeuge auf; führe ./desk mit der richtigen Schreibweise erneut aus. Meldet Python einen Syntax- oder Einrückungsfehler, zeige ./desk policy an und kopiere dann den vollständigen Dateiblock erneut mit intakten führenden Leerzeichen. Setze nicht die VM zurück und ändere nicht die vorbereiteten Werkzeuge. Die Schrittprüfung testet geänderte Identitäten in einer entbehrlichen Testumgebung und bewahrt die aktuelle Primärquelle; sie verlangt keine bestimmte Schlüsselschreibweise.

Jeder Befüllung eine feste Ablaufzeit geben

In diesem Schritt ergänzt du eine endliche Lebensdauer, wenn ein Preis in Redis gelangt, und verhinderst, dass Cache-Treffer diese Ablaufzeit verschieben.

Fahre in Terminal unter /home/labex/project/cache-desk fort. Prüfe einen vorhandenen vollständigen Schlüssel:

./desk inspect north MUG USD

pttl_ms ist die verbleibende Lebensdauer in Millisekunden. -1 bedeutet, dass der Schlüssel keinen Ablauf hat; -2 bedeutet, dass er fehlt. Ein positiver Wert zählt herunter. Ein nicht abgelaufener Wert ohne Ablaufzeit kann eine externe Preisänderung unbegrenzt überdauern.

Redis SET key value EX seconds speichert den Wert und seinen Ablauf in einem Befehl. Wähle 15 Sekunden für dieses Lehrgeschäft; jede akzeptierte Befüllung muss mit einer anfänglichen TTL von 12 bis 20 Sekunden gespeichert werden. Dieses kurze Intervall macht natürlichen Ablauf beobachtbar; es ist keine TTL-Empfehlung für den Produktivbetrieb. Setze die Ablaufzeit nur bei einem Miss. Sie bei jedem Treffer zu erneuern, kann einen häufig angefragten veralteten Preis unbegrenzt am Leben halten. Ein einfaches SET, das einen ablaufenden Schlüssel überschreibt, entfernt den alten Ablauf, sofern dessen Erhalt nicht ausdrücklich angefordert wurde.

Ersetze die Datei durch dieselbe vollständige Identität und ein SET mit Zeitbegrenzung. In Python werden die separaten Argumente "EX", 15 an Redis übergeben; 15 ist eine Ganzzahl, keine Kennung in Anführungszeichen.

cat > policy.py <<'POLICY'
def cache_key(prefix, identity):
    return f"{prefix}:{identity[0]}:{identity[1]}:{identity[2]}"


def read_price(source, cache, prefix, identity):
    key = cache_key(prefix, identity)
    value = cache.command("GET", key)
    if value is not None:
        return int(value), "cache"
    cents = source.read(identity)
    cache.command("SET", key, cents, "EX", 15)
    return cents, "source"


def change_price(source, cache, prefix, identity, cents):
    source.write(identity, cents)
POLICY

Die im vorherigen Schritt befüllten Werte mit vollständiger Identität haben weiterhin keinen Ablauf: Eine Codeänderung ergänzt nicht rückwirkend eine Ablaufzeit. forget löscht absichtlich nur den aktuellen Cache-Schlüssel einer bekannten Identität und lässt deren Primärpreis und andere Schlüssel unberührt. Entferne diese vier ausdrücklich entbehrlichen Übungseinträge einzeln. Dies ist eine ausdrückliche Lernendenaktion, niemals ein umfassendes Leeren oder eine verborgene Reparatur durch das Leseprogramm. Nachfolgende Befüllungen verwenden alle die neue Ablaufzeit. Befülle dann Norths Preis und prüfe ihn:

./desk forget north MUG USD
./desk forget south MUG USD
./desk forget north MUG EUR
./desk forget north FREE USD
./desk view north MUG USD
./desk inspect north MUG USD
./desk view north MUG USD
./desk inspect north MUG USD

Die erste Ansicht ist source/1, die nächste cache/0, wenn sie vor Ablauf erfolgt. Positive PTTL sinkt, statt erneut bei 15000 zu starten. Dauert das Lesen länger als 15 Sekunden, ist ein tatsächlicher Miss zu erwarten: Wiederhole die Befüllungs- und Prüfbefehle zügig, ohne deine Policy zu ändern.

Du kannst auch native Redis-Werte über die bereitgestellte schreibgeschützte Verbindung lesen. ./redis sendet seine Argumente an das private Redis dieses Kurses, nicht an den allgemeinen Redis-Dienst:

./redis GET catalog:north:MUG:USD
./redis TTL catalog:north:MUG:USD

Der Wrapper gibt eine JSON-Zeichenfolge wie "1200", eine native ganzzahlige TTL oder null für einen fehlenden Wert aus. Er ruft niemals einen fehlenden Preis ab. Nun fordert sleep 16 die Shell auf, 16 echte Sekunden zu warten. Es simuliert keine Zeit und löscht keinen Schlüssel für dich:

sleep 16
./desk inspect north MUG USD
./desk view north MUG USD
./desk view north MUG USD

Vor der erneuten Befüllung zeigt inspect value: null und PTTL -2. Die nächste Ansicht liest die Quelle erneut, die folgende kann Redis treffen. Alle maßgeblichen Preise bleiben in dieser Einheit unverändert. Die Bewertung testet tatsächlichen Ablauf auf isolierten Schlüsseln; aktuelle Schlüssel können beim Lesen natürlich ablaufen, daher hängt der Abschluss nicht von einem Wettlauf gegen einen kurzen Countdown ab.

Zusammenfassung

Du hast Geschäft, SKU und Währung in tatsächlichen Redis-Schlüsseln getrennt, Preise von null bewahrt, Cache-Treffer anhand von Primärlesezugriffen geprüft und jeder Befüllung eine nicht gleitende Lebensdauer gegeben. Deine Policy ist wiederverwendbar; die vorbereitete Primärquelle und unbeteiligte Katalogdaten bleiben intakt.