Что такое кэш функция
Кэширование и производительность веб-приложений
Кэширование позволяет увеличивать производительность веб-приложений за счёт использования сохранённых ранее данных, вроде ответов на сетевые запросы или результатов вычислений. Благодаря кэшу, при очередном обращении клиента за одними и теми же данными, сервер может обслуживать запросы быстрее. Кэширование — эффективный архитектурный паттерн, так как большинство программ часто обращаются к одним и тем же данным и инструкциям. Эта технология присутствует на всех уровнях вычислительных систем. Кэши есть у процессоров, жёстких дисков, серверов, браузеров.
Ник Карник, автор материала, перевод которого мы сегодня публикуем, предлагает поговорить о роли кэширования в производительности веб-приложений, рассмотрев средства кэширования разных уровней, начиная с самого низкого. Он обращает особое внимание на то, где именно могут быть кэшированы данные, а не на то, как это происходит.
Мы полагаем, что понимание особенностей систем кэширования, каждая из которых вносит определённый вклад в скорость реакции приложений на внешние воздействия, расширит кругозор веб-разработчика и поможет ему в деле создания быстрых и надёжных систем.
Процессорный кэш
Начнём наш разговор о кэшах с самого низкого уровня — с процессора. Кэш-память процессора — это очень быстрая память, которая играет роль буфера между процессором (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-заголовки, указывающие браузеру на то, когда и на какое время он может кэшировать ответ сервера.
Перед нами весьма полезная технология, которая даёт следующие преимущества всем участникам обмена данными:
Кэширование в браузере
Кэширование и прокси-серверы
В компьютерных сетях прокси-серверы могут быть представлены специальным аппаратным обеспечением или соответствующими приложениями. Они играют роль посредников между клиентами и серверами, хранящими данные, которые этим клиентам требуются. Кэширование — это одна из задач, которую они решают. Рассмотрим различные виды прокси-серверов.
▍Шлюзы
Шлюз (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). Например, если вы посещаете популярный веб-сайт и загружаете какие-нибудь статические данные, они попадают в кэш. Каждый следующий пользователь, запросивший те же данные, получит их, до истечения срока их кэширования, с кэширующего сервера. Эти серверы, определяя актуальность информации, ориентируются на серверы, хранящие исходные данные.
Прокси-серверы в инфраструктуре обмена данными между клиентом и сервером
Итоги
В этом материале мы рассмотрели различные уровни кэширования данных, применяющиеся в процессе обмена информацией между клиентом и сервером. Веб-приложения не могут мгновенно реагировать на воздействия пользователя, что, в частности, связано, для действий, требующих обмена данными с серверами этих приложений, с необходимостью выполнения неких вычислений перед отправкой ответа. Во время, необходимое для передачи данных от сервера клиенту, входит и время, необходимое для поиска необходимых данных на диске, и сетевые задержки, и обработка очередей запросов, и механизмы регулирования полосы пропускания сетей, и многое другое. Если учесть, что всё это может происходить на множестве компьютеров, находящихся между клиентом и сервером, то можно говорить о том, что все эти задержки способны серьёзно увеличить время, необходимое для прихода запроса на сервер и получения клиентом ответа.
Правильно настроенная система кэширования способна значительно улучшить общую производительность сервера. Кэши сокращают задержки, неизбежно возникающие при передаче данных по сети, помогают экономить сетевой трафик, и, в результате, уменьшают время, необходимое для того, чтобы браузер вывел запрошенную у сервера веб-страницу.
Уважаемые читатели! Какие технологии кэширования вы используете в своих проектах?
Кэши для «чайников»
Кэш глазами «чайника»:
Кэш – это комплексная система. Соответственно, под разными углами результат может лежать как в действительной, так и в мнимой области. Очень важно понимать разницу между тем, что мы ждем и тем, что есть на самом деле.
Давайте прокрутим полный оборот ситуаций.
Tl;dr: добавляя в архитектуру кэш важно явно осознавать, что кэш может быть средством дестабилизации системы под нагрузкой. Смотрите конец статьи.
Представим, что у нас есть доступ к базе данных, возвращающей курсы валют. Мы спрашиваем rates.example.com/?currency1=XXX¤cy2=XXX и в ответ получаем plain text значение курса. Каждые 1000 запросов к базе данных для нас, допустим, стоят 1 евроцент.
Итак, теперь мы хотим показывать на нашем сайте курс доллара к евро. Для этого нам нужно получить курс, поэтому на нашем сайте мы создаём API-обёртку для удобного использования:
И в шаблонах в нужном месте вставляем что-нибудь вроде:
Наивная имплементация делает самое простое, что можно придумать: на каждый запрос от пользователя спрашивает удалённую систему и использует ответ напрямую. Это означает, что теперь каждые 1000 просмотров пользователями нашей страницы стоят для нас на копейку больше. Казалось бы – гроши. Но вот проект растёт, у нас уже 1000 постоянных пользователей, которые каждый день заходят на сайт и просматривают по 20 страниц, а это уже 6 евро в месяц, что превращает сайт из бесплатного во вполне уже сопоставимый с платой за самые дешевые выделенные виртуальные серверы.
Вот тут на сцену выходит его величество Кэш
Зачем нам спрашивать курс для каждого пользователя на каждое обновление страницы, если для людей эта информация, в общем-то, не нужна так часто? Давайте просто ограничим частоту обновления до, например, раз в 5 секунд. Пользователи, переходя со страницы на страницу, всё равно будут видеть новое число, а мы платить будем в 1000 раз меньше.
Сказано – сделано! Добавляем несколько строчек:
Это самый главный аспект кэша: хранение последнего результата.
И вуаля! Сайт снова становится для нас почти бесплатным… До конца месяца, когда мы обнаруживаем от внешней системы счет на 4 евро. Конечно, не 6, но мы ожидали намного большей экономии!
К счастью, внешняя система позволяет посмотреть начисления, где мы видим всплески по 100 и более запросов каждые ровные 5 секунд в течение пиковой посещаемости.
Так мы познакомились со вторым важным аспектом кэша: дедупликацией запросов. Дело в том, что как только значение устарело, между проверкой наличия результата в кэше и сохранением нового значения, все пришедшие запросы фактически выполняют запрос к внешней системе одновременно.
В случае с memcache это можно реализовать, например, так:
И вот, наконец, потребление сравнялось с ожидаемым — 1 запрос в 5 секунд, расходы сократились до 2 евро в месяц.
Почему 2? Было 6 без кэширования для тысячи человек, мы же всё закэшировали, а сократилось всего в 3 раза? Да, стоило просчитать пораньше… 1 раз в 5 секунд = 12 в минуту = 72 в час = 576 за рабочий день = 17 тысяч в месяц, а ещё не все ходят по расписанию, есть странные личности заглядывающие поздней ночью… Вот и получается, в пике вместо сотни обращений одно, а в тихое время — по-прежнему запрос почти на каждое обращение проходит. Но всё равно, даже в худшем случае счёт должен быть 31×86400÷5 = 5.36 евро.
Так мы познакомились с еще одной гранью: кэш помогает, но не устраняет нагрузку.
Впрочем, в нашем случае люди приходят в проект и уходят и в какой-то момент начинают жаловаться на тормоза: страницы замирают на несколько секунд. А еще бывает под утро сайт не отвечает вообще… Просмотр консоли сайта показывает, что иногда днём запускаются дополнительные инстансы. В это же время скорость выполнения запросов падает до 5-15 секунд на запрос — из-за чего это и происходит.
Упражнение для читателя: посмотреть внимательно предыдущий код и найти причину.
Кстати, это грабли отнюдь не только кэша, это общий аспект распределённых блокировок: важно освобождать блокировки и иметь таймауты, во избежание дедлоков. Если бы мы добавляли «?» вообще без времени жизни, всё б замирало при первой же ошибке связи с внешней системой. К сожалению, memcache не предоставляет хороших способов для создания распределённых блокировок, использование полноценной БД с блокировками на уровне строк лучше, но это было просто лирическое отступление, необходимое просто потому, что на эти грабли наступили.
Итак, мы исправили проблему, вот только ничего не изменилось: всё равно изредка начинались тормоза. Что примечательно, они совпадали по времени с информационным бюллетенем от внешней системы о технических работах…
Ну-ка ну-ка… Давайте сделаем краткую передышку и пересчитаем, что мы насобирали уже сейчас, что должен уметь кэш:
Отсюда: кэш обязан уметь какое-то время хранить отрицательный результат. Наше наивное исходное предположение по сути подразумевает хранение отрицательного результата 0 секунд (но передачу этого самого отрицания всем, кто уже ждёт его). К сожалению, в случае с Memcache реализация нулевого времени ожидания весьма проблематична (оставлю как домашнее задание въедливому читателю; cовет: используйте механизм CAS; и да, в AppEngine можно использовать и Memcache и Memcached).
Мы же просто добавим сохранение отрицательного значения с 1 секундой жизни:
Казалось бы, ну теперь-то уже всё, и можно успокоиться? Как бы не так. Пока мы росли, наш любимый внешний сервис тоже рос, и в какой-то момент начал иногда тормозить и отвечать аж по секунде… И что примечательно – вместе с ним начал тормозить и наш сайт! Причем снова для всех! Но почему? Мы же всё кэшируем, в случае ошибок запоминаем ошибку и тем самым отпускаем всех ожидающих сразу, разве нет?
Что ж, мы можем вместо ожидания, добавить ветку else<> у условия вокруг memcache->add … Правда, стоит, наверное, вернуть последнее известное значение, да? Ведь мы кэшируем ровно затем, что мы согласны получить устаревшие сведения, если нет свежих; итак, еще одно требование к кэшу: пусть подтормаживает не более одного запроса.
Итак, мы снова победили: даже если тормозит внешний сервис, подтормаживает не более одной страницы… То есть как бы среднее время ответа сократилось, но пользователи всё равно немного недовольны.
Примечание: обычный PHP по умолчанию пишет сессии в файлы, блокируя параллельные запросы. Чтобы избежать этого поведения, можно передать в session_start параметр read_and_close либо принудительно закрывать через session_close сессию после совершения всех необходимых изменений, иначе тормозить будет не одна страница, а один пользователь: так как скрипт, обновляющий значение, будет блокировать открытие сессии другим запросом от того же пользователя. При исполнении на AppEngine по умолчанию включено хранение сессий в memcache, то есть без блокировок, поэтому будет проблема не так заметна.
Так вот, пользователи всё равно недовольны (ох уж эти пользователи!). Те, кто проводят времени больше всех на сайте, всё равно замечают эти короткие зависания. И их нисколько не радует осознание факта того, что так случается редко, и им просто не везёт. Придётся для данного случая сделать требование еще более жестким: никакие запросы не должны ждать ответа.
Что же мы можем сделать в такой постановке вопроса? Мы можем:
Итак, наш поставщик данных растёт, но не все его клиенты читают хабр, а потому они не используют правильного кэширования (если используют его вообще) и в какой-то момент начинают выдавать огромное количество запросов, из-за чего сервису становится плохо, и эпизодически он начинает отвечать не просто медленно, а очень медленно. До десятков секунд и более. Пользователи, конечно, быстро обнаружили, что можно нажать F5 или иначе перезагрузить страницу, и она появляется моментально – вот только страница снова начала упираться в бесплатные пределы, так как постоянно начали висеть процессы, просто ожидающие внешний ответ, но потребляющие наши ресурсы.
В числе прочих побочных эффектов участились случаи показа устаревшего курса. [Мда… в общем, представьте, что мы сейчас говорим не про наш случай, а про что-нибудь более сложное, где устаревание видно невооруженным глазом 🙂 на самом деле, даже в простом случае обязательно найдётся пользователь, который заметит такие совершенно неочевидные косяки].
Смотрите, что получается:
Итак, давайте подведём промежуточный итог. В бытовом понимании кэш:
Рассмотрим простейший случай:
3600. Что означает, что если отравление наступило на 5000 запросах в минуту, до тех пор, пока нагрузка не упадёт с 5000 до 3000 система нестабильна. То есть любой (даже пиковый!) всплеск трафика потенциально может вызвать длительную нестабильность системы.
Особенно прекрасно это смотрится, когда после новостной рассылки с какими-либо новыми функциями практически одновременно приходит волна пользователей. Эдакий маркетологический хабраэффект на регулярной основе.
Всё это не означает, что кэш нельзя или вредно использовать! О том, как правильно применять кэш для улучшения стабильности системы и как восстанавливаться от вышеупомянутой петли гистерезиса, мы поговорим в следующей статье, не переключайтесь.
Что такое кэш в процессоре и зачем он нужен
Содержание
Содержание
Для многих пользователей основополагающими критериями выбора процессора являются его тактовая частота и количество вычислительных ядер. А вот параметры кэш-памяти многие просматривают поверхностно, а то и вовсе не уделяют им должного внимания. А зря!
В данном материале поговорим об устройстве и назначении сверхбыстрой памяти процессора, а также ее влиянии на общую скорость работы персонального компьютера.
Предпосылки создания кэш-памяти
Любому пользователю, мало-мальски знакомому с компьютером, известно, что в составе ПК работает сразу несколько типов памяти. Это медленная постоянная память (классические жесткие диски или более быстрые SSD-накопители), быстрая оперативная память и сверхбыстрая кэш-память самого процессора. Оперативная память энергозависимая, поэтому каждый раз, когда вы выключаете или перезагружаете компьютер, все хранящиеся в ней данные очищаются, в отличие от постоянной памяти, в которой данные сохраняются до тех пор, пока это нужно пользователю. Именно в постоянную память записаны все программы и файлы, необходимые как для работы компьютера, так и для комфортной работы за ним.
Каждый раз при запуске программы из постоянной памяти, ее наиболее часто используемые данные или вся программа целиком «подгружаются» в оперативную память. Это делается для ускорения обработки данных процессором. Считывать и обрабатывать данные из оперативной памяти процессор будет значительно быстрей, а, следовательно, и система будет работать значительно быстрее в сравнении с тем, если бы массивы данных поступали напрямую из не очень быстрых (по меркам процессорных вычислений) накопителей.
Если бы не было «оперативки», то процесс считывания напрямую с накопителя занимал бы непозволительно огромное, по меркам вычислительной мощности процессора, время.
Но вот незадача, какой бы быстрой ни была оперативная память, процессор всегда работает быстрее. Процессор — это настолько сверхмощный «калькулятор», что произвести самые сложные вычисления для него — это даже не доля секунды, а миллионные доли секунды.
Производительность процессора в любом компьютере всегда ограничена скоростью считывания из оперативной памяти.
Процессоры развиваются так же быстро, как память, поэтому несоответствие в их производительности и скорости сохраняется. Производство полупроводниковых изделий постоянно совершенствуется, поэтому на пластину процессора, которая сохраняет те же размеры, что и 10 лет назад, теперь можно поместить намного больше транзисторов. Как следствие, вычислительная мощность за это время увеличилась. Впрочем, не все производители используют новые технологии для увеличения именно вычислительной мощности. К примеру, производители оперативной памяти ставят во главу угла увеличение ее емкости: ведь потребитель намного больше ценит объем, нежели ее быстродействие. Когда на компьютере запущена программа и процессор обращается к ОЗУ, то с момента запроса до получения данных из оперативной памяти проходит несколько циклов процессора. А это неправильно — вычислительная мощность процессора простаивает, и относительно медленная «оперативка» тормозит его работу.
Такое положение дел, конечно же, мало кого устраивает. Одним из вариантов решения проблемы могло бы стать размещение блока сверхбыстрой памяти непосредственно на теле кристалла процессора и, как следствие, его слаженная работа с вычислительным ядром. Но проблема, мешающая реализации этой идеи, кроется не в уровне технологий, а в экономической плоскости. Такой подход увеличит размеры готового процессора и существенно повысит его итоговую стоимость.
Объяснить простому пользователю, голосующему своими кровными сбережениями, что такой процессор самый быстрый и самый лучший, но за него придется отдать значительно больше денег — довольно проблематично. К тому же существует множество стандартов, направленных на унификацию оборудования, которым следуют производители «железа». В общем, поместить оперативную память прямо на кристалл процессора не представляется возможным по ряду объективных причин.
Как работает кэш-память
Как стало понятно из постановки задачи, данные должны поступать в процессор достаточно быстро. По меркам человека — это миг, но для вычислительного ядра — достаточно большой промежуток времени, и его нужно как можно эффективнее минимизировать. Вот здесь на выручку и приходит технология, которая называется кэш-памятью. Кэш-память — это сверхбыстрая память, которую располагают прямо на кристалле процессора. Извлечение данных из этой памяти не занимает столько времени, сколько бы потребовалось для извлечения того же объема из оперативной памяти, следовательно, процессор молниеносно получает все необходимые данные и может тут же их обрабатывать.
Кэш-память — это, по сути, та же оперативная память, только более быстрая и дорогая. Она имеет небольшой объем и является одним из компонентов современного процессора.
На этом преимущества технологии кэширования не заканчиваются. Помимо своего основного параметра — скорости доступа к ячейкам кэш-памяти, т. е. своей аппаратной составляющей, кэш-память имеет еще и множество других крутых функций. Таких, к примеру, как предугадывание, какие именно данные и команды понадобятся пользователю в дальнейшей работе и заблаговременная загрузка их в свои ячейки. Но не стоит путать это со спекулятивным исполнением, в котором часть команд выполняется рандомно, дабы исключить простаивание вычислительных мощностей процессора.
Спекулятивное исполнение — метод оптимизации работы процессора, когда последний выполняет команды, которые могут и не понадобиться в дальнейшем. Использование метода в современных процессорах довольно существенно повышает их производительность.
Речь идет именно об анализе потока данных и предугадывании команд, которые могут понадобиться в скором будущем (попадании в кэш). Это так называемый идеальный кэш, способный предсказать ближайшие команды и заблаговременно выгрузить их из ОЗУ в ячейки сверхбыстрой памяти. В идеале их надо выбирать таким образом, чтобы конечный результат имел нулевой процент «промахов».
Но как процессор это делает? Процессор что, следит за пользователем? В некоторой степени да. Он выгружает данные из оперативной памяти в кэш-память для того, чтобы иметь к ним мгновенный доступ, и делает это на основе предыдущих данных, которые ранее были помещены в кэш в этом сеансе работы. Существует несколько способов, увеличивающих число «попаданий» (угадываний), а точнее, уменьшающих число «промахов». Это временная и пространственная локальность — два главных принципа кэш-памяти, благодаря которым процессор выбирает, какие данные нужно поместить из оперативной памяти в кэш.
Временная локальность
Процессор смотрит, какие данные недавно содержались в его кэше, и снова помещает их в кэш. Все просто: высока вероятность того, что выполняя какие-либо задачи, пользователь, скорее всего, повторит эти же действия. Процессор подгружает в ячейки сверхбыстрой памяти наиболее часто выполняемые задачи и сопутствующие команды, чтобы иметь к ним прямой доступ и мгновенно обрабатывать запросы.
Пространственная локальность
Принцип пространственной локальности несколько сложней. Когда пользователь выполняет какие-то действия, процессор помещает в кэш не только данные, которые находятся по одному адресу, но еще и данные, которые находятся в соседних адресах. Логика проста — если пользователь работает с какой-то программой, то ему, возможно, понадобятся не только те команды, которые уже использовались, но и сопутствующие «слова», которые располагаются рядом.
Набор таких адресов называется строкой (блоком) кэша, а количество считанных данных — длиной кэша.
При пространственной локации процессор сначала ищет данные, загруженные в кэш, и, если их там не находит, то обращается к оперативной памяти.
Иерархия кэш-памяти
Любой современный процессор имеет в своей структуре несколько уровней кэш-памяти. В спецификации процессора они обозначаются как L1, L2, L3 и т. д.
Если провести аналогию между устройством кэш-памяти процессора и рабочим местом, скажем столяра или представителя любой другой профессии, то можно увидеть интересную закономерность. Наиболее востребованный в работе инструмент находится под рукой, а тот, что используется реже, расположен дальше от рабочей зоны.
Так же организована и работа быстрых ячеек кэша. Ячейки памяти первого уровня (L1) располагаются на кристалле в непосредственной близости от вычислительного ядра. Эта память — самая быстрая, но и самая малая по объему. В нее помещаются наиболее востребованные данные и команды. Для передачи данных оттуда потребуется всего около 5 тактовых циклов. Как правило, кэш-память первого уровня состоит из двух блоков, каждый из которых имеет размер 32 КБ. Один из них — кэш данных первого уровня, второй — кэш инструкций первого уровня. Они отвечают за работу с блоками данных и молниеносное обращение к командам.
Кэш второго и третьего уровня больше по объему, но за счет того, что L2 и L3 удалены от вычислительного ядра, при обращении к ним будут более длительные временные интервалы. Более наглядно устройство кэш-памяти проиллюстрировано в следующем видео.
Кэш L2, который также содержит команды и данные, занимает уже до 512 КБ, чтобы обеспечить необходимый объем данных кэшу нижнего уровня. Но на обработку запросов уходит в два раза больше времени. Кэш третьего уровня имеет размеры уже от 2 до 32 МБ (и постоянно увеличивается вслед за развитием технологий), но и его скорость заметно ниже. Она превышает 30 тактовых циклов.
Процессор запрашивает команды и данные, обрабатывая их, что называется, параллельными курсами. За счет этого и достигается потрясающая скорость работы. В качестве примера рассмотрим процессоры Intel. Принцип работы таков: в кэше хранятся данные и их адрес (тэг кэша). Сначала процессор ищет их в L1. Если информация не найдена (возник промах кэша), то в L1 будет создан новый тэг, а поиск данных продолжится на других уровнях. Для того, чтобы освободить место под новый тэг, информация, не используемая в данный момент, переносится на уровень L2. В результате данные постоянно перемещаются с одного уровня на другой.
С кэшем связан термин «сет ассоциативности». В L1 блок данных привязан к строкам кэша в определенном сете (блоке кэша). Так, например, 8-way (8 уровень ассоциативности) означает, что один блок может быть привязан к 8 строкам кэша. Чем выше уровень, тем выше шанс на попадание кэша (процессор нашел требуемую информацию). Есть и недостатки. Главные — усложнение процесса и соответствующее снижение производительности.
Также при хранении одних и тех же данных могут задействоваться различные уровни кэша, например, L1 и L3. Это так называемые инклюзивные кэши. Использование лишнего объема памяти окупается скоростью поиска. Если процессор не нашел данные на нижнем уровне, ему не придется искать их на верхних уровнях кэша. В этом случае задействованы кэши-жертвы. Это полностью ассоциативный кэш, который используется для хранения блоков, вытесненных из кэша при замене. Он предназначен для уменьшения количества промахов. Например, кэши-жертвы L3 будут хранить информацию из L2. В то же время данные, которые хранятся в L2, остаются только там, что помогает сэкономить место в памяти, однако усложняет поиск данных: системе приходится искать необходимый тэг в L3, который заметно больше по размеру.
В некоторых политиках записи информация хранится в кэше и основной системной памяти. Современные процессоры работают следующим образом: когда данные пишутся в кэш, происходит задержка перед тем, как эта информация будет записана в системную память. Во время задержки данные остаются в кэше, после чего их «вытесняет» в ОЗУ.
Итак, кэш-память процессора — очень важный параметр современного процессора. От количества уровней кэша и объема ячеек сверхбыстрой памяти на каждом из уровней, во многом зависит скорость и производительность системы. Особенно хорошо это ощущается в компьютерах, ориентированных на гейминг или сложные вычисления.