Инвалидируйте цену после зафиксированной записи

RedisBeginner
Практиковаться сейчас

Введение

Изменение цены сотрудником должно обновлять достоверную базу данных и удалять старое значение кеша именно этой цены. Очистка всех кешированных товаров отбросила бы полезную работу. Удаление записи кеша перед неудачной записью в источник также неверно отражало бы результат записи.

Это независимое занятие подготавливает новое рабочее место кеша и правильную политику чтения с полным идентификатором и сроком 15 секунд. Вам нужны понятия cache-aside, идентификатора, TTL и короткого шаблона Python из предыдущего занятия. Вы завершите change_price, увидите отклонённую запись в основную базу и сравните явную инвалидацию с внешним обновлением, которое становится видимым после естественного истечения срока. Требуется только Terminal; файлы или процессы из предыдущей VM не переносятся.

Редактируйте только /home/labex/project/cache-desk/policy.py, используя три описанные функции и API источника и кеша. Сохраните все инструменты, идентичность исходной таблицы, посторонние цены и заметку каталога. Разрешённые изменения основной базы: North MUG USD с 1200 на 1350 через вашу политику, отклонённая попытка отрицательной цены и подготовленное внешнее изменение на 1450. В пути учащегося запросы выполняются последовательно с исправными службами; это не строгая согласованность, распределённая инвалидация кеша или обещание атомарной фиксации двух баз данных. Оценка времени дана автором с учётом чтения и ошибок, без данных о времени новичков.

Инвалидируйте точную цену после фиксации

На этом шаге вы добьётесь удаления устаревшей цены из кеша после успешной записи в источник, сохраняя кеш после отклонённой записи.

Начните во вкладке Terminal. Перейдите в подготовленный рабочий каталог этого независимого занятия:

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

Три поля идентификатора — магазин, 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, а быстрый последующий просмотр всё ещё может вернуть кешированные 1200. Если 15 секунд уже прошли, просмотр может правильно дать промах и показать 1350; отсутствие инвалидации остаётся дефектом политики, даже когда истечение его скрывает. Сообщение об успехе говорит только о том, что переданная политика вернула управление; наблюдения основной базы и кеша определяют, что произошло на самом деле.

change_price уже вызывает source.write(identity, cents). Этот подготовленный метод обновляет одну известную строку основной базы в штатной транзакции SQLite. Он возвращает управление только после фиксации. Отрицательная цена нарушает ограничение CHECK источника и вызывает ошибку; неизвестный идентификатор вызывает ошибку поиска. Python выполняет следующую строку только при успешном завершении предшествующего вызова. Поэтому разместите точечное удаление ключа из Redis после этого вызова. cache_key(prefix, identity) повторно использует то же отображение идентификатора, что функция чтения. Не удаляйте по одному лишь SKU и не используйте FLUSHDB/FLUSHALL.

Как в предыдущем занятии, here-document с маркером в кавычках заменяет только 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

Заполните кеш двумя посторонними ценами, затем повторите разрешённую запись. Запись тех же 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 должен показывать отсутствие целевого ключа. Следующий просмотр возвращает source/1 и 1350; следующий за ним — cache/0. Другие ключи намеренно не инвалидируются; они всё ещё могут естественно истечь. Используйте status, чтобы отличать сохранённые основные значения от наличия кеша.

Теперь намеренно запросите недопустимую отрицательную цену. Следующая команда должна завершиться ненулевым кодом и вывести IntegrityError со штатной ошибкой CHECK. Это не успешное обновление, не промах кеша и не проблема соединения:

./desk change north MUG USD -1
./desk status
./desk inspect north MUG USD
./desk view north MUG USD

Достоверная цена остаётся 1350. Если заполненная запись ещё не истекла естественным образом, её значение и исходный срок сохраняются, а просмотр даёт cache/0. При медленном чтении вместо этого возможно обычное истечение; изолированная проверка испытывает сохранность после ошибки записи без гонки со временем чтения. Python останавливается до DEL, когда source.write вызывает исключение. Не перехватывайте ошибку, чтобы напечатать ложный успех.

Если оболочка сообщает об отсутствии ./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

Внешняя команда представляет намеренно контролируемый механизм записи, который обходит обработчик инвалидации этого приложения. Она выполняет настоящую фиксацию основной базы, а не изменение отображения по таймеру. В этом занятии разрешено только внешнее изменение указанной ниже цены на приведённое значение:

./desk external north MUG USD 1450
./desk status
./desk view north MUG USD
./desk inspect north MUG USD

Status немедленно показывает 1450. Просмотр до истечения существующего ключа всё ещё может вернуть кешированные 1350 с нулём чтений основной базы. Срок продолжает отсчитываться и не начинается заново при попадании. Если время чтения уже превысило срок жизни, ожидаемо увидеть 1450 после промаха. Вы можете без задержки повторить начальную последовательность изменения, заполнения и внешнего обновления этого шага, чтобы увидеть интервал устаревания.

Перед последним чтением подождите дольше полного настроенного срока жизни записи:

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

Inspect показывает отсутствие ключа. Следующий просмотр читает зафиксированные 1450 из основной базы и заполняет Redis; следующий может использовать эти настоящие кешированные 1450. Сохраните это итоговое состояние основной базы. Все остальные достоверные цены остаются 1500, 1100 и 0. ./redis GET catalog:admin:note позволяет изучить сохранённую постороннюю заметку без запроса к основной базе.

Это последовательная политика cache-aside. Внешнее обновление после заполнения может оставлять старое значение этой записи видимым до её существующего 15-секундного срока. Это наблюдение не доказывает глобального ограничения устаревания при одновременных чтениях, записях, медленном заполнении или остановленной службе. Конкурирующий читатель мог получить старое значение источника до записи и заполнить им кеш после инвалидации; этот курс не решает такую гонку или лавину одновременных промахов.

Фиксация источника и удаление ключа из Redis — отдельные операции. Если Redis отказывает в удалении после успешной фиксации, основная база уже изменена. Ошибка должна передаваться дальше как ошибка операции кеша; её нельзя описывать как откат основной базы или завершённую инвалидацию. Изолированная проверка испытывает этот штатный отказ, не ломая живую службу. Повторы в рабочей системе, надёжная инвалидация и восстановление после отказов требуют дополнительного проектирования за рамками упражнения.

Резюме

Вы связали настоящую фиксацию основной базы с точечной инвалидацией кеша, сохранили кешированные данные после отклонённой записи в источник и увидели внешнее изменение через естественное истечение срока. Ваша политика отличает ошибку записи в источник от последующей ошибки Redis и явно обозначает границу своей согласованности при последовательных запросах.