Что такое инвалидация кеша

Обновлено: 05.07.2024

Существует ли общее решение или метод аннулирования кеша; узнать, когда запись устарела, чтобы всегда получать свежие данные?

Например, рассмотрим функцию getData(), которая получает данные из файла. Он кэширует его на основе времени последнего изменения файла, которое проверяется каждый раз, когда он вызывается.
Затем вы добавляете вторую функцию transformData(), которая преобразует данные и кэширует результат для следующего вызова функции. Он ничего не знает о файле — как добавить зависимость, согласно которой, если файл изменен, этот кеш становится недействительным?

Вы можете вызывать getData() каждый раз, когда вызывается transformData(), и сравнивать его со значением, которое использовалось для создания кеша, но это может оказаться очень дорогостоящим.

Я думаю, что этот заголовок был бы лучше, чем "Инвалидация кеша — есть ли общее решение?" поскольку это относится к определенному классу проблем кэширования.

Нет, он плохо разбирался в информатике. Я уверен, что его участие в создании OpenGL, X11 и SSLv3 сделало его слишком занятым, чтобы по-настоящему изучить его. :-)

В информатике есть только две сложные проблемы: инвалидация кэша. Называние вещей. И отдельные ошибки.

Однажды я услышал это как "Две самые сложные вещи в области компьютерных наук — это аннулирование кеша, присвоение имен объектам и ошибки, возникающие поодиночке".

9 ответов 9

То, о чем вы говорите, - это пожизненная цепочка зависимостей, когда одно зависит от другого, которое может быть изменено вне его контроля.

Если у вас есть идемпотентная функция от a , b до c, где, если a и b одинаковы, то c тоже самое, но стоимость проверки b высока, то вы либо:

  1. примите, что вы иногда оперируете устаревшей информацией и не всегда проверяете b
  2. сделайте все возможное, чтобы проверить b как можно быстрее

Вы не можете получить свой торт и съесть его.

Если вы можете наложить дополнительный кеш на основе поверх, это ничуть не повлияет на первоначальную проблему. Если вы выбрали 1, то у вас есть свобода, которую вы дали себе, и, таким образом, вы можете кэшировать больше, но вы должны помнить о правильности кэшированного значения b . Если вы выбрали 2, вы все равно должны проверять b каждый раз, но можете вернуться к кешу для a, если b проверяется.

Если вы наслаиваете кеши, вы должны учитывать, не нарушили ли вы «правила» системы в результате комбинированного поведения.

Если вы знаете, что a всегда имеет силу, если имеет значение b, вы можете упорядочить свой кеш следующим образом (псевдокод):

Очевидно, что последовательное наслоение (скажем, x ) тривиально, если на каждом этапе допустимость вновь добавленных входных данных соответствует соотношению a : b для x : b и x : a .

Однако вполне возможно, что вы могли бы получить три входных данных, достоверность которых была бы полностью независимой (или была циклической), поэтому расслоение было бы невозможно. Это означало бы, что строка, помеченная как // важная, должна была бы измениться на

если срок действия endCache[a] истек или отсутствует)

или, может быть, если стоимость проверки b высока, вы используете pubsub, чтобы при изменении b он уведомлял c. Шаблон Наблюдатель распространен.

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

Я не думаю, что существует какое-то универсальное волшебное решение, позволяющее решить эту проблему. Но во многих практических случаях вполне может быть возможность преобразовать подход, основанный на "опросе", в подход, основанный на "прерывании", что может просто решить проблему.

ИМХО, функциональное реактивное программирование (FRP) в некотором смысле является общим способом решения проблемы недействительности кеша.

И вот почему: устаревшие данные в терминологии FRP называются сбоями. Одна из целей FRP — гарантировать отсутствие сбоев.

FRP более подробно объясняется в этом выступлении «Суть FRP» и в этом ответе SO.

В разговоре ячейки представляют кэшированный объект/сущность, и ячейка обновляется, если обновляется одна из ее зависимостей.

FRP скрывает код подключения, связанный с графом зависимостей, и гарантирует отсутствие устаревших ячеек.

Еще один способ (отличный от FRP), который я могу придумать, - это обернуть вычисленное значение (типа b ) в какой-то модуль записи Monad Writer (Set (uuid)) b, где Set (uuid) (нотация Haskell) содержит все идентификаторы изменяемых значений, от которых зависит вычисляемое значение b. Таким образом, uuid — это своего рода уникальный идентификатор, который идентифицирует изменяемое значение/переменную (скажем, строку в базе данных), от которой зависит вычисляемое значение b.

Объедините эту идею с комбинаторами, которые работают с этим типом записывающей монады, и это может привести к какому-то общему решению аннулирования кеша, если вы используете эти комбинаторы только для вычисления нового b . Такие комбинаторы (скажем, специальная версия filter ) принимают монады Writer и (uuid, a) -s в качестве входных данных, где a — изменяемые данные/переменная, определяемые uuid .

Поэтому каждый раз, когда вы меняете "исходные" данные (uuid, a) (скажем, нормализованные данные в базе данных, из которой вычислялось значение b), от которых зависит вычисляемое значение типа b, вы можете аннулировать кеш, содержащий b. если вы изменяете любое значение a, от которого зависит вычисленное значение b, потому что на основе набора (uuid) в монаде Writer вы можете сказать, когда это произойдет.

Поэтому каждый раз, когда вы что-то мутируете с заданным uuid , вы транслируете эту мутацию всем кэшам, и они делают недействительными значения b, которые зависят от изменяемого значения, идентифицированного с указанным uuid, потому что монада Writer, в которую упакован b, может скажите, зависит ли это b от указанного uuid или нет.

Конечно, это окупается только в том случае, если вы читаете гораздо чаще, чем пишете.

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

Должно быть, многие люди много раз слышали эту цитату (Фила Карлтона): В компьютерных науках есть только две сложные вещи: инвалидация кеша и проблема с именами. Два дня назад Ник Тирни снова упомянул об этом. в своем посте «Именование вещей». Поскольку он сказал, что не уверен, что означает аннулирование кеша, а у меня есть небольшой опыт в этом, я хочу написать этот короткий пост, чтобы объяснить, почему аннулирование кеша сложно, исходя из моего опыта.

Почему кеширование?

Самое сложное — это «то же самое». Откуда вы знаете, что вычисляете одно и то же? Это все, что касается «аннулирования кеша». Когда все изменится, вам придется аннулировать кеш и снова выполнить (предположительно трудоемкие) вычисления.

Игрушечный пример

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

Я использовал Sys.sleep() только для того, чтобы сделать вид, что эта функция отнимает много времени. В функции приветствия () Ник быстрый и скажет «Привет», а Иихуи медленный, говорящий по-китайски. Если нам нужно вызывать эту функцию много раз, нет необходимости ждать, если мы сможем сохранить то, что говорят Ник и Ихуи. Нам понадобится база данных для хранения их слов и ключи для получения результатов.

В первый раз, когда вы запустите эту функцию, она будет работать медленно, но во второй раз она будет работать мгновенно.

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

Когда аннулировать кеш?

Конечно, игрушечные примеры часто не отражают реальность. Если Ник поедет в Японию, он может говорить по-японски. Когда Yihui находится в США, он должен говорить по-английски. В этих случаях нам необходимо обновить базу данных кеша (сделав ранее сохраненные результаты недействительными).

Теперь позвольте мне рассказать о реальном примере кеширования вязания, который должен звучать похоже на случай, когда Ник находится в Японии (или Yihui в США). Для тех, кто заботится о технических деталях, Knitr кэширует результаты, используя эти строки кода, и делает кэш недействительным здесь.

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

Звучит правильно, не так ли?

Я слышал, как недовольные пользователи проклинают кеширование Knitr. Кому-то это показалось слишком чувствительным, а кому-то — глупым. Например, когда вы добавляете пробел в комментарий R в фрагменте кода, должен ли Knitr аннулировать кеш? Изменение комментария точно никак не повлияет на вычисления (но текстовый вывод может измениться, если показать код в выводе через echo = TRUE ), а вот хэш MD5 изменится. 1

Тогда пример, объясняющий, почему люди считают кэширование Knitr глупым: если вы читаете внешний CSV-файл в фрагменте кода, Knitr не знает, изменили ли вы файл данных. Если вы обновили файл данных, Knitr не будет перечитывать его по умолчанию, если вы не изменили параметры фрагмента или код. Ключ кэша не зависит от внешнего файла. В этом случае вы должны явно связать кеш с внешним файлом, например, 2

Начиная с кэша опций чанка.extra связан с файлом CSV, кеш будет аннулирован при изменении файла (поскольку ключ кеша будет другим).

Другим примером является фрагмент кода, использующий переменную, созданную из предыдущего фрагмента кода. Когда переменная обновляется в предыдущем чанке, кеш этого чанка также должен стать недействительным. Это приводит к теме структуры зависимостей фрагментов кода, которая может быть сложной, но есть некоторые вспомогательные функции, такие как Knitr::dep_prev() и Knitr::dep_auto(), чтобы сделать это немного проще.

Когда фрагмент кода занимает очень много времени, Knitr должен быть более консервативным (не делать недействительным дорогостоящий кеш, если только не были внесены критические изменения). Когда фрагмент кода выполняется умеренно медленно (например, 10 или 20 секунд), кеширование, вероятно, должно быть более чувствительным.

Сложность в том, что трудно найти баланс. Любое направление может оскорбить пользователей.

Скрытая стоимость, которую часто игнорируют

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

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

Полная документация по кэшированию Knitr находится в книге Knitr «Динамические документы с R и Knitr (2-е изд.)». Если у вас нет этой книги, на веб-сайте Knitr есть страница, содержащая дополнительную информацию.

Не знаю, о чем думал Фил Карлтон, когда говорил эти слова, но все вышеизложенное — мой опыт кэширования. Окончательное предложение, которое я часто даю пользователям, заключается в том, что если вы считаете, что кеширование Knitr слишком сложное, вполне нормально использовать гораздо более простой механизм кэширования, подобный этому:

В этом общем введении объясняются концепции аннулирования кеша. Если вы уже знакомы с инвалидацией кеша, можете пропустить эту главу.

Что такое инвалидация кеша?¶

В компьютерных науках есть только две сложные вещи: аннулирование кеша и присвоение имен вещам.

– Фил Карлтон

Проблема¶

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

Альтернативы¶

Есть три альтернативы аннулированию кеша.

  1. Первый — быстрое истечение содержания в кэше за счет сокращения времени его жизни (TTL). Однако короткие значения TTL вызывают более высокую нагрузку на приложение, поскольку из него необходимо чаще извлекать содержимое. Более того, уменьшенный TTL не гарантирует, что у клиентов будет свежий контент, особенно если контент очень быстро меняется в результате взаимодействия клиента с приложением.
  2. Второй вариант – проверка свежести кэшированного контента при каждом запросе. Опять же, это означает большую нагрузку на ваше приложение, даже если вы вернетесь раньше (например, используя запросы HEAD).
  3. Последнее средство — вообще не кэшировать нестабильное содержимое. Хотя это гарантирует, что пользователь всегда увидит изменения без задержек, это, очевидно, еще больше увеличивает нагрузку на ваше приложение.

Аннулирование кеша дает вам лучшее из обоих миров: у вас могут быть очень длинные TTL, поэтому, когда контент мало меняется, его можно обслуживать из кеша, потому что не требуются запросы к вашему приложению. В то же время, когда данные изменяются, это изменение незамедлительно отражается в веб-представлениях.

Недостатки¶

У аннулирования кеша есть два возможных недостатка:

Методы аннулирования¶

Кэшированный контент можно аннулировать тремя способами. Не все прокси-серверы поддерживают все методы. Подробную информацию см. в документации по прокси-серверу.

Purge немедленно удаляет содержимое с прокси-сервера. В следующий раз, когда клиент запрашивает URL-адрес, данные извлекаются из приложения, сохраняются на прокси-сервере и возвращаются клиенту.

При очистке удаляются все варианты кэшированного контента в соответствии с заголовком Vary.

Немедленно извлеките запрошенную страницу из серверной части, даже если обычно происходит попадание в кеш.Контент не просто удаляется из кеша, а заменяется новой версией, полученной из приложения.

Поскольку выборка выполняется с параметрами запроса на обновление, другие варианты того же контента не будут затронуты.

В отличие от очистки, запрет не удаляет контент из кеша сразу. Вместо этого ссылка на контент добавляется в черный список (или список банов). Каждый запрос клиента проверяется по этому черному списку. Если запрос соответствует содержимому из черного списка, новое содержимое извлекается из приложения, сохраняется на прокси-сервере и возвращается клиенту.

Банки не могут немедленно удалить контент из кеша, потому что это потребует просмотра всего кэшированного контента, что может занять много времени и снизить производительность кеша.

Решение о запрете может показаться громоздким, но предлагает более мощную аннулирование кеша, например, выбор содержимого для запрета с помощью регулярных выражений. Это открывает путь для мощных схем аннулирования, таких как пометка записей кэша.

Очистить Очистка кеша означает полное удаление всех его записей в кеше. Его можно использовать для более эффективного сброса кеша, а не для бана, который соответствует каждому запросу или для очистки каждого URL по отдельности.

© Copyright 2014–2018, FriendsOfSymfony, редакция b9f1a0b1.

Последняя стабильная версия 1.4 Загрузки в формате pdf On Read the Docs Project Home Сборки Бесплатный хостинг документов, предоставляемый Read the Docs.

Чтобы сохранить актуальность кэшированных данных с учетом времени, пользователя или других переменных, данные должны быть признаны недействительными или удалены из кэша. Dynacache предоставляет различные методы аннулирования кэша. Существует четыре способа сделать кеш недействительным.

Недействительность по времени

Недействительность на основе времени полезна, когда записи кэша не могут быть признаны недействительными каким-либо другим механизмом или их необходимо обновить по истечении заданного периода времени. Этот метод можно реализовать, указав подэлемент value с записью в кэше в файле cachespec.xml. Значение — это количество времени в секундах, в течение которого запись кеша хранится в кеше. Значение по умолчанию для этого элемента равно 0, что означает, что срок действия этой записи не ограничен. Дополнительные сведения об использовании тега см. в разделе Настройка кэшируемых объектов с помощью файла cachespec.xml.

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

Есть также подэлемент бездействия, который используется для указания значения времени жизни (TTL) для записи в кэше на основе времени последнего доступа к записи в кэше. Это подэлемент элемента cache-id. значение, где значение — это количество времени в секундах, в течение которого запись кеша сохраняется в кеше после последнего попадания в кеш. Это особенно полезно для записей кэша, зависящих от пользователя, где средняя продолжительность сеанса пользователя может быть указана как тайм-аут бездействия.

Аннулирование на основе команды

Аннулирование происходит при выполнении команды на основе правил аннулирования, распространяющихся на API WebSphere Commerce Command Framework. Идентификаторы недействительности для аннулирования на основе команд создаются на основе методов и полей, предоставляемых командами.

При создании политик аннулирования на основе команд в cachespec.xml помните о следующих ограничениях:

  • В компоненте метода можно использовать только методы, вызываемые командой, которые возвращают входные переменные экземпляра.
  • Все методы, используемые для создания идентификаторов аннулирования, должны быть предоставлены в командном интерфейсе и реализованы.
  • Тип компонента атрибутов запроса использовать нельзя.

Dynacache API и аннулирование таблицы CACHEIVL

Динамическое кэширование WebSphere Application Server предоставляет следующие классы Java для поддержки программного аннулирования

  • com.ibm.websphere.cache.DistributedMap
  • com.ibm.wsspi.cache.Cache
  • com.ibm.websphere.cache.Cache

WebSphere Commerce предоставляет команду DynaCacheInvalidation, которая периодически вызывается планировщиком для обработки записей в таблице CACHEIVL и вызова вышеуказанных классов Java динамического кэша WebSphere Application Server для аннулирования указанных записей кэша. По умолчанию интервал расписания составляет каждые десять минут.

Групповая недействительность

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

Вы можете указать дополнительные идентификаторы групп кэша, чтобы связать несколько записей кэша с одним и тем же идентификатором группы в cachespec.xml.Количество таких идентификаторов - идентификаторов зависимостей, которые можно определить в записи кэша, не ограничено. Вы можете определить более одного идентификатора зависимости для одной и той же записи кэша, и один и тот же идентификатор зависимости можно повторно использовать для другой записи кэша. Этот механизм обеспечивает удобный способ одновременного удаления всех связанных записей кэша с помощью одного правила.

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

На этой странице представлен обзор аннулирования кеша Cloud CDN.

Что такое инвалидация кеша?

Возможно, вы захотите удалить объект из кеша до истечения срока его действия. Вы можете заставить объект или набор объектов игнорироваться кешем, запросив аннулирование кеша.

Важно убедиться, что исходный сервер возвращает правильный контент, прежде чем запрашивать аннулирование кеша. В противном случае, когда Cloud CDN снова запрашивает контент, он может кэшировать неправильный контент.

Шаблоны пути

Каждый запрос на аннулирование указывает шаблон пути, который идентифицирует объект или набор объектов, которые должны быть аннулированы. Шаблон пути может быть либо конкретным путем, например /cat.jpg , либо всей структурой каталогов, например /pictures/* . К шаблонам пути применяются следующие правила:

Если у вас есть URL-адреса, содержащие строку запроса, например /images.php?image=fred.jpg , вы не можете выборочно аннулировать объекты, которые отличаются только строкой запроса. Например, если у вас есть два изображения, /images.php?image=fred.jpg и /images.php?image=barney.jpg , вы не можете аннулировать только fred.jpg . Чтобы аннулировать все изображения, предоставляемые images.php, используйте /images.php в качестве шаблона пути.

Аннулирование кеша для одного хоста

Вы можете ограничить аннулирование только одним из хостов, добавив в команду флаг --host.

Ограничения

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

В качестве альтернативы рутинным аннулированиям вы можете заблаговременно установить соответствующие сроки истечения срока действия ответов или использовать разные URL-адреса для разных версий вашего контента. Дополнительную информацию о сроках действия см. в разделе Сроки действия и запросы проверки.

Недействительные значения ограничены по частоте. Вы можете отправить не более одного аннулирования в минуту. Однако недействительность может быть любого размера. Аннулирование файла /images/fred.jpg считается одной инвалидацией. Аннулирование /images/* также считается одной инвалидацией.

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

Поскольку Cloud CDN — это распределенная система, она может сообщать о завершении аннулирования, даже если небольшое количество кешей еще не обработало запрос на аннулирование. Такая ситуация возникает редко и исправляется автоматически.

Что дальше

Чтобы узнать, как аннулировать кэшированный контент Cloud CDN, см. статью Аннулирование кэшированного контента.

Чтобы узнать, какой контент можно кэшировать, а какой нет, см. раздел Обзор кэширования.

Если не указано иное, содержимое этой страницы предоставляется по лицензии Creative Commons Attribution 4.0, а образцы кода — по лицензии Apache 2.0. Подробнее см. в Правилах сайта Google Developers. Java является зарегистрированным товарным знаком Oracle и/или ее дочерних компаний.

Читайте также: