войти зарегистрироваться

WEBO Site SpeedUp whois

индекс
119,84

Клиентское кэширование: основы, автоматизация, препятствия

В блоге Web Optimizer (продукта для автоматизации клиентской оптимизации) Николай Мациевский регулярно публикует интересные посты о клиентской оптимизации, раскрывая всё новые подробности этого перспективного направления в веб-разработке. По ряду причин Николай пишет статьи на английском языке. Чтобы все статьи были доступны и на русском языке, я предложил ему свою помощь с переводом. Далее перевод первой статьи из серии, посвященной тонкостям кэширования в клиентской оптимизации.

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


Основы кэширования


Очень просто кэшировать один произвольный файл. Достаточно лишь добавить к запросу заголовок Cache-Control (для HTTP/1.1) и заголовок Expires (для HTTP/1.0). Заголовки будут выглядеть следующим образом:

Expires: Thu, 31 Dec 2019 23:55:55 GMT
Cache-Control: max-age=315360000


Все действительно настолько просто? Ну, практически.

Кэширование на прокси-серверах


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

Можно ли влиять на этот процесс? В RFC 2616 описан способ, позволяющий сообщить прокси-серверам, что содержимое желательно кэшировать: Cache-Control: public. Приведенный выше пример примет следующий вид:

Expires: Thu, 31 Dec 2037 23:55:55 GMT
Cache-Control: max-age=315360000, public


Автоматизация кэширования


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

ExpiresActive On
ExpiresDefault "access plus 10 years"


Выглядит достаточно просто, какие могут быть проблемы?

Что именно следует кэшировать?


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

ExpiresActive On
ExpiresDefault "access plus 10 years"
<FilesMatch \.(html|xhtml|xml|shtml|phtml|php)$>
ExpiresActive Off


Но что если часть CSS- и JS-файлов, а может быть и часть изображений на сайте создаются динамически? Например, если картинки для предпросмотра и ряд стилей создаются при помощи PHP на лету?

ExpiresByType – наша волшебная палочка!


Мы можем использовать директиву ExpiresByType, чтобы кэшировать необходимые файлы исходя из их MIME-типа (который обычно корректно задается сервером). В этом случае директивы могут быть такими:

ExpiresActive On
ExpiresByType text/css A315360000


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

Возможные препятствия


При использовании описанных подходов может возникнуть множество менее распространенных проблем:
  • У ряда ресурсов (например, у файлов шрифтов) могут быть нестандартные MIME-типы. В подобных ситуациях заголовки кэширования могут быть применены только на основания расширения файлов с использованием FilesMatch. Но поскольку сложно гарантировать одинаковое поведение произвольного серверного окружения, лучше сочетать оба подхода: устанавливать заголовки с помощью FilesMatch и ExpiresByType.
  • Как определять какие файлы кэшировать? Web Optimizer имеет огромное количество предопределенных MIME-типов и расширений, позволяющих обработать практически любые статические ресурсы на сервере. В нем также есть несколько вариантов управления режимами кэширования.
  • Если на сервере отсутствует поддержка mod_expires, ее можно эмулировать при помощи light PHP proxy. В случае, если отсутствует mod_rewrite, можно организовать внутренние редиректы для всех ресурсов на этот прокси и все файлы будут закэшированы.
  • Если же на сервере нет поддержки ни mod_expires ни mod_rewrite, необходимо разбирать HTML-код и заменять все вызовы статических ресурсов их эквивалентами используя PHP proxy. Только и всего.

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

комментарии (14)

  • Весело, переводы на русский английский статей написанных русскими
    • А есть ли по-вашему существенная разница в какую сторону переводить? Два перевода — два отдельных текста. Мы просто разделили работу на двоих.
  • Кстати, а как там у Николая, книгу «Реактивные веб-сайты» уже в издательстве одобрили? :)
    • Одобрили, куда ж им деться: ) Сейчас корректируют, вычитывают.
    • не минусуйте человека, он просто спросил! :)
  • Ничего если я замечу что как-то _неэлегантно_ WebOptimizer в этой статье пиарится?))
    • Ничего, если я обращу ваше внимание на то, в каком блоге опубликована статья?: )
  • Вы, конечно, молодец, что уже знаете, что такое RFC и спецификации, но читать их непробовали?

    заголовок Expires (для HTTP/1.0).

    Цитаты из HTTP/1.1 Header Field Definitions:
    This section defines the syntax and semantics of all standard HTTP/1.1 header fields.

    14.21 Expires


    Там же написано, что

    #sec14.21
    • The presence of an Expires header field with a date value of some time in the future on a response that otherwise would by default be non-cacheable indicates that the response is cacheable
      т.е. в Cache-control нет нужды.

      И главное:
      HTTP/1.1 servers SHOULD NOT send Expires dates more than one year in the future.


      Так что почитайте спеки, gkond. ^_~
      • 1. Expires пришел в HTTP/1.1 из HTTP/1.0
        www.ietf.org/rfc/rfc1945.txt
        Раздел 10.7

        2. should not ни к чему не обязывает. Это просто рекомендация. Если бы было must not, тогда совсем другое дело

        3. Если Вас смущает дублирование Expires / Cache-Control, то Expires нужен для клиентов, поддерживающих только HTTP/1.0, а Cache-Control в данном случае нужен для public / private
        • а Cache-Control в данном случае нужен для public / private

          В таком случае зачем там max-age?
          А как же HTTP/1.1 секция 13.4:
          Unless specifically constrained by a cache-control directive, a caching system MAY always store a successful response (see section 13.8) as a cache entry, MAY return it without validation if it is fresh, and MAY return it after successful validation.

          A response received with a status code of 200, 203, 206, 300, 301 or 410 MAY be stored by a cache and used in reply to a subsequent request.


          2. should not ни к чему не обязывает. Это просто рекомендация. Если бы было must not, тогда совсем другое дело

          RFC 2119:
          4. SHOULD NOT This phrase, or the phrase «NOT RECOMMENDED» mean that
          there may exist valid reasons in particular circumstances when the
          particular behavior is acceptable or even useful, but the full
          implications should be understood and the case carefully weighed
          before implementing any behavior described with this label.


          Перевожу на русский язык: не знаешь – не лезь. Зачем вам ставить expires >+1y? Все ли опасности знаете? Весь ли смысл этого действия осознаёте?
          • знаем, осознаем. Успокоились? :)

            Вы еще приведите оттуда раздел про ограничение в 2 соединения на хост. Много чего за 10 лет изменилось.
            • знаем, осознаем. Успокоились? :)

              Объясните смысл установки max-age/expires в 28 лет.
              Какая от этого польза? Вдруг кому-то не придётся обновлять кеш, если год назад он что-то сохранил? Т.е. вероятность мизерна. Польза — экономия одного запроса в год.

              Опасность? Некоторые клиенты и прокси могут проигнорировать такую установку, решив, что 28 лет — абсурд. В результате будут бить динамически с каждым запросом.
              Вероятность — похожая. Ущерб — сотни запросов в год.

              Expected return — ущерб 0,01 запроса в год. Зачем?

              Вы еще приведите оттуда раздел про ограничение в 2 соединения на хост. Много чего за 10 лет изменилось.
              Аналогия не корректна. Приведу цитату полностью:
              These guidelines are intended to improve HTTP response times and avoid congestion.

              Сейчас можно рассчитывать, что и с 6 соединениями не будет больших проблем с response times и congestion.
              Выгода очевидна: скорость для пользователя.
              Вероятность выгоды: 100%

              Опастность: затормозим некий сервер.
              Вероятность: 5% (из задницы)

              Expected return: положительна.

              Нет?
              • Много букв. Не хочу кормить тролля. Успокойтесь уже наконец.
Только авторизованные пользователи могут оставлять комментарии. Авторизуйтесь, пожалуйста.