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

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

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

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

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

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

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

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

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

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

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

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

В заключение

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

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

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

Автор статьи:  Антон Бойко.