はじめに
スタッフが価格を変えたら、正しい元データベースを更新し、その価格そのものの古いキャッシュ値を削除する必要があります。全商品のキャッシュを消せば、有用な作業まで捨ててしまいます。元データの書き込みが失敗する前にキャッシュを削除することも、書き込み結果を正しく表しません。
この独立した実習は、新しい価格受付と、正しい完全な識別情報・15 秒の読み取りポリシーを準備します。前の実習のキャッシュアサイド、識別情報、TTL、短い Python ひな型の概念が必要です。change_price を完成させ、拒否されたプライマリ書き込みを観察し、明示的な無効化と、自然な期限切れで見える外部更新を比較します。必要なのは Terminal だけで、前の VM のファイルやプロセスは引き継ぎません。
説明された 3 関数と source/cache API を使い、/home/labex/project/cache-desk/policy.py だけを編集します。全ツール、元テーブルの同一性、無関係な価格、カタログメモを保全します。許可されたプライマリ変更は、ポリシー経由で North MUG USD を 1200 から 1350 に変更すること、拒否される負価格の試行、準備済みの 1450 への外部変更です。学習者の操作では正常なサービスに逐次リクエストを行います。強い整合性、分散キャッシュ無効化、2 データベースのアトミックなコミットの保証ではありません。所要時間は作者が読解とミスを見込んだ値で、初心者の計測データはありません。
コミット後に対象の価格だけを無効化する
このステップでは、成功した元データの書き込みが古いキャッシュ価格を削除し、拒否された書き込みではキャッシュを保つようにします。
Terminal から始め、この独立した単元の準備済み作業領域に入ります。
cd /home/labex/project/cache-desk
./desk status
./desk policy
3 つの識別フィールドは店舗、SKU、通貨です。North MUG USD は 1200 セント、South MUG USD は 1500、North MUG EUR は 1100、North FREE USD は 0 から始まります。通常の価格をキャッシュに入れ、正当な変更を送信します。
./desk view north MUG USD
./desk view north MUG USD
./desk change north MUG USD 1350
./desk status
./desk view north MUG USD
status はコミット済みのプライマリ価格 1350 を表示しますが、すぐに view を行うと、まだキャッシュの 1200 を返すことがあります。15 秒を過ぎていれば、view は正しくミスして 1350 を表示する場合もあります。期限切れで隠れても、無効化の欠如はポリシーの欠陥です。成功メッセージは提出したポリシーが返ったことだけを表し、実際に何が起きたかはプライマリとキャッシュの観察で判断します。
change_price はすでに source.write(identity, cents) を呼びます。この準備済みメソッドは、ネイティブな SQLite トランザクションで既知のプライマリ行 1 つを更新し、コミット後にだけ戻ります。負価格は元データの CHECK 制約に違反し、エラーを送出します。未知の識別情報も検索エラーになります。Python は、前の呼び出しが正常に戻った場合だけ次の行を実行します。そのため、正確な Redis の削除をこの呼び出しの後に置きます。cache_key(prefix, identity) は読み取り関数と同じ識別対応を再利用します。SKU だけで削除したり、FLUSHDB/FLUSHALL を使ったりしないでください。
前の実習と同様に、引用符付きヒアドキュメントで policy.py だけを置き換えます。インデントを保ちます。完全な置換になるよう、読み取り関数全体も繰り返します。
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)
cache.command("DEL", cache_key(prefix, identity))
POLICY
無関係な 2 価格をキャッシュに入れ、許可された書き込みを繰り返します。同じ 1350 を書いても、既知の行の実際のコミットを行い、無効化を試せます。
./desk view south MUG USD
./desk view north MUG EUR
./desk change north MUG USD 1350
./desk inspect north MUG USD
./desk view north MUG USD
./desk view north MUG USD
書き込み直後の inspect では、対象キーがない必要があります。次の view は source/1 と 1350 を返し、その次は cache/0 です。他のキーを意図的に無効化することはありませんが、自然に期限切れになる場合はあります。保全されたプライマリ値とキャッシュの存在を、status で区別してください。
次に、意図的に無効な負価格を要求します。以下のコマンドは非ゼロで終了し、ネイティブな CHECK 失敗と IntegrityError を表示する想定です。成功した更新、キャッシュミス、接続問題ではありません。
./desk change north MUG USD -1
./desk status
./desk inspect north MUG USD
./desk view north MUG USD
正しい元価格は 1350 のままです。格納したエントリーが自然に期限切れになっていなければ、その値と元の期限が残り、view は cache/0 です。ゆっくり読んだ場合は通常の期限切れが見えることもあります。隔離したチェックでは、読解時間の競争なしに失敗時の保全を試します。source.write が例外を送出すると、Python は DEL の前で止まります。エラーを捕まえて偽の成功を表示しないでください。
シェルが ./deskk を見つけられないと報告したら、ls を実行して名前を直します。ポリシーに構文・インデントエラーがあれば、./desk policy で確認し、完全なブロックで置き換えます。負価格の失敗でリセットは不要です。準備済みの元データのトランザクションは、その試行をすでにロールバックしています。直接データベースを編集せず、読み取りを続けてください。
外部更新を次のキャッシュ格納に反映させる
このステップでは、実際の外部の元データ変更と、古いキャッシュ値の有限な有効期間を観察します。
Terminal の /home/labex/project/cache-desk で続けます。許可されたコミット済み価格を再適用して既存の対象キャッシュを削除し、1350 を格納します。別の商品を変えずに、開始状態を明確にします。
./desk change north MUG USD 1350
./desk view north MUG USD
./desk inspect north MUG USD
external コマンドは、このアプリの無効化フックを迂回する、意図的に制御された書き込み元を表します。タイマーで表示を変えるのではなく、実際にプライマリをコミットします。この単元で許可する外部対象と新価格は、次だけです。
./desk external north MUG USD 1450
./desk status
./desk view north MUG USD
./desk inspect north MUG USD
status はすぐに 1450 を表示します。既存のキーの期限前の view は、プライマリ読み取りゼロでキャッシュの 1350 を返すことがあります。期限は減り続け、ヒットで再開しません。読解時間がすでに有効期間を超えたら、ミスで 1450 が見えるのは想定どおりです。古い値が見える期間を観察するには、このステップの最初の変更・格納・外部更新を手早く繰り返せます。
最後の読み取り前に、設定した格納の有効期間全体を超えて待ちます。
sleep 16
./desk inspect north MUG USD
./desk view north MUG USD
./desk view north MUG USD
./desk status
inspect はキーの不在を表示します。次の view はコミット済みの 1450 をプライマリから読んで Redis に格納し、その次は実際のキャッシュの 1450 を使えます。この最終的なプライマリ状態を保ってください。他の正しい元価格はすべて 1500、1100、0 のままです。./redis GET catalog:admin:note はプライマリへのリクエストなしで、保全された無関係なメモを確認できます。
これは逐次処理のキャッシュアサイドポリシーです。格納後の外部更新では、その格納の既存の 15 秒の期限まで古い値が見えることがあります。この観察は、同時の読み書き、遅い格納、停止したサービスでも成り立つ全体的な古さの上限を証明しません。同時の読み取り側が、書き込み前に古い元値を取得し、無効化後に格納する場合があります。このコースは、その競合や同時ミスの集中によるスタンピードを解決しません。
元データのコミットと Redis の削除は別操作です。正常なコミット後に Redis が削除を拒否したら、プライマリはすでに変わっています。エラーはキャッシュ操作の失敗として伝播する必要があり、プライマリのロールバックや無効化完了と説明してはいけません。隔離した採点は、実際のサービスを壊さずに、そのネイティブな失敗を試します。本番の再試行、永続的な無効化、障害復旧には追加設計が必要で、この実習の範囲外です。
まとめ
実際のプライマリのコミットと正確なキャッシュ無効化を結び、拒否された元データの書き込み後はキャッシュを保ち、自然な期限切れを通じて外部変更を観察しました。ポリシーは元データの書き込み失敗と、その後の Redis 失敗を区別し、逐次処理での整合性の範囲を明確にします。



