Что такое кэширование


Кэширование и производительность веб-приложений / RUVDS.com corporate blog / Habr

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

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

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

Процессорный кэш


Начнём наш разговор о кэшах с самого низкого уровня — с процессора. Кэш-память процессора — это очень быстрая память, которая играет роль буфера между процессором (CPU) и оперативной памятью (RAM). Кэш-память хранит данные и инструкции, к которым обращаются чаще всего, благодаря чему процессор может получать ко всему этому доступ практически мгновенно.

В процессорах имеется особая память, представленная регистрами процессора, которая обычно представляет собой небольшое хранилище информации, обеспечивающее крайне высокую скорость обмена данными. Регистры — это самая быстрая память, с которой может работать процессор, которая расположена максимально близко к остальным его механизмам и имеет небольшой объём. Иногда регистры называют кэшем нулевого уровня (L0 Cache, L — это сокращение от Layer).

У процессоров, кроме того, имеется доступ к ещё нескольким уровням кэш-памяти. Это — до четырёх уровней кэша, которые, соответственно, называются кэшами первого, второго, третьего, и четвёртого уровня (L0 — L4 Cache). То, к какому именно уровню относятся регистры процессора, в частности, будет ли это кэш нулевого или первого уровня, определяется архитектурой процессора и материнской платы. Кроме того, от архитектуры системы зависит то, где именно — на процессоре, или на материнской плате, физически расположена кэш-память разных уровней.


Структура памяти в некоторых новейших CPU

Кэш жёсткого диска


Жёсткие диски (HDD, Hard Disk Drive), применяемые для постоянного хранения данных — это, в сравнении с оперативной памятью, предназначенной для кратковременного хранения информации, устройства довольно медленные. Однако надо отметить, что скорость постоянных хранилищ информации увеличивается благодаря распространению твердотельных накопителей (SSD, Solid State Drive).

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


Кэш жёсткого диска

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

О быстродействии жёстких дисков и оперативной памяти


Разница между временным хранением данных в оперативной памяти и постоянным хранением на жёстком диске проявляется в скорости работы с информацией, в стоимости носителей и в близости их к процессору.

Время отклика оперативной памяти составляет десятки наносекунд, в то время как жёсткому диску нужны десятки миллисекунд. Разница в быстродействии дисков и памяти составляет шесть порядков!


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

Простой веб-сервер


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

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

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

При последующих запросах, направленных на получение тех же данных, поиск в кэше окажется успешным, это — так называемое «попадание кэша». Данные в ответ на запрос будут поступать из дискового буфера до тех пор, пока они не будут перезаписаны, что, при повторном обращении к тем же данным, приведёт к промаху кэша.

Кэширование баз данных


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

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

Кэширование ответов веб-сервера


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

Ответы веб-сервера кэшируются в оперативной памяти. Кэш приложения может храниться либо локально, в памяти, либо на специальном кэширующем сервере, который использует базу данных, вроде Redis, которая хранит данные в оперативной памяти.

Мемоизация функций


Сейчас поговорим об оптимизации производительности серверного приложения за счёт мемоизации. Это — разновидность кэширования, применяемая для оптимизации работы с ресурсоёмкими функциями. Данная техника позволяет выполнять полный цикл вычислений для определённого набора входных данных лишь один раз, а при следующих обращениях к функции с теми же входными данными сразу выдавать найденный ранее результат. Мемоизация реализуется посредством так называемых «таблиц поиска» (lookup table), хранящих ключи и значения. Ключи соответствуют входным данным функции, значения — результатам, которые возвращает функция при передаче ей этих входных данных.
Мемоизация функции с помощью таблицы поиска

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

Кэширование в браузере


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

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

Перед нами весьма полезная технология, которая даёт следующие преимущества всем участникам обмена данными:

  • Улучшаются впечатления пользователя от работы с сайтом, так как ресурсы из локального кэша загружаются очень быстро. Во время получения ответа не входит время прохождения сигнала от клиента к серверу и обратно (RTT, Round Trip Time), так как запрос не уходит в сеть.
  • Уменьшается нагрузка на серверное приложение и на другие серверные компоненты, ответственные за обработку запросов.
  • Высвобождается некоторая часть сетевых ресурсов, которыми теперь могут воспользоваться другие пользователи интернета, экономятся средства на оплату трафика.


Кэширование в браузере

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


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

▍Шлюзы


Шлюз (gateway) — это прокси-сервер, который перенаправляет входящие запросы или исходящие ответы, не модифицируя их. Такие прокси-серверы ещё называют туннелирующими прокси (tunneling proxy), веб-прокси (web proxy), прокси (proxy), или прокси уровня приложения (application level proxy). Эти прокси-серверы обычно совместно используются, например, всеми клиентами, находящимися за одним и тем же файрволом, что делает их хорошо подходящими для кэширования запросов.

▍Прямые прокси-серверы


Прямой прокси-сервер (forward proxy, часто такие серверы называют просто proxy server) обычно устанавливается на стороне клиента. Веб-браузер, который настроен на использование прямого прокси-сервера, будет отправлять исходящие запросы этому серверу. Затем эти запросы будут перенаправлены на целевой сервер, расположенный в интернете. Одно из преимуществ прямых прокси заключаются в том, что они защищают данные клиента (однако, если говорить об обеспечении анонимности в интернете, безопаснее будет пользоваться VPN).

▍Веб-ускорители


Веб-ускоритель (web accelerator) — это прокси-сервер, который уменьшает время доступа к сайту. Он делает это, заранее запрашивая у сервера документы, которые, вероятнее всего, понадобятся клиентам в ближайшем будущем. Подобные серверы, кроме того, могут сжимать документы, ускорять выполнение операций шифрования, уменьшать качество и размер изображений, и так далее.

▍Обратные прокси-серверы


Обратный прокси-сервер (reverse proxy) — это обычно сервер, расположенный там же, где и веб-сервер, с которым он взаимодействует. Обратные прокси-серверы предназначены для предотвращения прямого доступа к серверам, расположенным в частных сетях. Обратные прокси используются для балансировки нагрузки между несколькими внутренними серверами, предоставляют возможности SSL-аутентификации или кэширования запросов. Такие прокси выполняют кэширование на стороне сервера, они помогают основным серверам в обработке большого количества запросов.

▍Пограничное кэширование


Обратные прокси-серверы расположены близко к серверам. Существует и технология, при использовании которой кэширующие серверы располагаются как можно ближе к потребителям данных. Это — так называемое пограничное кэширование (edge caching), представленное сетями доставки контента (CDN, Content Delivery Network). Например, если вы посещаете популярный веб-сайт и загружаете какие-нибудь статические данные, они попадают в кэш. Каждый следующий пользователь, запросивший те же данные, получит их, до истечения срока их кэширования, с кэширующего сервера. Эти серверы, определяя актуальность информации, ориентируются на серверы, хранящие исходные данные.
Прокси-серверы в инфраструктуре обмена данными между клиентом и сервером

Итоги


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

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

Уважаемые читатели! Какие технологии кэширования вы используете в своих проектах?

habr.com

Как очистить кэш браузера и зачем это нужно?

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

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

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

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

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

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

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

Стоит также отметить, что далеко не всё содержимое сайта кэшируется. Настройки кэша выставляются каждым веб-мастером по собственному усмотрению. Если же информационный ресурс создается при помощи CMS (WordPress, Joomla, Drupal), то разработчику, как правило, доступны уже готовые решения по обеспечению кеширования в виде плагинов (которые имеют стандартные установки и часто не нуждаются в дополнительных настройках).

В CMS WordPress, к примеру, широкую популярность обрели плагины WP Super Cache и W3 Total Cache.

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

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

Когда вы сталкиваетесь с разработкой информационного ресурса, то очистка кэша – настолько привычная и регулярная процедура, что проводится абсолютно «на автомате» (ведь сайт всё время меняется, а результат нужно увидеть сразу же).

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

Также не стоит забывать и о том, что копии страниц, сохраненные браузером, имеют кое-какой вес. Кроме того, каждый браузер имеет свой собственный кэш, то есть, открыв веб-ресурс в Гугл Хром, а затем в Firefox, вы создадите на своем компьютере 2 копии одних и тех же страниц. А если сайтов посещено тысячи, и кэш не очищался несколько месяцев, то место, занимаемое копиями, будет довольно существенное.

Рассмотрим удаление кэша в некоторых популярных на сегодняшний день браузерах:

  • Интернет Эксплорер:


Заходим в меню браузера, после чего ищем пункт «Сервис». Нажимаем «Удалить журнал обозревателя», а в появившемся окне ставим галочку только напротив пункта «Временные файлы интернета». Жмем «Удалить».


Переходим в меню и выбираем пункт «Настройки». Открываем вкладку «Дополнительные» и ищем в ней пункт «Сеть». Перейдя к содержимому, видим, среди прочего, надпись «Кэшированное веб-содержимое», напротив которой расположена кнопка «Очистить сейчас». Жмем по заветной кнопке и процесс завершен.


Для того чтобы очистить кэш в браузере Хром, заходим в меню и открываем пункт «Инструменты». Нажимаем на «Показать дополнительные настройки», после чего кликаем по «Очистить историю». Если нужно очистить весь кэш, то указываем период «За всё время», а галочку ставим только напротив пункта «Изображения и другие файлы, сохраненные в кэше». Жмем на «Очистить историю».


Заходим в раздел «Настройки», кликаем на «Безопасность». Нажимаем на «Очистить историю посещений», а в разделе «Уничтожить следующие элементы» стоит выбрать «С самого начала» (если хотим очистить весь кэш). Ставим галочку только напротив «Очистить кэш» и нажимаем на «Очистить историю». Процесс завершен.

  • Яндекс.Браузер:


Для того чтобы очистить кэш в Яндекс.Браузере, заходим в меню и выбираем вкладку «Инструменты». Переходим в «Удаление данных о просмотренных страницах».

Чтобы очистить весь кэш, в выпадающем списке рядом с надписью «Удалить указанные ниже элементы» выбираем «За все время». Ставим отметку только напротив пункта «Очистить кэш» и кликаем по кнопке «Очистить историю».

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

www.internet-technologies.ru

Гид по заголовкам кэширования HTTP для начинающих / Habr

В статье данные сведения по заголовкам кэширования (ЗК) для HTTP и соответствующее поведение сетей доставки контента (CDN). Если вам хочется разобраться, каким образом заголовки кэширования вписываются в современный веб, или вам просто интересно, о чём говорят ваши коллеги – эта статья для вас.

Если вы уже понимаете преимущества ЗК, и хотите расширить свои знания, я рекомендую вам обратиться к документации от W3.

Что могут ЗК сделать для вас?

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

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

В случае ресурсов вроде логотипа вашей компании, favicon сайта или основных CSS-файлов, которые не меняются от запроса к запросу, можно разрешить запрашивающему хранить копии этих файлов какое-то время. Если бы ваши посетители были детьми на заднем сиденье автомобиля, которые бы всё время спрашивали вас «Мы уже приехали?», то это разрешение было бы сродни ответу «Нет, и нам ехать ещё 20 минут, так что запомните мой ответ».

Уменьшая количество запросов к серверу, вы увеличиваете число запросов, которые он может обработать. Картинки, скрипты и таблицы стилей обычно можно кэшировать в хвост и гриву, а динамически создаваемые страницы (форумы, веб-приложения) обычно не стоит. Если вы беспокоитесь в первую очередь за производительность, весь ваш динамический контент должен быть сведён к минимуму ресурсов AJAX, а остальные ресурсы должны кэшироваться по-максимуму.

Для клиентов и CDN

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

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

При правильной настройке, CDN передаёт ваш контент клиентам через самый быстрый и ближайший к нему сервер. Кроме этого, CDN работает буфером между вами и пользователями. Нас интересует процент количества кэшированных запросов – тех запросов, которые CDN обработало, не дёргая наш сервер. В зависимости от трафика и архитектуры этот номер может достигать и 90%, хотя эффект вы заметите и при меньших цифрах. Надо заметить, что при небольшом количестве запросов большая их часть будет отправляться на ваш сервер – поэтому этот процент имеет смысл только вместе с временем кэширования и общей нагрузкой сайта. Но если вы настроите один лишь кэш, а заголовки кэширования будут работать неправильно, итоговые показатели могут даже стать хуже, чем были.


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

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

Основные заголовки

1. cache-control

Самый главный из всех. Обычно вы задаёте в строке его параметры, нечто вроде:

cache-control: private, max-age=0, no-cache

Эти настройки называются директивы ответа кэша, и они бывают следующие:

private | public

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

no-cache

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

no-store

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

max-age

Обычно время жизни ресурса задаётся через expires, но если вам надо быть более конкретным, можно задать max-age в секундах. И эта директива имеет преимущество над expires.

s-maxage

Немного похоже на предыдущую, однако s здесь означает shared cache, и нужна для CDN. Эта директива имеет преимущество над max-age и expires, когда речь идёт о CDN-серверах.

must-revalidate

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

no-transform

Некоторые прокси умеют сжимать и конвертировать контент для ускорения работы. Эта директива запрещает подобное поведение.

proxy-revalidate

Примерно то же, что must-revalidate, но для промежуточных CDN-серверов. Почему её не назвали s-mustrevalidate? Кто его знает. Смысл в том, что проверять, не обновился ли контент, нужно для каждого нового пользователя только один раз.

2. expires

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

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

3. etag

Сокращение от entity-tag. Это уникальный идентификатор запрашиваемого ресурса – обычно, некий хэш его содержимого, или хэш времени его обновления. В общем, способ клиента запросить у CDN «дай мне ресурс Х, если у него etag отличается от моего».
4. vary

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

Часто можно встретить заголовок типа Accept-Encoding, который удостоверяется, что ваши ресурсы, сжатые gzip, будут приняты клиентом. Это здорово сберегает трафик. Кроме этого, настройка

vary: User-Agent

сделает ваш сайт более дружественным к SEO, если вы раздаёте разные HTML/CSS в зависимости от User-Agent. Google заметит эту штучку и Googlebot будет обрабатывать и ваш мобильный контент.

5. pragma

Довольно старая директива, которая умеет делать много чего, что, однако, уже обрабатывается при помощи более современных. Нам более всего интересна форма

pragma: no-cache

что в современных клиентах превращается в

cache-control: no-cache

Предостережения

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

Кроме того, вы могли заметить, что некоторые заголовки дублируют друг друга или их области применения перекрываются. Это происходит из-за небольших различий у разных методов, или из-за перехода веба с HTTP/1.0 на протокол HTTP/1.1, в котором кэширование расписано более подробно.

1. Сжатие

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

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

2. SSL

CDN – это человек-в-середине. Вам нужно подумать об организации HTTPS-трафика и о том, как он идёт к вам на сервер. Многие CDN перенаправят запрос к somesite.com/asset на адрес somesite.com/asset, поэтому если логика вашего сервера зависит от протокола, либо поменяйте логику, либо попросите CDN сделать переадресацию на HTTPS.
А что же с динамическим контентом?

Обычно в этом случае надо задавать cache-control: no-cache, чтобы CDN не кэшировали его. Если вам интересно, как можно немного ускорить и его работу, продолжайте чтение.

Типичный динамический контент

HTTP/1.1 200 OK Server: Apache X-Rack-Cache: miss ETag: "e6811cdbcedf972c5e8105a89f637d39-gzip" Status: 200 Content-Type: text/html; charset=utf-8 Expires: Mon, 29 Apr 2013 21:44:55 GMT Cache-Control: max-age=0, no-cache, no-store Pragma: no-cache Date: Mon, 29 Apr 2013 21:44:55 GMT 

Большая часть динамического контента не такая уж и непостоянная. Список активных пользователей, к примеру, имеет время жизни 10-20 секунд. Страницы с графиками наверняка могут пожить несколько минут. Новостная лента может некоторое время и покэшироваться, особенно при наличии etag. Если загрузка вашего сайта велика, стоит попробовать кэшировать ненадолго некоторые его ресурсу

Анализ времени кэширования

Так какое время для хранения ресурсов лучше задавать? Это зависит от количества трафика, размера ресурсов, размера кэша.

Кроме того, надо подумать о главном недостатке кэширования – уменьшении контроля над ресурсами. Если вам надо обновить ресурс мгновенно, у вас будут проблемы, если вы некоторое время назад задали ему время жизни в год. Особенно, если вы задали это время не только для CDN (s-maxage), но и для пользователей (max-age).

Самый длительный промежуток для кэша – год, или 31536000. Но это плохая идея. Это всё равно, что сделать татуировку на лице. Если ваши сервера не выдерживают хотя бы ежедневных запросов от CDN по поводу того, изменился ли ресурс,- пора менять сервера.

Заголовки для статичного контента

HTTP/1.1 200 OK Cache-Control: no-transform,public,max-age=300,s-maxage=900 Content-Type: text/html; charset=UTF-8 Date: Mon, 29 Apr 2013 16:38:15 GMT ETag: "bbea5db7e1785119a7f94fdd504c546e" Last-Modified: Sat, 27 Apr 2013 00:44:54 GMT Server: AmazonS3 Vary: Accept-Encoding X-Cache: HIT 

Пример настроек кэша для статичного контента с S3. Кэшу рекомендуется хранить ресурс 900 секунд, пользовательским программам – 300 секунд. Последний заголовок говорит о том, какой из CDN обработал запрос.

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

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

Время кэширования (мин) Процент запросов к кэшу Запросов к оригиналу в час
1 99.8% 60
5 99.96% 12
20 99.99% 3
60 99.997% 1
86400 99.9998% <1

Какой процент запросов к кэшу вас устроит? Обычно от 60 секунд до 60 минут – нормальное время жизни для ресурса. Для псевдо-динамического контента можно устанавливать время кэширования в промежутке до 60 секунд.

Проверка CDN

Проверяйте, что заголовки проходят через CDN так, как вы этого ожидаете. Обычно CDN вставляет какой-нибудь Х- заголовок, где указывает подробности по данному ресурсу. Вот некоторые инструменты, которые показались мне довольно полезными.
1. Web Inspector

Самый простой метод – правый клик на странице в Chrome, выбрать Inspect Element, перейти на закладку Network и нажать на ресурс HTML. Если это не выбрано по умолчанию, выбрать закладку Headers, чтобы посмотреть все заголовки. Также в Chrome есть возможности задать user agent и не использовать локальный кэш.
2. Charles Proxy

Через такой прокси можно перенаправить трафик и манипулировать запросами DNS, записывать заголовки, смотреть статистику быстродействия – всё это в понятном и простом GUI.
3. cURL

Делайте запросы из командной строки и просматривайте заголовки ответов. Полезные ключи: -A просмотр user anget, -b – куки, -F – данные форм, -H – назначить заголовки, -I – запрос только заголовков.
4. hurl.it

Грубо говоря, это cURL с понятным интерфейсом. Можно задавать заголовки и просматривать заголовки ответа и тело ответа.
5. Python и Requests

Requests – библиотека для Python для веб-запросов. С её помощью можно написать автоматизированные тесты для вашего сайта.
Заметки на полях

Теперь, когда вы прочли весь гид, немного замечаний.

Большинство веб-серверов, таких, как Apache и Nginx, делают большую часть работы за вас. Вам придётся работать только с заголовком cache-control. Браузеры обычно настроены на сильное кэширование контента, поэтому вам чаще приходится бороться с излишним кэшированием, нежели наоборот. Обычно вы задаёте некий путь вроде “/static”, который кэшируется какое-то разумное время, например, 300 секунд. Затем надо убедиться, что корневой путь "/" отдаётся с заголовком “cache-control: no-cache”, а лучше перенаправлять пользователя за динамическим контентом прямо на ваши сервера, и оставлять для CDN только то, что лежит в “/static”.

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

За дополнительными материалами по ускорению работы сайта рекомендуем обратиться к документации Mobile Web Performance.

habr.com

Кэширование и memcached / Habr

Этим постом хочу открыть небольшую серию постов по материалам доклада на HighLoad++-2008. Впоследствии весь текст будет опубликован в виде одной большой PDF-ки.

Введение


Для начала, о названии серии постов: посты будут и о кэшировании в Web’е (в высоконагруженных Web-проектах), и о применении memcached для кэширования, и о других применениях memcached в Web-проектах. То есть все три составляющие названия в различных комбинациях будут освещены в этой серии постов.

Кэширование сегодня является неотъемлемой частью любого Web-проекта, не обязательно высоконагруженного. Для каждого ресурса критичной для пользователя является такая характеристика, как время отклика сервера. Увеличение времени отклика сервера приводит к оттоку посетителей. Следовательно, необходимо минимизировать время отклика: для этого необходимо уменьшать время, требуемое на формирование ответа пользователю, а ответ пользователю требует получить данные из каких-то внешних ресурсов (backend). Этими ресурсами могут быть как базы данных, так и любые другие относительно медленные источники данных (например, удаленный файловый сервер, на котором мы уточняем количество свободного места). Для генерации одной страницы достаточно сложного ресурса нам может потребоваться совершить десятки подобных обращений. Многие из них будут быстрыми: 20 мс и меньше, однако всегда существует некоторое небольшое количество запросов, время вычисления которых может исчисляться секундами или минутами (даже в самой оптимизированной системе один могут быть, хотя их количество должно быть минимально). Если сложить всё то время, которое мы затратим на ожидание результатов запросов (если же мы будем выполнять запросы параллельно, то возьмем время вычисления самого долгого запроса), мы получим неудовлетворительное время отклика.

Решением этой задачи является кэширование: мы помещаем результат вычислений в некоторое хранилище (например, memcached), которое обладает отличными характеристиками по времени доступа к информации. Теперь вместо обращений к медленным, сложным и тяжелым backend’ам нам достаточно выполнить запрос к быстрому кэшу.

Memcached и кэширование


Принцип локальности


Кэш или подход кэширования мы встречаем повсюду в электронных устройствах, архитектуре программного обеспечения: кэш ЦП (первого и второго уровня), буферы жесткого диска, кэш операционной системы, буфер в автомагнитоле. Чем же определяется такой успех кэширования? Ответ лежит в принципе локальности: программе, устройству свойственно в определенный промежуток времени работать с некоторым подмножеством данных из общего набора. В случае оперативной памяти это означает, что если программа работает с данными, находящимися по адресу 100, то с большей степенью вероятности следующее обращение будет по адресу 101, 102 и т.п., а не по адресу 10000, например. То же самое с жестким диском: его буфер наполняется данными из областей, соседних по отношению к последним прочитанным секторам, если бы наши программы работали в один момент времени не с некоторым относительно небольшим набором файлов, а со всем содержимым жесткого диска, буферы были бы бессмысленны. Буфер автомагнитолы совершает упреждающее чтение с диска следующих минут музыки, потому что мы, скорее всего, будем слушать музыкальный файл последовательно, чем перескакивать по набору музыки и т.п.

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

Кэш всегда лучше, чем исходный источник данных: кэш ЦП на порядки быстрее оперативной памяти, однако мы не можем сделать оперативную память такой же быстрой, как кэш – это экономически неэффективно и технически сложно. Буфер жесткого диска удовлетворяет запросы за данными на порядки быстрее самого жесткого диска, однако буфер не обладает свойством запоминать данные при отключении питания – в этом смысле он хуже самого устройства. Аналогичная ситуация и с кэшированием в Web’е: кэш быстрее и эффективнее, чем backend, однако он обычно в случае перезапуска или падения сервера не может сохранить данные, а также не обладает логикой по вычислению каких-либо результатов: он умеет возвращать лишь то, что мы ранее в него положили.

Memcached


Memcached представляет собой огромную хэш-таблицу в оперативной памяти, доступную по сетевому протоколу. Он обеспечивает сервис по хранению значений, ассоциированных с ключами. Доступ к хэшу мы получаем через простой сетевой протокол, клиентом может выступать программа, написанная на произвольном языке программирования (существуют клиенты для C/C++, PHP, Perl, Java и т.п.).

Самые простые операции – получить значение указанного ключа (get), установить значение ключа (set) и удалить ключ (del). Для реализации цепочки атомарных операций (при условии конкурентного доступа к memcached со стороны параллельных процессов) используются дополнительные операции: инкремент/декремент значения ключа (incr/decr), дописать данные к значению ключа в начало или в конец (append/prepend), атомарная связка получения/установки значения (gets/cas) и другие.

Memcached был реализован Брэдом Фитцпатриком (Brad Fitzpatrick) в рамках работы над проектом ЖЖ (LiveJournal). Он использовался для разгрузки базы данных от запросов при отдаче контента страниц. Сегодня memcached нашел своё применение в ядре многих крупных проектов, например, Wikipedia, YouTube, Facebook и другие.

Общая схема кэширования


В общем случае схема кэширования выглядит следующим образом: frontend’у (той части проекта, которая формирует ответ пользователю) требуется получить данные какой-то выборки. Frontend обращается к быстрому как гепард серверу memcached за кэшом выборки (get-запрос). Если соответствующий ключ будет обнаружен, работа на этом заканчивается. В противном случае следует обращение к тяжелому, неповоротливому, но мощному (как слон) backend’у, в роли которого чаще всего выступает база данных. Полученный результат сразу же записывается в memcached в качестве кэша (set-запрос). При этом обычно для ключа задается максимальное время жизни (срок годности), который соответствует моменту сброса кэша.

Такая стандартная схема кэширования реализуется всегда. Вместо memcached в некоторых проектах могут использоваться локальные файлы, иные способы хранения (другая БД, кэш PHP-акселератора и т.п.) Однако, как будет показано далее, в высоконагруженном проекте данная схема может работать не самым эффективным образом. Тем не менее, в нашем дальнейшем рассказе мы будем опираться именно на эту схему.

Архитектура memcached


Каким же образом устроен memcached? Как ему удаётся работать настолько быстро, что даже десятки запросов к memcached, необходимых для обработки одной страницы сайта, не приводят к существенной задержке. При этом memcached крайне нетребователен к вычислительным ресурсам: на нагруженной инсталляции процессорное время, использованное им, редко превышает 10%.

Во-первых, memcached спроектирован так, чтобы все его операции имели алгоритмическую сложность O(1), т.е. время выполнения любой операции не зависит от количества ключей, которые хранит memcached. Это означает, что некоторые операции (или возможности) будут отсутствовать в нём, если их реализация требует всего лишь линейного (O(n)) времени. Так, в memcached отсутствуют возможность объединения ключей «в папки», т.е. какой-либо группировки ключей, также мы не найдем групповых операций над ключами или их значениями.

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

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

По сути, можно сказать, что время отклика сервера memcached определяется только сетевыми издержками и практически равно времени передачи пакета от frontend’а до сервера memcached (RTT). Такие характеристики позволяют использовать memcached в высоконагруженных web-проектов для решения различных задач, в том числе и для кэширования данных.

Потеря ключей

Memcached не является надежным хранилищем – возможна ситуация, когда ключ будет удален из кэша раньше окончания его срока жизни. Архитектура проекта должна быть готова к такой ситуации и должна гибко реагировать на потерю ключей. Можно выделить три основных причины потери ключей:
  1. Ключ был удален раньше окончания его срока годности в силу нехватки памяти под хранение значений других ключей. Memcached использует политику LRU, поэтому такая потеря означает, что данный ключ редко использовался и память кэша освобождается для хранения более популярных ключей.
  2. Ключ был удален, так как истекло его время жизни. Такая ситуация строго говоря не является потерей, так как мы сами ограничили время жизни ключа, но для клиентского по отношению к memcached кода такая потеря неотличима от других случаев – при обращении к memcached мы получаем ответ «такого ключа нет».
  3. Самой неприятной ситуацией является крах процесса memcached или сервера, на котором он расположен. В этой ситуации мы теряем все ключи, которые хранились в кэше. Несколько сгладить последствия позволяет кластерная организация: множество серверов memcached, по которым «размазаны» ключи проекта: так последствия краха одного кэша будут менее заметны.

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

«Можно потерять». К этой категории относятся кэши выборок из базы данных. Потеря таких ключей не так страшна, потому что мы можем легко восстановить их значения, обратившись заново к backend’у. Однако частые потери кэшей приводят к излишним обращениям к БД.

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

«Совсем не должны терять». Memcached удобен для хранения сессий пользователей – все сессии равнодоступны со всех серверов, входящих в кластер frontend’ов. Так вот содержимое сессий не хотелось бы терять никогда – иначе пользователей на сайте будет «разлогинивать». Как попытаться избежать? Можно дублировать ключи сессий на нескольких серверах memcached из кластера, так вероятность потери снижается.

habr.com

Первое знакомство с кэшем и процессом кэширования - Статьи TechNet - Россия (Pусский)

Первое знакомство с кэшем и процессом кэширования

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

Виды кэширования

При создании высоконагруженных систем одним из способов уменьшить вычислительную нагрузку на сервера баз данных есть использование механизма кэширования. Но это далеко не единственная сфера его применения. Давайте для начала рассмотрим, что же мы можем кэшировать. Если мы рассматриваем веб приложение, то кэшировать тут можно практически все, начиная от довольно статического контента представленного рисунками, css файлами, js файлами и т.д. и заканчивая наборами данных (результатами выборки из базы). Вполне логичным есть тот факт, что кэширование разных типов контента требует разных подходов, только так можно достичь максимальную эффективность от использования кэша.

 

Рисунок 1. Виды кэша и их место в архитектуре системы.

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

Кэш интернет обозревателя

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

Кэш веб сервера

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

Распределенный кэш

Для решения этой проблемы существует распределенный кэш. Этот кэш наследует идеи кэша в оперативной памяти, но – он гарантирует, что все клиенты которые запрашивают данные из кэша будет всегда получать самые актуальные данные, т.е. он гарантирует доступ к одним данным кэша для всех кэш клиентов. Таким образом мы решаем проблему синхронизации данных кэша между всеми кэш клиентами. Одним из примеров распределенного кэша может служить Windows Azure Caching. В таком кэше можно хранить любые сериализированные данные. Чаще всего его использует для хранения результатов выборки объектов из базы, хотя это не единственное его применение.

Сеть доставки контента

Еще одним важным видом кэширования есть сети доставки контента. Идея их очень проста и мы рассмотрим ее на примере. Итак, представьте, вы владелец огромного портала на котором пользователи хранят собственное видео, музыку и изображения. Огромное множество других пользователей со всего мира ходит на ваш портал с целью посмотреть интересное видео, послушать хорошую музыку и посмотреть красивые изображения. Ваша аудитория – весь мир. Вполне логично, что даже разместив веб сервера на каждом континенте вы не сможете одинаково хорошо обслуживать разных пользователей. Для этого есть как минимум одна причина – задержка в прохождении трафика от вашего сервера к конечному клиенту. Эта задержка происходит из-за банальной географической удаленности пользователя. Но, если мы сможем «приблизить» контент к пользователю, то мы сможем гарантировать более высокую пропускную способность наших серверов, а также, более комфортную работу пользователя с системой за счет уменьшения времени ожидания. Именно эту задачу нам помогают решить сети доставки контента. Сети доставки контента не просто кэшируют статический контент, они уменьшают путь между клиентом и сервером, решая попутно еще и задачу уменьшения количества трафика на веб сервера. Платформа Windows Azure имеет свою сеть доставки контента CDN, которую можно и нужно использовать для уменьшения трафика на веб сервера и увеличения производительности системы в целом.

Преимущества кэширования

Давайте рассмотрим более подробно, что собой представляет кэширование. Представьте, что вам нужно вычислить значение какого-либо уравнения, или, как более практичный пример – выбрать записи из базы данных. Вполне логично, что если вы нашли корни какого-либо уравнения, то искать их повторно для конкретно этого уравнения смысла нет, можно просто взять результат предыдущих вычислений. Аналогичная ситуация и с выборкой из базы данных – если мы нашли набор строк удовлетворяющих конкретному запросу с конкретными параметрами, и если на момент повторного запроса этих данных ничего в базе не изменилось, то нет смысла повторно вычислять этот запрос, можно взять готовый результат с прошлого раза. В данном контексте тяжело понять смысл фразы «на момент повторного запроса этих данных ничего в базе не изменилось». На самом деле можно подойти к этому вопросу с прагматичной стороны и вести механизм контроля изменения данных по отношению к конкретному запросу. Данный вопрос относится скорее к теме построения высоконагруженных баз данных, и обсуждать его в этой статье мы не будем. Я позволю себе только одно замечание – дополнительные затраты на обслуживания механизма контроля таких изменений должны перекрываться выигрышем в приросте производительности при использовании кэширования. Но, на практике, в большинстве проектов мы просто прогнозируем длину срока жизни данных. Т.е. мы помещаем данные в кэш априорно утверждая, что они будут актуальны ближайшие N минут. Это стандартный прием при использовании кэширования.

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

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

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

В заключение

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

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

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

social.technet.microsoft.com

Логическая организация кэш-памяти процессора / Habr

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

Кэш память процессора используется для уменьшения времени простоя процессора при обращении к RAM.

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

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

Так вот суть кэширования состоит в разбиении RAM на кэш-линии и отображении их на кэш-линии кэш-памяти. Возможно несколько вариантов такого отображения.

DIRECT MAPPING

Основная идея прямого отображения (direct mapping) RAM на кэш-память состоит в следующем: RAM делится на сегменты, причем размер каждого сегмента равен размеру кэша, а каждый сегмент в свою очередь делится на блоки, размер каждого блока равен размеру кэш-линии.

Блоки RAM из разных сегментов, но с одинаковыми номерами в этих сегментах, всегда будут отображаться на одну и ту же кэш-линию кэша:

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

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

b — размер кэш-линии.
m — количество кэш-линий в кэше.

Для адресации b байт внутри каждой кэш-линии потребуется: log2b бит.
Для адресации m кэш-линий внутри каждого сегмента потребуется: log2m бит.

m = Объем кэш-памяти/Размер кэш линии.

Для адресации N сегментов RAM: log2N бит.

N = Объем RAM/Размер сегмента.

Для адресации байта потребуется: log2N + log2m + log2b бит.

Этапы поиска в кэше:
1. Извлекается средняя часть адреса (log2m), определяющая номер кэш-линии в кэше.
2. Тэг кэш-линии с данным номером сравнивается со старшей частью адреса (log2N).

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

FULLY ASSOCIATIVE MAPPING

Основная идея полностью ассоциативного отображения (fully associative mapping) RAM на кэш-память состоит в следующем: RAM делится на блоки, размер которых равен размеру кэш-линий, а каждый блок RAM может сохраняться в любой кэш-линии кэша:

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

Тэг (tag) каждой кэш-линии хранит старшую часть адреса первого байта в данной кэш-линии.

b — размер кэш-линии.
m — количество кэш-линий, умещающихся в RAM.

Для адресации b байт внутри каждой кэш-линии потребуется: log2b бит.
Для адресации m кэш-линий: log2m бит.

m = Размер RAM/Размер кэш-линии.

Для адресации байта потребуется: log2m + log2b бит.

Этапы поиска в кэше:
1. Тэги всех кэш-линий сравниваются со старшей частью адреса одновременно.

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

SET ASSOCIATIVE MAPPING

Основная идея наборно ассоциативного отображения (set associative mapping) RAM на кэш-память состоит в следующем: RAM делится также как и в прямом отображении, а сам кэш состоит из k кэшей (k каналов), использующих прямое отображение.

Кэш-линии, имеющие одинаковые номера во всех каналах, образуют set (набор, сэт). Каждый set представляет собой кэш, в котором используется полностью ассоциативное отображение.

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

Структура адреса байта в точности такая же, как и в прямом отображении: log2N + log2m + log2b бит, но т.к. set представляет собой k различных кэш-линий, то поиск в кэше немного отличается.

Этапы поиска в кэше:
1. Извлекается средняя часть адреса (log2m), определяющая номер сэта в кэше.
2. Тэги всех кэш-линий данного сета сравниваются со старшей частью адреса (log2N) одновременно.

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

Т.о количество каналов кэша определяет количество одновременно сравниваемых тэгов.

habr.com

Масштабировать просто. Часть вторая — кэширование / Habr

В предыдущей части мы говорили об основных архитектурных принципах построения масштабируемых порталов. Сегодня поговорим об оптимизации правильно построенного портала. Итак: первый вид оптимизации — локальный кэш.
Часть вторая. Кэширование

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

Кэши — тема интересная и практически бесконечная. Поэтому я попробую обрисовать ее достаточно коротко, для первого раунда оптимизации, не вдаваясь в подробности о кэше 1 и 2 уровня, распределенном кэше (distributed cache) и т. д. Так как нам нужно кэшировать чтение объекта, пока мы пропустим и кэш записи (write cache).

Когда мы начинаем локальное кэширование, перед нами обычно стоит выбор: query или object cache (кэширование вызова или объекта). Query cache (или method cache) — это кэш, который можно использовать «снаружи»: он записывает результаты вызовов методов (query), а мы предполагаем, что одинаковые запросы вызывают одинаковые ответы. При повторении одного и того же запроса несколько раз, можно, начиная со второго раза, пропустить сложную и долгую обработку, и просто вернуть предыдущий результат. Преимущество таких кэшей в том, что они не зависят ни от архитектуры, ни от домена, то есть интегрируются как утилита (например, aspect) в готовый продукт, не сильно его изменяя. В противовес этому преимуществу, у них целый ряд недостатков:

  • Они неэффективны, когда у нас богатые интерфейсы, у которых есть несколько методов чтения одного и того же объекта. Причина — они кэшируют путь к объекту, а не сам объект.
  • Их размер зависит не от количества возможных объектов (результатов), а от количества возможных запросов, и потому они обычно тяжелее, чем альтернативы. Их размер и количество необходимой памяти тяжело планировать.
  • Они некрасивы.

Совсем иначе обстоит дело с объектными кэшами: их тяжелее встроить, но они и гораздо эффективнее. Идеальная имплементация кэша объекта — это коллекция (список или множество зависит от требований), которая содержит все объекты, управляемые этим сервисом, в их объектном виде. В идеале сервис должен быть в состоянии ответить на каждый запрос при помощи кэша и без обращения к внешней персистентности (например, базе данных). К сожалению, такая 100% кэшируемость редко достижима, но там, где ее можно применить, она всегда рентабельна. Лучший пример для 100% кэша — учетные записи пользователей. Они, как правило, маленькие (состоят из id, почты, имени, времени регистрации и т.д.) и постоянно требуются в разных местах приложения.

Кэшируем то, чего нет

Ещё одна полезная форма кэша — так называемый ноль-кэш, или отрицательный кэш. В большинстве случаев объектные кэши наполняются во время работы приложения, для того, чтобы был возможен так называемый «холодный старт» и создание новых объектов в базе, при одновременном существовании нескольких инстанций одного и того же сервиса. В результате, обращения к приложению могут «пробиваться» сквозь кэш и доходить до базы. В случае, если такое «пробивание» будет происходить постоянно, это может привезти к перегрузке базы. Тогда все наши кэши, выстроенные с таким трудом, потеряют всяческую эффективность и защитную функцию. Для борьбы с подобной перегрузкой существуют отрицательные кэши, которые запоминают однажды безуспешно опрошенные объекты, тем самым давая сервису возможность при следующем запросе прекратить их обработку на ранней стадии.
Кэшируем то, что меняется

Другая подкатегория кэшей — ExpiryCaches. Они основаны на постулировании того, что объект или его части не будут менять свое состояние в течение какого-то промежутка времени. Типичный пример такого объекта — профиль пользователя на сайте онлайн знакомств. Если пользователь А редактирует свой профиль, то для пользователя Б, который просматривает профиль пользователя А, не принципиально важно, увидит ли он эти изменения через 5, 30 или 60 секунд (особенно, если эти пользователи не контактируют). Тем самым мы можем зафиксировать состояние профиля пользователя А на время, незначительное для человека, но долгое с точки зрения машины, и работать с зафиксированной версией. Этим мы предотвращаем обработку значительного количества запросов, которые, с большой вероятностью, вернули бы идентичный результат (потому что пользователи меняют профиль гораздо реже, чем, например, ищут или отвечают на сообщения), и экономим ресурсы. Плата за эту экономию — всего лишь риск показать обновление в профиле чуть позже, чем мы могли бы. Эта техника с особой популярностью используется на стороне клиента (веб-сервера) для экономии сетевого траффика (к базе данных или сервису) и, соответственно, времени. Но это не единственный пример, когда использование Expiry Cache целесообразно. Другой сценарий использования — это когда в процессе обработки запроса мы исходим из того, что один и тот же объект будет запрошен много раз, но с настолько удаленных друг от друга мест в коде, что хранить его значение в переменной невозможно или нецелесообразно. Популярная технология реализации таких промежуточных кэшей — ThreadLocal (Java).
ExpiryCache — ни что иное, как обмен ресурсами (trade off): мы жертвуем скоростью отображения изменений ради производительности приложения.

Вообще, масштабирование приложений (и особенно порталов) — это обмен ресурсов, которых у нас много, на те, которых не хватает: например, RAM на CPU, сетевой траффик или IO.

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

habr.com

Кэширование данных, возможно последняя вещь которую Вам стоит использовать / Habr

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

Пакет с которым я работал, интенсивно использовал кэширование. Он не мог отдавать более 10 страниц в секунду, если не были включены некоторые «опциональные» настройки кэша. Очевидно что с такой производительностью они на самом деле не опциональны, а обязательны.

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

Кэширование может работать не для всех пользователей — Вы открываете страницу — она загружается быстро. Но так ли это для всех пользователей? Кэширование очень часто позволяет оптимизировать время загрузки для большинства посетителей, но часто в реальности Вам надо чтобы страница загружалась быстро для всех без исключения (если следовать принципу six sigma). На практике запрос может промахиваться мимо кэша всегда для одного и того же пользователя, что еще более усугубляет ситуацию (Прим. переводчика: Я знаю совершенно реальный случай, когда в электронном магазине кэш срабатывал для 99% процентов пользователей и не работал для 1% посетителей имевших длинную историю покупок, как результат магазин работал медленно как раз для активных покупателей).

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

Управление кэшем в реальности непростая задача — Вы когда-нибудь боролись с "убеганием кэша" или с ситуацией когда большое количество элементов кэша инвалидируются одновременно?

Альтернативный подход

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

Что это за способы?

Перед тем как вводить оптимизацию убедитесь что Вы прошлись по этому достаточно простому списку:

Вы понимаете план исполнения каждого запроса? Если нет, установите long_query_time=0 и используйте команду mk-query-digest, чтобы получить полный список запросов. Выполните для каждого из них EXPLAIN, проанализируйте план исполнения.

- Вы используете SELECT * чтобы потом использовать только небольшой набор столбцов? Или вы выбираете из БД много строк, но используете только некоторые из них? Если это так — то вы выбираете слишком много данных, ограничивая оптимизацию уровня СУБД, такую например как использование индексов.

Знаете ли Вы сколько именно запросов Вы используете для генерации одной страницы? Все ли они действительно необходимы? Можно ли какие-то из этих запросов превратить в один запрос или вообще убрать? (Прим. переводчика: Очень распространенная проблема. Реально знаю случай когда на странице отображался список учеников в классе, а затем в цикле для каждого ученика запрашивалась дополнительная информация, включая название класса. После переделки количество запросов сократилось с 61 до 3-х).

Думаю что как вывод можно сказать: «Оптимизация очень редко уменьшает сложность приложения. Старайтесь избегать усложнения, за счет оптимизации только того, что действительно надо оптимизировать» — цитата со слайда Джастина — instrumentation-for-php.

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

Прим. переводчика: Совершенно реальный диалог произошедший не так давно:
— Так у нас проблемы с производительностью, надо добавить кэширование, вертикальное партиционирование и NoSQL DB для логинов
— Парни — я тут посмотрел EXPLAIN — у Вас fullscan запрос на 4,000 строк, я попробовал создать индекс- все ускорилось в 26 раз.

Несколько замечаний к переводу

1. Термин cache stampeding — я перевел как убегание кэша (был соблазн перевести как «просрачивание», но это было бы неправильно). Если коротко, это ситуация, когда например определенный запрос выполняется достаточно долго и результаты этого запроса кэшируются, когда затем эти данные рано или поздно уходят из кэша, и одновременно рендерится 10 страниц на которых эти данные нужны, то в БД отправляется 10 медленных запрсов, вместо одного. Обычно с этим борются пере запрашивая данные до того как они будут выкинуты из кэша. см например
2. Хочу обратить внимание, что в статье не говорится что кэшировать данные не надо. Их надо кэшировать, но только после того как Вы попробуете несколько простых способов оптимизации запросов к БД. Иными словами начинать надо с простого.

habr.com


Смотрите также



© 2010- GutenBlog.ru Карта сайта, XML.