Модель истечения срока годности. Определение срока годности под управлением сервера

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

Предполагается, что серверы припишут в явном виде значения времени пригодности (expiration time) откликам в предположении, что объекты вряд ли изменятся семантически значимым образом до истечения этого времени. Это сохраняет семантическую прозрачность при условии, что время жизни выбрано корректно.

Механизм времени пригодности (expiration) применим только к откликам, взятым из кэша, а не к откликам, полученным из первых рук и переадресованных запрашивающему клиенту.

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

Если исходный сервер хочет заставить любой HTTP/1.1 кэш, вне зависимости от его конфигурации, проверять каждый запрос, он может применить директиву Cache-Control mustrevalidate.

Серверы определяют реальные времена сроков пригодности с помощью заголовка Expires или директивы максимального возраста заголовка Cache-Control.

Время пригодности (expiration time) не может использоваться для того, чтобы заставить агента пользователя обновить картинку на дисплее или перезагрузить ресурс; его семантика применима только для механизма кэширования, а такой механизм нуждается только в контроле истечения времени жизни ресурса, когда инициируется новый запрос доступа к этому ресурсу.

Эвристический контроль пригодности

Так как исходные серверы не всегда предоставляют значение времени пригодности в явном виде, HTTP кэши присваивают им значения эвристически, используя алгоритмы, которые привлекают для оценки вероятного значения времени пригодности другие заголовки (такие как Last-Modified time). Спецификация HTTP/1.1 не предлагает каких­-либо специальных алгоритмов, но налагает предельные ограничения на полученный результат. Так как эвристические значения времени жизни могут подвергнуть риску семантическую прозрачность, они должны применяться с осторожностью. Предпочтительнее, чтобы исходные серверы задавали время пригодности явно.

Вычисление возраста

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

В этом обсуждении используется термин "сейчас" для обозначения текущего показания часов на ЭВМ, выполняющей вычисление. ЭВМ, которая применяет HTTP, и в особенности ЭВМ, работающие в качестве исходных серверов и кэшей, должны задействовать NTP [7.28] или некоторый схожий протокол для синхронизации их часов с использованием общего точного временного стандарта.

Следует обратить внимание на то, что HTTP/1.1 требует от исходного сервера посылки в каждом отклике заголовка Date, сообщая время, когда был сгенерирован отклик. Мы пользуемся термином date_value для обозначения значения заголовка Date, в форме, приемлемой для арифметических операций.

HTTP/1.1 использует заголовок отклика Age для того, чтобы облегчить передачу информации о возрасте объектов между кэшами. Значение заголовка Age равно оценке отправителем времени, прошедшего с момента генерации отклика исходным сервером. В случае кэшированного отклика, который был перепроверен исходным сервером, значение Age базируется на времени перепроверки, а не на времени жизни оригинального отклика.

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

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

1. Текущее время минус date_value, если местные часы синхронизованы с часами исходного сервера. Если результат отрицателен, он заменяется на нуль.

2. age_value, если все кэши вдоль пути отклика поддерживают HTTP/1.1.

Таким образом, мы имеем два независимых способа вычисления возраста отклика при его получении; допускается их комбинирование, например:

corrected_received_age = max(now date_value, age_value)

и, поскольку мы имеем синхронизованные часы или все узлы вдоль пути поддерживают HTTP/1.1, получается достаточно надежный результат.

Заметьте, что поправка применяется в каждом кэше HTTP/1.1 вдоль пути так, что если встретится на пути кэш HTTP/1.0, правильное значение возраста будет получено, потому что его часы почти синхронизованы. Нам не нужна сквозная синхронизация (хотя ее неплохо бы иметь).

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

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

corrected_initial_age = corrected_received_age + (now request_time)

где request_time равно времени (согласно местным часам), когда был послан запрос, вызвавший данный отклик.

Резюме алгоритма вычисления возраста при получении отклика кэшем:

/*
* age_value
*
равно значению Age: заголовок, полученный кэшем с этим откликом.


• date_value
*
равно значению Date исходного сервера: заголовок


* request_time
*
равно местному времени, когда кэш сделал запрос,
который явился причиной этого кэшированного отклика


* response_time
*
равно местному времени, когда кэш получил отклик


* now
*
равно текущему (местному) времени


*/
apparent_age = max(0, response_time date_value);
corrected_received_age = max(apparent_age, age_value);
response_delay = response_time request_time;
corrected_initial_age = corrected_received_age + response_delay;
resident_time = now response_time;
current_age = corrected_initial_age + resident_time;

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

Клиент не может надежно сказать, что отклик получен из первых рук, но присутствие заголовка Age определенно указывает на то, что это не так. Кроме того, если значение в отклике соответствует более раннему времени, чем местное время запроса клиента, отклик, вероятно, получен не из первых рук (в отсутствие серьезного сбоя часов).

Наши рекомендации